diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index d00022984f..c66a325124 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/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_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) {