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:
    14
    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:
    895
    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:
    14
    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:
    14
    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);
     
    jackmememe and mahdi1375unity like this.
  5. Invertex

    Invertex

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