Vertex Texture Fetch with calculated normals, tangents, working with lighting?

Has anyone written a shader that does modification to the vertex position, and calculates the normals and tangents in the shader post-displacement, and still works properly with lighting? Does anyone have a good starting point?

I imagine I cannot use a surface shader- i’m not sure how/if can manually calculate per-vertex normals and tangents in a surface shader.

Yes, I was working with a heightfield, which can be a basic grid, so this article helped me out. Because I displaced vertices based on a heightfield, I could sample neighboring texels and get easily get vertex data that way. It might be a little trickier with different kinds of meshes though.

That’s totally what I’m doing with a plane- my question was more to do with how to make a shader where I’m calculating normals in a shader integrate with unitys lighting properly. Did you use a cg shader? You wouldn’t perhaps be able to share any code, would you?

To make use of Unity’s default lighting, it’s easiest to use surface shaders. Surface shaders are first compiled into regular vertex and fragment shaders. You can write a surface function, which is called by the automatically generated fragment shader.

You can also let a vertex shader function be called in a similar way (look for ‘optional parameters’ on the page I linked to earlier), which accepts a struct as parameter, similar to how you would write a vertex shader. Only now your vertex shader function is called by the generated vertex shader, in stead of the graphics pipeline.

The code I’m using very specific to my implementation, but I have included the important bits for changing normals at the end of this post. With the documentation and the information I’ve added, you can probably figure it out ;).

// Since you'll be using a surface shader, you could simply use appdata_base, appdata_tan or appdata_full from UnityCG.cginc
// UnityCG.cginc is already included by surface shaders anyway.
struct appdata {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;// Have this in your vertex shader output structure.
    float2 texcoord : TEXCOORD0;
};

void WaterVert (inout appdata v){
    v.normal = calcGridNormal();// Simply output your new float3's to the struct member marked as NORMAL.
}

I should mention that I wrote a surface shader that does height map displacement with VTF. It just doesn’t have proper lighting- my surface shader was complaining about needing tangents when i tried to assign normals in a shader. How did you handle this? Maybe I can do something along these lines: (the last post on the page)
http://forum.unity3d.com/threads/131445-Tangents-missing-on-a-terrain

Since you’re telling me surface shaders are the way to go if i use shader-calculated normals, I will continue down this route, thank you.

If you’re talking about:
Shader warning in 'WaterSimulation/WaterSurface': Program 'vert_surf', invalid subscript 'tangent'I worked around that by adding
float4 tangent : TANGENT;to the appdata struct (alternatively, use appdata_tan or appdata_full), which works fine if you don’t want to do normal mapping. For basic lighting you only need to have the vertex normals set up.

Surface shaders are the way to go if you want Unity to handle adding the lighting calculations. You can also calculate normals in your shader if you use regular vertex and fragment shaders, but you’d have to handle the lighting yourself.

[Edit] I actually just came across the source of the error, while rewriting a surface shader into separate fragment and vertex shaders. ‘v.tangent’ is used when calculating the viewDirection, to determine the rotation matrix.

i’m not totally sure i understand your [edit]- v.tangent is or isn’t required, for basic lighting to work properly? I’m hacking away at this at the moment, and it’s really hard to determine where my issue is, (the lighting /normals appear to be flickering) and narrowing down any possibilities helps.

Im trying two different ways: a sobel kernel, and a gradient sampling, in the vert fn.
Thanks!

v.tangent is required if you’re using viewDir or normal mapping in your surface shader.
If you’re actually going to be using them, I think you’ll have to generate the tangents for your mesh.

Hmm, viewDir shouldn’t need tangent unless you’re using normal maps.

Tangent (and generated binormal, along with the normal) is used to build the rotation matrix for all object space vectors (viewDir, lightDir) in order to rotate them into the same tangent space as the normal map.

If there’s no normal map, you don’t need the matrix and therefore don’t need the tangent.

got it working late last night. my issue was that my uv coords were in 0 to 1 space, i was thinking they were 0 to _MainTex_TexelSize (oops.)