Browse Source

ShaderGenerator: pack eye-space normal to save one varying

Only when normal mapping is enabled.
rdb 6 years ago
parent
commit
dc8f01df8a
1 changed files with 37 additions and 16 deletions
  1. 37 16
      panda/src/pgraphnodes/shaderGenerator.cxx

+ 37 - 16
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -749,6 +749,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   bool need_world_normal = false;
   bool need_eye_position = key._lighting;
   bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
+  bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
+
+  // If we have binormal/tangent and eye position, we can pack eye normal in
+  // the w channels of the others.
+  bool pack_eye_normal = need_eye_normal && need_tangents && need_eye_position;
 
   bool have_specular = false;
   if (key._lighting) {
@@ -829,7 +834,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       map_index_gloss = i;
     }
   }
-  if (key._texture_flags & ShaderKey::TF_map_normal) {
+  if (need_tangents) {
     tangent_freg = alloc_freg();
     binormal_freg = alloc_freg();
     text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
@@ -854,13 +859,15 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t uniform float4x4 trans_model_to_view,\n";
     eye_position_freg = alloc_freg();
     text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
-  } else if (key._texture_flags & ShaderKey::TF_map_normal) {
+  } else if (need_tangents) {
     text << "\t uniform float4x4 trans_model_to_view,\n";
   }
   if (need_eye_normal) {
-    eye_normal_freg = alloc_freg();
     text << "\t uniform float4x4 tpose_view_to_model,\n";
-    text << "\t out float3 l_eye_normal : " << eye_normal_freg << ",\n";
+    if (!pack_eye_normal)  {
+      eye_normal_freg = alloc_freg();
+      text << "\t out float3 l_eye_normal : " << eye_normal_freg << ",\n";
+    }
   }
   if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
     text << "\t in float3 vtx_normal : " << normal_vreg << ",\n";
@@ -946,9 +953,6 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (need_eye_position) {
     text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
   }
-  if (need_eye_normal) {
-    text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
-  }
   pmap<const InternalName *, const char *>::const_iterator it;
   for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
     // Pass through all texcoord inputs as-is.
@@ -958,7 +962,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (need_color && key._color_type == ColorAttrib::T_vertex) {
     text << "\t l_color = vtx_color;\n";
   }
-  if (key._texture_flags & ShaderKey::TF_map_normal) {
+  if (need_tangents) {
     text << "\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input << ".xyz));\n";
     text << "\t l_tangent.w = 0;\n";
     text << "\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input << ".xyz));\n";
@@ -976,6 +980,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
     text << "\t l_eyevec = normalize(l_eyevec);\n";
   }
+  if (need_eye_normal) {
+    if (pack_eye_normal) {
+      // We can pack the normal into the w channels of these unused varyings.
+      text << "\t float3 eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
+      text << "\t l_tangent.w = eye_normal.x;\n";
+      text << "\t l_binormal.w = eye_normal.y;\n";
+      text << "\t l_eye_position.w = eye_normal.z;\n";
+    } else {
+      text << "\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
+    }
+  }
   text << "}\n\n";
 
   // Fragment shader
@@ -995,7 +1010,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (need_eye_position) {
     text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n";
   }
-  if (need_eye_normal) {
+  if (need_eye_normal && !pack_eye_normal) {
     text << "\t in float3 l_eye_normal : " << eye_normal_freg << ",\n";
   }
   for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
@@ -1020,9 +1035,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t uniform float4 texcolor_" << i << ",\n";
     }
   }
-  if (key._texture_flags & ShaderKey::TF_map_normal) {
-    text << "\t in float3 l_tangent : " << tangent_freg << ",\n";
-    text << "\t in float3 l_binormal : " << binormal_freg << ",\n";
+  if (need_tangents) {
+    text << "\t in float4 l_tangent : " << tangent_freg << ",\n";
+    text << "\t in float4 l_binormal : " << binormal_freg << ",\n";
   }
   for (size_t i = 0; i < key._lights.size(); ++i) {
     text << "\t uniform float4x4 attr_light" << i << ",\n";
@@ -1078,6 +1093,12 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t discard;\n";
     text << "\t }\n";
   }
+
+  // Reconstruct a packed normal vector.
+  if (need_eye_normal && pack_eye_normal) {
+    text << "\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
+  }
+
   text << "\t float4 result;\n";
   if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
     text << "\t o_aux = float4(0, 0, 0, 0);\n";
@@ -1102,7 +1123,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t float4 texcoord" << i << " = l_world_normal;\n";
       break;
     case TexGenAttrib::M_eye_position:
-      text << "\t float4 texcoord" << i << " = l_eye_position;\n";
+      text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n";
       break;
     case TexGenAttrib::M_eye_normal:
       text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n";
@@ -1199,7 +1220,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t // Correct the surface normal for interpolation effects\n";
     text << "\t l_eye_normal = normalize(l_eye_normal);\n";
   }
-  if (key._texture_flags & ShaderKey::TF_map_normal) {
+  if (need_tangents) {
     text << "\t // Translate tangent-space normal in map to view-space.\n";
 
     // Use Reoriented Normal Mapping to blend additional normal maps.
@@ -1218,8 +1239,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       }
     }
     text << "\t l_eye_normal *= tsnormal.z;\n";
-    text << "\t l_eye_normal += normalize(l_tangent) * tsnormal.x;\n";
-    text << "\t l_eye_normal += normalize(l_binormal) * tsnormal.y;\n";
+    text << "\t l_eye_normal += normalize(l_tangent.xyz) * tsnormal.x;\n";
+    text << "\t l_eye_normal += normalize(l_binormal.xyz) * tsnormal.y;\n";
     text << "\t l_eye_normal = normalize(l_eye_normal);\n";
   }
   if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {