- Home /
I'm computing my surface normals in the fragment program - so why does Unity still require per-vertex normals/tangents?
Hi all,
In computer graphics there exist techniques for computing a surface normal in the fragment shader, without needing per-vertex information. This is done by using ddx/ddy of the fragments world space to find two vectors which lie on the triangle's surface, and then taking the cross product to find the normal. That is, you can achive a flat-shaded lighting effect even if your vertices only contain positions.
I have implemented this in Unity with the following simple surface shader:
Shader "FlatShadedMesh"
{
SubShader
{
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
#pragma target 3.0
#pragma only_renderers d3d9
struct Input
{
float4 color : COLOR;
float3 worldPos;
};
void surf (Input IN, inout SurfaceOutput o)
{
// Compute the surface normal in the fragment shader.
float3 surfaceNormal = normalize(cross(ddx(IN.worldPos.xyz), ddy(IN.worldPos.xyz)));
o.Albedo = IN.color;
o.Normal = surfaceNormal;
}
ENDCG
}
Fallback "Diffuse"
}
I then generate a mesh using the following snippet of code:
Mesh mesh = new Mesh();
mesh.name = "testMesh";
mesh.Clear();
Vector3[] vertices = new Vector3[resultVertLength / 4];
Vector3[] normals = new Vector3[resultVertLength / 4];
Vector4[] tangents = new Vector4[resultVertLength / 4];
for(int ct = 0; ct < resultVertLength / 4; ct++)
{
vertices[ct] = new Vector3(resultVertices[ct * 4 + 0], resultVertices[ct * 4 + 1], resultVertices[ct * 4 + 2]);
normals[ct] = new Vector3(0.0f, 0.0f, 1.0f); // <-- Dummy normals required by Unity
tangents[ct] = new Vector4(1.0f, 0.0f, 0.0f, 1.0f); //<-- Dummy tangents required by Unity
}
mesh.vertices = vertices;
mesh.normals = normals; // What a waste!
mesh.tangents = tangents; // What a waste!
mesh.triangles = resultIndices;
Note that I am providing dummy normals and tangents. These properties are the same for every vertex, are basically meaningless, and are never used by my surface shader. But if I don't include these dummy properties then Unity complains:
Shader wants tangents but the mesh testMesh doesn't have them
Shader wants normals, but the mesh testMesh doesn't have them
So what must I do so that Unity will let me remove these properties? They are basically tripling the size of my vertex data. My best guess is that Unity wants them to do lighting calculation in tangent space. Can I make it do lighting in world space instead? Any other thoughts on how I can eliminate this unused data?
Answer by whydoidoit · Apr 28, 2013 at 08:06 AM
You need to write a vertex/fragment shader - surface shaders have a lot of pre-written code that gets included that need inputs based on the script you actually write.
Thanks, I half suspected this. But how is it possible to access Unity's light information (position, colour, etc) from a vertex/fragment program? I read http://docs.unity3d.ru/Components/SL-Attenuation.html but I believe it only works with Unity 2 (which is old). At least I tried it, and Unity commented out my shader and explicitly told me to use surface shaders ins$$anonymous$$d. $$anonymous$$aybe I should try again and then post a new question for this...
With Lighting On in the pass:
unity_LightPosition[n] and unity_LightColor[n]
Great, thank you. It seems rather hard to find official documentation for this, I feel that unity_LightPosition[n] should be listed on http://docs.unity3d.com/Documentation/Components/SL-BuiltinValues.html for example (actually I found '_ObjectSpaceLightPos' so maybe I'll use that). However, now that I know what to search for I found a some nice information on the Wiki here: http://en.wikibooks.org/wiki/Cg_Program$$anonymous$$g/Unity/Diffuse_Reflection
Hopefully that tells me everything I need to know - thanks again for you help!
Best thing I found was to read the UnitCG.inc stuff and see how they do it :)
If you feel this has helped, can you tick the answer?
Your answer
Follow this Question
Related Questions
How to write unlit surface shader? 6 Answers
Can I retrieve per face normals instead of per vertex normals in vertex shader? 1 Answer
Reflections not seamless 1 Answer
Mirroring Entire Scene 0 Answers