Search Unity

[Released] Advanced Terrain Grass

Discussion in 'Assets and Asset Store' started by larsbertram1, Sep 11, 2017.

  1. SRGeodan

    SRGeodan

    Joined:
    Oct 16, 2014
    Posts:
    12
    This is how I generate grass.
    There is quite some unrelated code.
    But what else should I do?

    Code (CSharp):
    1.         public static void GenerateGrass(Terrain ter)
    2.         {
    3.             if (ter == null) return;
    4.             var td = ter.terrainData;
    5.             if (td == null) return;
    6.             TerrainBehaviour tb = ter.GetComponent<TerrainBehaviour>();
    7.             if (tb == null) return;
    8.             GrassManager gm = ter.gameObject.AddOrGetComponent<GrassManager>();
    9.             GrassSettings set = WorldManager.Instance.GrassSettings;
    10.             List<Texture2D> textures = Helpers.LoadAllAssets<Texture2D>(set.GrassLabel);
    11.             List<GameObject> prefabs = Helpers.LoadAllAssets<GameObject>(set.GrassLabel);
    12.             DetailPrototype[] dps = new DetailPrototype[textures.Count + prefabs.Count];
    13.             int k = 0;
    14.             foreach (var t in textures)
    15.             {
    16.                 dps[k] = new DetailPrototype();
    17.                 dps[k].prototypeTexture = t;
    18.                 dps[k].renderMode = DetailRenderMode.Grass;
    19.                 dps[k].minWidth = set.MinWidth;
    20.                 dps[k].maxWidth = set.MaxWidth;
    21.                 dps[k].minHeight = set.MinHeight;
    22.                 dps[k].maxHeight = set.MaxHeight;
    23.                 k++;
    24.             }
    25.             foreach (var pf in prefabs)
    26.             {
    27.                 dps[k] = new DetailPrototype();
    28.                 dps[k].prototype = pf;
    29.                 dps[k].usePrototypeMesh = true;
    30.                 dps[k].renderMode = DetailRenderMode.Grass;
    31.                 //dps[k].minWidth = set.MinWidth;
    32.                 //dps[k].maxWidth = set.MaxWidth;
    33.                 //dps[k].minHeight = set.MinHeight;
    34.                 //dps[k].maxHeight = set.MaxHeight;
    35.                 k++;
    36.             }
    37.             td.detailPrototypes = dps;
    38.             List<Color32> styles = new List<Color32>();
    39.             set.SpawnGrassOn.ToList().ForEach(style =>
    40.             {
    41.                 var pixels = StyleManager.Instance.StyleToPixels(style);
    42.                 if ( pixels != null && pixels.Count!=0)
    43.                     styles.AddRange(pixels);
    44.             });
    45.             styles = styles.Distinct().ToList();
    46.             float fx = WorldManager.Instance.TerrainSettings.MemoryResolution / WorldManager.Instance.TerrainSettings.DetailResolution;
    47.             for (k = 0; k < textures.Count; k++)
    48.             {
    49.                 var res = WorldManager.Instance.TerrainSettings.DetailResolution;
    50.                 int[,] map = new int[res, res];
    51.                 for (int y = 0; y < res; y++)
    52.                     for (int x = 0; x < res; x++)
    53.                     {
    54.                         Color32 style = GetStylePixel(tb, Mathf.RoundToInt( x * fx ), Mathf.RoundToInt( y * fx ));
    55.                         Color32 style2 = GetStylePixel(tb, Mathf.RoundToInt((x+1) * fx), Mathf.RoundToInt(y * fx));
    56.                   //      Color32 style3 = GetStylePixel(tb, Mathf.RoundToInt((x-1) * fx), Mathf.RoundToInt(y * fx));
    57.                         Color32 style4 = GetStylePixel(tb, Mathf.RoundToInt(x * fx), Mathf.RoundToInt((y+1) * fx));
    58.                  //       Color32 style5 = GetStylePixel(tb, Mathf.RoundToInt(x * fx), Mathf.RoundToInt((y-1) * fx));
    59.                         int d = 0;
    60.                         if (style.Equal(style2) && style2.Equal(style4) /*&& style3.Equal(style4) && style4.Equal(style5) && */ && styles.Any(c => c.Equal(style)))
    61.                         {
    62.                             d = set.Density;
    63.                         }
    64.                         map[y, x] = d;
    65.                     }
    66.                 td.SetDetailLayer(0, 0, k, map);
    67.             }
    68.  
    69.             gm.UpdateGrass();
    70.             for (int i = 0; i < gm.ShadowCastingMode.Length; i++)
    71.                 gm.ShadowCastingMode[i] = UnityEngine.Rendering.ShadowCastingMode.On;
    72.         }
     
  2. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    the grassmanager expects a fully set up terrain with heightmap, detail density maps and grass prototypes.

    if you create the terrain from script i would start with removing the init function from the OnEnable().
    call it instead when your terrain is fully configured.

    you also have to take care about the arrays usually been filled by the inspector like v_mesh, v_mat, v_clip, InstanceRotation, WriteNormalBuffer etc.
     
  3. SRGeodan

    SRGeodan

    Joined:
    Oct 16, 2014
    Posts:
    12
    It is fully set up.
    Then I add the script either by hand or from script -> always results in the exception.
    I then do: GetPrototypes() from script or by hand, does not matter. Same errors.
    Tried Init, Tried UpdateGrass(), basically everything already.
    No luck :(
     
  4. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    Let us have a look into this next week.
     
  5. oceanquigley

    oceanquigley

    Joined:
    Apr 20, 2018
    Posts:
    6
    Is it possible for the "Unlit" lighting mode to still receive shadows? I'm using baked lighting (which I'm saving as a texture and using as my grass base texture) for static objects, so the grass is beautifully integrated into the static scene - but the effect is ruined when a dynamic shadow goes over.
     
  6. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    nope. it is unlit...
    but actually i would need some more information.
     
  7. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    i read your answer in my emails - although you have deleted it here.
    you should be able to use a pigment map ( top-down screencapture of the terrain), get nice blending between the terrain and the grass and support real time shadows.
    you must not go unlit but fully lit and make sure that grass lighting matches terrain lighting.
     
    Last edited: Aug 14, 2019
  8. Gua

    Gua

    Joined:
    Oct 29, 2012
    Posts:
    356
    I'm having issues with Decal Master: Advanced Deferred Decals + Advanced Terrain Grass.



     
    Last edited: Aug 18, 2019
  9. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    i do not know how decal master renders its deferred decals.
    the white border around the decal however seems to be smoothness getting smoothly blended from decal to gbuffer.
    atg however interpretes smoothness as specular mask. so this will fail.
    atg uses a custom gbuffer layout and material ids stored in the normalBuffer's alpha channel.
    you have to make sure that the decal shader will not affect this channel.
     
  10. Sam512

    Sam512

    Joined:
    Jan 13, 2019
    Posts:
    178
    Hey, I wonder if I use World Creator, will I still be able to use your shader?
     
  11. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    yes, you are.
     
  12. Murkawski

    Murkawski

    Joined:
    Nov 30, 2014
    Posts:
    48
    Hey, I would appreciate some help. I have some 2 errors popping up. The last thing I did was remove 2 grass from the terrain details as I don't use them and don't need them. Do you know what the problem could be?
     

    Attached Files:

  13. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    you have to rebuild the saved terrain data.
     
  14. Murkawski

    Murkawski

    Joined:
    Nov 30, 2014
    Posts:
    48
    Thanks. I'll try that
     
  15. Murkawski

    Murkawski

    Joined:
    Nov 30, 2014
    Posts:
    48
    Hello. I'm getting an error in the shader.
     

    Attached Files:

  16. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    have you enabled "GPU instancing" in the material inspector? should be off.
    you may also edit the shader and comment #pragma multi_compile_instancing in the depth only and the shadow caster pass: we are using procedural instancing.

    please let me know if this fixes the error.
     
  17. Murkawski

    Murkawski

    Joined:
    Nov 30, 2014
    Posts:
    48
    Yes, I did enable GPU instancing. So I should turn it off right?

    And when I comment out what you mentioned than the error goes away. Ty
     
  18. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    yes. we do not use unity's built in instancing.

    fine!
     
  19. Sam512

    Sam512

    Joined:
    Jan 13, 2019
    Posts:
    178
    I wonder if you will ever add touch bending feature and just increase the price? I do have VS but that asset prevent me from my performance technique so I don't use it anymore
     
    John-Lisenby likes this.
  20. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    touch bending has been implemented by some other users already: please read this thread.
     
    Lars-Steenhoff likes this.
  21. Sam512

    Sam512

    Joined:
    Jan 13, 2019
    Posts:
    178
    What thread?
     
  22. Sam512

    Sam512

    Joined:
    Jan 13, 2019
    Posts:
    178
    I'm not a programmer
     
  23. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    the conversation starts here:
    #post 177
    maybe @dongliang28 can share some more information or even code with you.
     
  24. John-Lisenby

    John-Lisenby

    Joined:
    Nov 8, 2013
    Posts:
    114
    Hello,

    I am getting shader error. Please see image. I not sure how or what needs to be updated to fix this error. FYI Im building for UWP / Xbox.

    Thanks,

    John
     

    Attached Files:

  25. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    hmm, you may try to uncomment the paragma "nolightmap". it currently is commented because it causes trouble with baked shadow maps. i hope you do not use these...

    so line 59 of the shader should look like this:
    #pragma surface surf ATGSpecular vertex:vertgrass addshadow nodynlightmap nolppv nometa nolightmap
    doing so makes the warning go away in unity 5.6.3. on dx11. maybe it stops the shader compiler from erroring when compiling for xbox one.
     
  26. JiLu

    JiLu

    Joined:
    Apr 8, 2019
    Posts:
    1
    Does this work with HDRP?
     
  27. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    not yet. hdrp is still in preview.
     
  28. StepStudio

    StepStudio

    Joined:
    May 1, 2018
    Posts:
    1
    Hi

    Does this work with LWRP?
     
  29. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    it does not currently.
     
  30. Sam512

    Sam512

    Joined:
    Jan 13, 2019
    Posts:
    178
    Last update cause grass flickering around slopes
     

    Attached Files:

  31. Paul-Swanson

    Paul-Swanson

    Joined:
    Jan 22, 2014
    Posts:
    287
    @larsbertram1 is there a way to make the wind pattern get detected by ATG off the wind zones themselves? I made this script but its not interacting with ATG. The main goal was i just wanted my grenades to make the grass move very quickly using a spherical wind zone. Am I just misunderstanding something very simple? or is there now way to make that work the way I tried?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using CoverShooter;
    5.  
    6. public class ExplosionWind : MonoBehaviour
    7. {
    8.     public float MinStart = 0f;
    9.     public float MaxVal = 1f;
    10.     public WindZone AttachedWindZone;
    11.     public DelayedDestroy AttachedDelayDestroy;
    12.     public float DestroyTime = 4f;
    13.     public float LerpSpeed;
    14.     public float timer;
    15.  
    16.     // Start is called before the first frame update
    17.     void Awake()
    18.     {
    19.         getWindObject();
    20.         SetStartVal();
    21.         getDelayedDestroy();
    22.         SetDestroyTime();
    23.     }
    24.  
    25.     // Update is called once per frame
    26.     void FixedUpdate()
    27.     {
    28.         timer += Time.deltaTime;
    29.         if (timer < DestroyTime/2) { TimerUnderHalf(); }
    30.         else if (timer >= DestroyTime/2) { TimerOverHalf();  }
    31.        
    32.     }
    33.  
    34.     void getWindObject()
    35.     {
    36.         if (AttachedWindZone == null)
    37.         {
    38.             AttachedWindZone = GetComponent<WindZone>();
    39.         }
    40.         else return;
    41.  
    42.     }
    43.  
    44.     void getDelayedDestroy()
    45.     {
    46.         if (AttachedDelayDestroy == null)
    47.         {
    48.             AttachedDelayDestroy = GetComponent<DelayedDestroy>();
    49.         }
    50.         else return;
    51.     }
    52.  
    53.     void SetStartVal()
    54.     {
    55.         AttachedWindZone.windTurbulence = 0f;
    56.         AttachedWindZone.windMain = 0f;
    57.     }
    58.  
    59.     void SetDestroyTime()
    60.     {
    61.         DestroyTime = (float)AttachedDelayDestroy.Delay;
    62.         LerpSpeed = ((DestroyTime / 2f)*.01f);
    63.     }
    64.  
    65.     void TimerUnderHalf()
    66.     {
    67.         AttachedWindZone.windTurbulence =       Mathf.Lerp(AttachedWindZone.windTurbulence, MaxVal, LerpSpeed);
    68.         AttachedWindZone.windMain =             Mathf.Lerp(AttachedWindZone.windMain, MaxVal, LerpSpeed);
    69.     }
    70.  
    71.     void TimerOverHalf()
    72.     {
    73.         AttachedWindZone.windTurbulence =       Mathf.Lerp(AttachedWindZone.windTurbulence, MinStart, LerpSpeed);
    74.         AttachedWindZone.windMain =             Mathf.Lerp(AttachedWindZone.windMain, MinStart, LerpSpeed);
    75.     }
    76.  
    77. }
    78.  
     
  32. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    could you elaborate a bit on this?
     
  33. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    the main wind render texture tiles over the terrain so it does not support local effects like a spherical wind zone.
    in order to add local forces and touch bending you will have to add another render texture: top down projection only showing the area around the current camera.
    starting here you will find a little discussion about adding such a system to atg.
     
  34. PatrickLipo

    PatrickLipo

    Joined:
    Mar 14, 2015
    Posts:
    28
    Hi there! I've been using ATG for a while now to put grass on procedurally-generated terrain. It's worked pretty well for me so far (I just have to refresh the grass after I generate the detail and height maps).

    HOWEVER recently I started breaking my terrains into chunks so that it can cull more effectively. So now I have a map with 4 terrains (set as neighbors) and 4 grass managers. Since this change I have experienced strange culling problems that I can't seem to fix. The grass will cull out if I am in a single spot and pivot to look away from the center of the terrain. It is as though the grass has a very small culling volume rather than covering the entire terrain.
    grasscull.jpg
    multiterrain.jpg
    The culling options I use have served me fine for a single terrain, and still work fine on single-terrain maps.
    Any insight on what might have caused this problem to occur? How full-featured is ATG across multiple terrains? I'd love to keep using it!
    grasssettings.jpg
     
  35. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    i tried to recreate you setup based upon the settings from the grass manager:
    4 terrains, each 32 x 32 meters (?!) (16 cells, cellsize = 2m) and a detail resolution of 256.
    is this correct?

    using these values i was able to reproduce the issue.
    i do not know why it worked for you using just a single terrain - it does not work for me.
    the grass manager stops drawing grass as all culling spheres signal that they are visible - which the manager takes as an error and skips drawing: this usually happens in the first frame when the culling group is not set up properly. in this case all cells would be queried to be initialized - which on a large terrain would be a killer...

    in your case however (using that small terrains) it happens more or less all the time and is not an error.
    so you can simply comment the safe guard.
    grass manager.cs --> line 1246 ff: comment the "return".
    if(numResults == TotalCellCount) {
    // return;
    }

    in order to keep the safe guard we would have to to introduce a simple flag like firstFrameSkipped which is set to false by default/start and gets set to true if(numResults == TotalCellCount)
    then change the if(numResults == TotalCellCount)
    to

    // CullingGroup most likely did not return a valid result... (which happens in the first frame)
    if(numResults == TotalCellCount && !firstFrameSkipped) {
    firstFrameSkipped = true;
    return;
    }
     
    Last edited: Nov 10, 2019
  36. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    it works but could be optimized regarding memory consumption... as all terrains should share a pool of cells and buffers. difficult to do tho without any precomputation.
    but memory should not be an issue in your example.
    nevertheless i would recommend to leower the cache distance: it is set to 96m which 3 times the drawing distance!
    unless you camera is moving very fast you should be able to set it to 40 or even 32 meters instead.
    enable debug -> debug cells and activate "gizmos" in the game view (upper right corner) to see which cells are visible and setup, which have to be set up and which are cached.

    i also recommend to increase the cell size. 2x2meters - that is nothing! and produces a lot of draw commands.
    using larger cells will give you some more work in the vertex shader (as more invisible) vertices will have to be processed before the gpu will cull them but should be faster than doing all the work on the cpu.
    alternatively enabling compute will cull all instances which are not visible before the gpu starts rendering the grass.

    if i set the cell size to 8x8 meters and enable compute i get 520 fps (instead of 250 not using compute and a cell size of 2x2meters).


    terrain in the foreground uses 64 buckets per cell (cell size is 8x8meters)
    terrain in the background uses cells of 2x2meters in size.

    cells.PNG
     
  37. PatrickLipo

    PatrickLipo

    Joined:
    Mar 14, 2015
    Posts:
    28
    Yeah, my terrains are 32x32 meters (it's a tile-based game with 1 "meter" tiles). Since it's a procedurally-generated terrain I start the GrassManager off, set up the terrain in the first frame, and then turn it on. It's an unusual use case to be sure, but that's the game, my scale is "unrealistic" by design. :)

    Your changes worked a treat. I thought that 16x16 was the actual cell size, but it was 2x2 (oops). I didn't introduce a firstFrameSkipped flag as of yet but it's good to know about that option. I still haven't quite used your system to its absolute maximum capability (I know you recommend a grass model rather than an alpha sprite, and it would look far better from above anyway) but I'm looking forward to taking full advantage. Thanks for everything!
     
  38. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    yeah, any mesh with less than 64 vertices will not fully utilize the GPUs wavefront or warp. so instead of drawing 16 quads is way more efficient to draw one mesh containing 16 quads.
     
  39. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    support for URP is coming.

     
  40. Olafson

    Olafson

    Joined:
    Aug 7, 2012
    Posts:
    251
    Hi Lars,
    first of all sorry for the late reply. I did not notice that you sent me a PM. I hope the issue is resolved by now?

    Either way I am afraid that I will have to bother you again... We stepped on a new bug, which makes grass throw thousands of errors on some of our scenes. However this only happens on Scene A, Scene B works just fine.

    The error it throws is:
    Code (CSharp):
    1.  
    2. ArgumentNullException: Value cannot be null.
    3. Parameter name: _unity_self
    4.   at (wrapper managed-to-native) UnityEngine.ComputeBuffer.SetCounterValue(UnityEngine.ComputeBuffer,uint)
    5.   at AdvancedTerrainGrass.GrassManager.DrawGrass () [0x0033e] in C:\Users\nicof\Desktop\BCoF_Unity5_Project - Mapping\Assets\_AdvancedTerrainGrass\_Scripts\GrassManager.cs:1266
    6.   at AdvancedTerrainGrass.GrassManager.LateUpdate () [0x00001] in C:\Users\nicof\Desktop\BCoF_Unity5_Project - Mapping\Assets\_AdvancedTerrainGrass\_Scripts\GrassManager.cs:345
    7.  
    8. (Filename: C:/Users/nicof/Desktop/BCoF_Unity5_Project - Mapping/Assets/_AdvancedTerrainGrass/_Scripts/GrassManager.cs Line: 1266)
    9.  


    The terrains are almost identically to another, they even use the same settings for grass and same number and types of prototypes. Heightmap resolution is 4k for both terrains.

     
    Last edited: Nov 13, 2019
  41. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    hmm, line 1270 does not point me towards anything related to the message when i am looking into the current code...
    can you tell me how this line looks in the version of the grass manager you are using?

    should be:
    MergedCellcontentBuffer.SetCounterValue(0);

    if so MergedCellcontentBuffer seems to not exist.
    easiest explanation: your saved terrain data is out of sync.
    another explanation: it could not be created because you are out of memory.
     
  42. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    version 1.2 is available!
     
    PatrickLipo likes this.
  43. Olafson

    Olafson

    Joined:
    Aug 7, 2012
    Posts:
    251
    Thanks for the quick reply. Yes that is the line. Turning off compute obviously fixes it, but why does it break in the first place? I doubt I am running out of memory, it also works just fine in editor, but breaks in build. Saved Terrain data is up to date.
     
  44. Olafson

    Olafson

    Joined:
    Aug 7, 2012
    Posts:
    251
    Okay, I updated to the new version and that seems to have fixed it. Thank you.
     
  45. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    ups!
    the array of the MergedCellcontentsBuffers is created in the Init() function.
    its size is based upon NumberOfFinalLayers which also gets set up Init() function.

    you may try to wrap the setcounterval...

    for (int i = 0; i < NumberOfFinalLayers; i++) {
    if(MergedCellcontentsBuffers != null) {
    MergedCellcontentsBuffers.SetCounterValue(0);
    }
    }

    but i wonder why it works in editor and not in build.
     
    Last edited: Nov 13, 2019
  46. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    oh, i was too slow, fine!
     
  47. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    2,364
    It's only for deferred on default render pipeline right?
     
  48. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    2,364
    Where can I find screenspace grass? that seems interesting
     
  49. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    no, it supports forward, deferred and URP.
     
    Lars-Steenhoff likes this.
  50. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    5,433
    i don't know what you mean, sorry.
     
unityunity