Search Unity

Deform ground mesh/terrain with dynamically modified displacement map

Discussion in 'Shaders' started by grossimatte, Dec 9, 2014.

  1. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hello everybody,
    i would like my character to deform a snowy mesh (or a terrain) possibly using a directx11 tessellation shader, at runtime.

    I am not an expert of coding and shading, but what seems to make the trick is a dynamically modified displacement map, used in the tessellation shader to "extrude" the mesh. I am making some test using a rendertexture camera, and using the rendertexture material into the displacement map in the tessellation shader, it works, but is not 100% what i am looking for. Actually, the texture is raised up, and not lowered down, and i have not much control over it.

    My instinct says that the procedure would be to use two different displacement map, 1 for the main mesh extrusion, and a second one to be subtracted to the first one, so that it can generate a lowering. This way i modify the original displacement map with the player footspteps (or shape) being subtracted.

    Does it make sense?

    There is already an example on this community, but the author of that package is not updating it anymore, and also not responding to messages, so i decided to go through it by my self.

    Any ideas?

    Here is the existing example made in unity:
    http://forum.unity3d.com/threads/snow-tessellation-pack.233527/


    And here approximately the same technique used in Batman Arkham Origin:
    http://www.slideshare.net/colinbb/gdc2014-deformable-snow-rendering-in-batman-arkham-origins


    Also note that i am interested in a non dx11 version, eventually compatible with portable devices.

    Thanks in advance

    Matt
     
  2. HellSinker

    HellSinker

    Joined:
    Apr 18, 2013
    Posts:
    65
    I'm doing a similar stint at the moment - but on a different topic - I wanted to phsyically deform an ocean mesh....

    The way I'm deforming the mesh is similar to what you are after....


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class SnowPseudo : MonoBehaviour {
    5.     public GameObject GroundObject; // Basically just an empty object with a meshfilter and meshrenderer, also a mechcollider if you want that...
    6.     public int Dimension;
    7.     private GameObject[,] Surface;
    8.     private Mesh[,] SurfaceMesh;
    9.     private List<Vector2> uv;
    10.     private List<int> tri;
    11.     void Start()
    12.     {
    13.         int w;
    14.         Surface = new GameObject[Dimension, Dimension];
    15.         SurfaceMesh = new Mesh[Dimension, Dimension];
    16.         for (int x = 0; x < Dimension; x++)
    17.             for (int y = 0; y < Dimension; y++)
    18.             {
    19.                 Surface[x, y] = (GameObject)Instantiate(GroundObject, new Vector3((float)(x * 1 << 6), 0, (float)(y << 6)), Quaternion.Euler(new Vector3(0, 0, 0)));
    20.  
    21.                 SurfaceMesh[x, y] = Surface[x, y].GetComponent<MeshFilter>().mesh;
    22.             }
    23.         uv = new List<Vector2>();
    24.         tri = new List<int>();
    25.         tri.Clear(); uv.Clear();
    26.         for (int u = 0; u < 1 << 6; u++)
    27.             for (int v = 0; v < 1 << 6; v++)
    28.             {
    29.                 w = u;
    30.                 w <<= 6;
    31.                 w += v;
    32.                 w <<= 2;
    33.                 tri.Add(w);
    34.                 tri.Add(w | 2);
    35.                 tri.Add(w | 1);
    36.                 tri.Add(w);
    37.                 tri.Add(w | 3);
    38.                 tri.Add(w | 2);
    39.                 uv.Add(new Vector2(0, 0));
    40.                 uv.Add(new Vector2(1, 1));
    41.                 uv.Add(new Vector2(1, 1));
    42.                 uv.Add(new Vector2(0, 1));
    43.             }
    44.     }
    45.  
    46.     void Update () {
    47.         List<Vector3> xyz=new List<Vector3>();
    48.         for (int x = 0; x < Dimension; x++)
    49.             for (int y = 0; y < Dimension; y++)
    50.             {
    51.                 SurfaceMesh[x,y].Clear();
    52.                 xyz.Clear();
    53.                 for (int u = 0; u < 1<<6; u++)
    54.                     for (int v = 0; v < 1 << 6; v++)
    55.                     {
    56.                         TexCoOrdx = x;
    57.                         TexCoOrdx <<= 6;
    58.                         TexCoOrdx += u;
    59.                         TexCoOrdy = y;
    60.                         TexCoOrdy <<= 6;
    61.                         TexCoOrdy += v;
    62.                         xyz.Add(new Vector3((float)TexCoOrdx, EvalHeight(TexCoOrdx, TexCoOrdy) * 64.0f, (float)TexCoOrdy));
    63.                         xyz.Add(new Vector3((float)(TexCoOrdx + 1), EvalHeight(TexCoOrdx + 1, TexCoOrdy) * 64.0f, (float)TexCoOrdy));
    64.                         xyz.Add(new Vector3((float)(TexCoOrdx + 1), EvalHeight(TexCoOrdx + 1, TexCoOrdy + 1) * 64.0f, (float)(TexCoOrdy + 1)));
    65.                         xyz.Add(new Vector3((float)TexCoOrdx, EvalHeight(TexCoOrdx, TexCoOrdy + 1) * 64.0f, (float)(TexCoOrdy + 1)));
    66.                     }
    67.                 SurfaceMesh[x, y].vertices = xyz.ToArray();
    68.                 SurfaceMesh[x, y].uv = uv.ToArray();
    69.                 SurfaceMesh[x, y].triangles = tri.ToArray();
    70.                 SurfaceMesh[x, y].Optimize();
    71.                 SurfaceMesh[x, y].RecalculateNormals();
    72.             }
    73.     }
    74.     private float EvalHeight(int x, int y)
    75.     {
    76.         return 0.0f;// Here you would hold the snow heights.... which would need to be adjusted where the snow had been displaced, perhaps some kind of array would suffice...
    77.         /* Example
    78.          * return (float) GroundHeight[x,y]+ (float) SnowAmount[x,y];
    79.          * GroundHeight never changes in this case, and may even be a seperate mesh with the collisions on it...
    80.          * SnowAmount is where the values are updated, and has no collisions, if the snow is <0.0f it will be below the ground!
    81.          * everytime (see below) you change a meshchunk - as indicated by its Dimension size - you need to set that chunks specificChunk[x,y] to true, and set doUpdate to true also....
    82.          */
    83.     }
    84. }
    85.  
    Basically - what you are doing is similar to a one or few layer voxel mesh - but instead of using whole cubes - you are just adjusting the surface mesh

    if you want collisions...

    Code (csharp):
    1.  
    2. MeshCollider[,] coll;
    3. coll=new MeshCollider[Dimension,Dimension];
    4.  
    5. coll[x,y] = Surface [ x,y].collider as MeshCollider;
    6.  
    7. // then
    8.  
    9. coll.sharedmesh=surfaceMesh[x,y];
    10.  
    because you are deforming the mesh itself, you can apply any shaders on top of this also..(including tessleation)

    hope that helps...

    EDIT: btw - something which would dynamically improve performance is to put a private bool doUpdate; at the top and wrap most of the Update(){} in a

    Code (CSharp):
    1. if (doUpdate)
    2. {
    3.     // Do the mesh update...
    4.     doUpdate=false;
    5. }
    Then whenever you actually deform the snow - set doUpdate to true...

    sorry - most of that code above is almost directly copy pasted from my own experiment - which has gone horribly wrong atm....

    Also: If you were being picky about the performance - you could also have a bool[,] specificChunk; at the start....

    Then where the chunks are initialized set all of the values in the array to true (to initialize the meshes)...

    Finally just after the for int y loop do this....

    Code (CSharp):
    1. if (!specificChunk[x,y]) continue;
    Don't forget to set it to false after the code is complete(or whereever - just so long as it gets changed so it doesn't keep recalculating the once changed mesh repeatedly after it has already been updated).

    This would cause it so that only the chunk(s) that were altered will be updated, further increasing performance....

    With what I've seen from voxels, your mesh could be quite large doing it this way - with almost no overhead - except the shaders. and poly counts////

    Finally: If you are determined to use a shader - complain to me - I'm pretty sure most of the above could be moved to a vertex shader - I don't mind seeing if I can try that - and might do that in a second post - but this atleast describes the process...

    PS: As a side note - depending on your target platforms - if you really want to squeeze performance - you will see in my code I use a lot of << 6, which is the same a * 64...
    This means that each meshchunk is 64x64 vertexes....
    With low end phones for example - sifting through 4096 verts may be a problem, you could reduce the sizes of the chunks by changing this down a notch or two - to maybe 4 or 5, it would reduce the sizes of the chunks... (maybe don't hard code it) - so that when you do alter a chunk - it only updates a smaller area, the trade off is the expanding size of the Dimension variable... but this is less costly than the updating large chunks...
     
    Last edited: Dec 9, 2014
    RavenOfCode likes this.
  3. MikeUpchat

    MikeUpchat

    Joined:
    Sep 24, 2010
    Posts:
    1,056
    I did something similar in one of my projects but not being a programmer I made use of the displace and paint modifiers in the MegaFiers system, the first one will deform a mesh from a texture so as my character walked over the area where I wanted to leave a path I draw into the texture and that updated the mesh, the other one works in a similar way but does more of the work for you, allowing you to define the area of effect, whether you add or subtract, fall off distances and even have the mesh revert to its original form over time.

     
    led_bet likes this.
  4. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Thank you HellSinker,
    unfortunately i am not a programmer and following your method would mean a lot of frustrating work for me, as my knowledge of programming is very basic.
    MikeUpchat,
    thanks for the advice, definitely what you are describing sounds like what i am looking for at this stage of my experimentation, can i see an example that shows how it worked on your personal project?
    What about performance? Did you also tried it on ios systems?

    I'm going to check the Megafier package right now though, keep you updated.


    Thanks guys, if someone else already went trough it, please share!!!

     
  5. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    I've just tried the Megafiers package, in particular the Displace modifier, simple but impressing.
    Just a question, how did you write into the displacement texture? It's pretty much what i am trying to do.

    Hope you can help me.
     
  6. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,762
    If you submit a support ticket we can help you out.
     
  7. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Thank you Spooky, but there is no need for a support ticket now, as MegaFiers support "can not always respond to requests for custom scripts to be written, if the request is for something that could benefit most users of the system then we can add the request to the wish list but we are not able to write custom scripts or examples", and my issue is not with the Megafiers modifier, so no reason at all for a support ticket, but thanks for asking.

    Anyway i still need help to write into the displacement texture of a displaced mesh at runtime.

    Anyone?
     
  8. MikeUpchat

    MikeUpchat

    Joined:
    Sep 24, 2010
    Posts:
    1,056
    Seems to me they were offering to help you otherwise they wouldn't have said submit a ticket.
     
  9. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    My problem is not with Megafiers, how can they help me?

    I'm just trying to understand how to paint a texture directly into a specular map applied to another object, via a custom script that has nothing to to with their products.

    Can we please stay in-topic?
     
  10. MikeUpchat

    MikeUpchat

    Joined:
    Sep 24, 2010
    Posts:
    1,056
    I think if I had paid out $150 for an extension that does what I need it to and could not figure out how to use part of it I would take the author up on their offer of help.
     
  11. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Can we please stay In-topic and stop the witch-hunt now? If no, then please someone close this thread as it turned irreparably useless to the community.