Normals and vertex shaders

Hello, I’d like to know how can I recalculate normals or beter yet project some sort of normals in a vertex program. The reason why I’m asking this is I’d like to use custom normal directions for a reflection shader.

Might see msilly, but I’ts quite important actually, because the reflection vector is usually based on normals and at some cases they fail. (Planar reflected cubemaps etc.)

You can change, adjust or calculate your own normals. But normally you don’t want to change the normals. Instead you want to project your cube map on a specific distance. The default for reflections is to treat the cube maps as being infinitely far away. You can get better results by projecting the cube map to an actual box for example.

Hey jvo3dc, Box projection does not work in my case, I need some sort of upwards vector math, I’m wanting this kind of results:


As you can see the surface is banked, but the reflection itself is planar.

I supose that the reflection vector must have some sort of height modifyer related to vert position ?

Here’s my code sofar:

Shader "Cg shader with reflection map 2" {
   Properties {
   }
   SubShader {
      Pass {  
         CGPROGRAM

         #pragma vertex vert 
         #pragma fragment frag

         #include "UnityCG.cginc"
       
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float3 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float3 normalDir : TEXCOORD0;
            float3 normalVertDir : TEXCOORD1;
            float3 viewDir : TEXCOORD2;
         };

         vertexOutput vert(vertexInput i)
         {
            vertexOutput o;

            float4x4 modelMatrix = _Object2World;
            float4x4 modelMatrixInverse = _World2Object;

            o.viewDir = mul(modelMatrix, i.vertex).xyz
               - _WorldSpaceCameraPos;
              
            o.normalDir = normalize(
               mul(i.normal, modelMatrixInverse).xyz);              
              
            o.pos = mul(UNITY_MATRIX_MVP, i.vertex);
           
               // Planar reflection vector for nonplanar surface (needs to modify vector height?)
               o.normalVertDir = mul(_World2Object, float3(0,1,0) ).xyz * unity_Scale.w;
            return o;
         }

         float4 frag(vertexOutput i) : COLOR
         {
             // Default reflection vector
            //float3 reflectedDir =
            //   reflect(i.viewDir, normalize(i.normalDir));
           
            // Full planar reflection vector
            //float3 reflectedDir =
            //   reflect(i.viewDir, normalize(float3(0,1,0)));
           
            // Planar with vertex heigt modification
            float3 reflectedDir =
               reflect(i.viewDir, normalize(i.normalVertDir));
              
            //half3 texA = DecodeHDR (UNITY_SAMPLE_TEXCUBE_LOD (unity_SpecCube0, reflectedDir, 0), _TexA_HDR);
            half3 texA = UNITY_SAMPLE_TEXCUBE_LOD (unity_SpecCube0, reflectedDir, 0);
            return float4(texA,1);
         }

         ENDCG
      }
   }
}

Can you show your current result?


This is the current state, this actually was with box projection on. But for example the lamp post on the right is rendered wrong and many other things, you’ll notice them instantly.

any ideas?

Well, I wouldn’t try to adjust the normal. Instead just warp the reflection directly in the pixel shader. This is a tricky one. Mapping the cube correctly will be fairly difficult, because the shape is not easy to capture in a formula. So I’d use a planar reflection buffer. (Camera mirrored around a horizontal plane on the average height of the track.) You’ll have to take care to only render objects that are above the road. (Normally you could use a clip plane, but the changes in height make that very tricky.)

The warp is dependent on the perspective transform, so I would try to include that in the warp directly. That way it keeps working if the field of view changes. So, in the vertex shader, move the vertex to the height of the actual planar reflection and calculate the clip space position again. Then pass this to the pixel shader. In the pixel shader, calculate the screen space projective texture coordinates based on this adjusted clip space position. This should do the trick. You will end up missing information at the edges of the screen this way.