Search Unity

Bake vertex offset shader to mesh?

Discussion in 'Shaders' started by wadewt, Jan 18, 2018.

  1. wadewt

    wadewt

    Joined:
    Mar 17, 2013
    Posts:
    16
    Hello,

    I'm currently working on a project where I'm using a vertex offset shader to change the shape of an object. I then need to save the modified mesh.

    I've done this previously by using graphics.blit to output a texture which is then used to modify the vertex position on the cpu. The problem with this method is that you start getting limited by the colour depth of the texture and graphics.blit does not have access to the same information as the original mesh - if the shader uses vertex normals, for instance, graphics.blit will use the vertex normals of a quad it renders to, rather than the intended mesh. This leads to using textures for vertex normals which again leads to imprecision, even with 32bit textures.

    I'm just curious if anyone has ideas for a better way to do this.
     
  2. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    The vertex modification only really exists for the moment a specific triangle is being rendered, that is why the only real way to get data out of a normal shader is by encoding it to the image buffers a shader sends its result to. (the same reason why your shadows won't match the displaced object unless you tell Unity to generate a shadowpass from your code or write your own custom one that replicates the vertex movements)

    What you'll have to do is look into using Compute shaders which will allow you to process data with the GPU and access it from the CPU for doing whatever you want like saving it.
     
  3. wadewt

    wadewt

    Joined:
    Mar 17, 2013
    Posts:
    16
    Thanks Invertex, I have just been talking to the progammer I work with and we've been looking into compute shaders also. Good to know we're on the right track.
     
  4. wadewt

    wadewt

    Joined:
    Mar 17, 2013
    Posts:
    16
    We found a solution where we didn't have to use Compute Shaders and instead modified our existing Surface Shader, this was important to us as we were using Amplify Shader Editor so we would need to port all our shader functions from the node system into CG to use a compute shader.

    We targeted Shader Model 5 and added a buffer to the shader to hold the updated vertex positions:
    Code (CG):
    1. RWStructuredBuffer<float3> OutputVertexBuffer : register(u1);
    We also had to change the vert function signature to allow us to get the index of the vertex it is operating on:
    Code (CG):
    1. v2f vert(appdata_full v, uint id : SV_VertexID)
    Then at the end of the vert function just before the return statement we populated it with the offset vertices:
    Code (CG):
    1. OutputVertexBuffer[id] = v.vertex.xyz;
    On the C# side we set up a ComputeBuffer:
    Code (CSharp):
    1. OutputVertexBuffer = new ComputeBuffer(targetMesh.vertexCount, Marshal.SizeOf(typeof(Vector3)));
    Make sure to use this code on the buffer so the Shader can write to the buffer
    Code (CSharp):
    1. Graphics.SetRandomWriteTarget(1, OutputVertexBuffer, true);
    Then we set the buffer in the shader:
    Code (CSharp):
    1. material.SetBuffer(OutputVertexBufferID, OutputVertexBuffer);
    Now whenever we want the updated mesh we can call this code to to fill an array of vertex positions called ExportData:
    Code (CSharp):
    1. OutputVertexBuffer.GetData(ExportData);
     
  5. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    That is essentially a compute shader. Glad you figured it out!
     
  6. Passeridae

    Passeridae

    Joined:
    Jun 16, 2019
    Posts:
    395
    Hi! Sorry for bumping an old thread, but we are trying to achieve the same thing. We are unable to bake any vertex offset created by a texture map. However, we can bake everything else:



    For example, using this shader we can displace our mesh with a texture. This displacement can be observed in the editor just fine and works as expected. But baking this vertex offset creates and "undisplaced" mesh in its original state. On the other hand, if we uncomment this line
    Code (CSharp):
    1. v.vertex.x *=2;
    then our baked mesh will become two times longer along the X axe, just as we expect. To sum it up, we can bake any offset except the one driven by a texture map. And we can't understand where the problem is.

    Here's our compute shader:
     
    ignarmezh likes this.