1
votes

Update

The main question is: How can I pass the world space vertex positions of the triangle to the surface shader in a Unity shader. As mentioned in a comment it might be possible to pass them from a geometry shader. But I read somewhere that implementing a custom geometry shader overwrites Unitys logic to calculate shadows etc. I would add the triangle information in the Input structure. But before I change my mesh generation logic for it I would like to know if this is feasible. For this solution the vertex positions of the triangle must be constant for every pixel in a triangle and not be interpolated.

This is the original question:

I am writing a surface shader for a triangle mesh. I set a custom vertex attribute with a texture id to every vertex. Now I want the surface shader to apply the texture as seen in the following image. (Note that each color is representing a texture) enter image description here

In the surface shader I need the 3 vertices that define the triangle and their texture ids. Furthermore I need to position of the pixel I am drawing.

  1. If all texture ids are the same I pick this texture for all pixels.
  2. If one or two texture ids differ I calculate the pixels distance to the triangle vertices and pick the texture like seen in the next image: enter image description here

The surface shader needs to be aware of the pixels triangle. With this logic I should get the shading I am looking for. I am creating my mesh programmatically so I can add the triangle vertices and their texture ids as vertex attributes and pass it to the surface shader.

But I am not sure if this is feasible with how surface/vertex shaders work. Is there a relationship between the vertex and the pixel to get my custom triangle information from? Is there a better way of doing this?

I am using Unitys ShaderLab for my shaders.

2
In both of these cases, if the triangle becomes very obtuse, the lines will go outside of the triangle. Is this intended or can you guarantee that the triangles are not obtuse?Nico Schertler
Thank you for the hint. This is no issue. The triangles always have this form.Luca Hofmann
Then I would probably use the geometry shader to gather the required triangle information and pass those to the fragment shader. No need to change the mesh. Alternatively, you could use the gl_PrimitiveID from the fragment shader. But that alone without random access to the vertex data will not help you much. The geometry shader can also bring the vertices in a canonical order, such that you don't have that many cases to handle in the fragment shader.Nico Schertler
It would be nice to pass them from the geometry shader since I have all the vertices of the primitive (triangle) without changing the mesh. However I have doubts if I destroy the build in logic of Unity with a custom geometry shader (e.g. calculating shadows). I am also not sure if the pipeline interpolates the vertex positions making them unusable for my purpose.Luca Hofmann
Well, you need a custom fragment shader anyway, so you have to replicate whichever Unity functionality you want to use. Adding a geometry shader in between shouldn't change that. You can use interpolation qualifiers on your attributes to tell the GPU not to interpolate. But since all of your vertices would have the same attributes, interpolation wouldn't hurt either (you have three distinct attributes, the first one set to the first vertex position of the triangle for all three vertices and so on...)Nico Schertler

2 Answers

1
votes

No, you should not be (nor have acceess to) using vertex data in a fragment shader. In a fragment shader you only have access to data about that given pixel, you cannot go back and look at the mesh that formed it (this is the way the pipeline is constructed).

What you can do (and is a common practice) is to bake the data into one of the available channels (i.e. other UV Mapping channels) of the verts within the Vertex Shader. This way the Fragment shader will have access to the value via interpolators

0
votes

Ok I think I found a solution. Thank you for the comments, they where useful.

Fist I change my grid topology to not use shared vertices. With this I can use a vertex color channel to set the texture ids.

vertexColor.r = vertexTextureId0; // Texture to use for vertex 0
vertexColor.g = vertexTextureId1; // Texture to use for vertex 1
vertexColor.b = vertexTextureId2; // Texture to use for vertex 2

I do not have to worry about interpolation because all vertices of the triangle have the same color information. Now I create a texture to look up to which vertex my pixel belongs to. This texture looks similar to the images I posted in the question. I have to transpose the UV coordinates according to the TWO or THREE case. This solution gives me the freedom to easily change the edge and make it more ragged.