From dc8f01df8a4a0fc50fbc6eb27f5886b76ae0f55a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:51:50 +0100 Subject: [PATCH 1/6] ShaderGenerator: pack eye-space normal to save one varying Only when normal mapping is enabled. --- panda/src/pgraphnodes/shaderGenerator.cxx | 53 ++++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) 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) { From 0e447b7429117d6a0ee173cee9736f2271896ed5 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:54:22 +0100 Subject: [PATCH 2/6] ShaderGenerator: do shadow map calcs in fshader if out of varyings If too many shadow-casting lights are active, too many TEXCOORD varyings will be used and a shader compilation error will be displayed. Instead, Panda will now just do the calculation in the fragment shader if not enough varyings are available. It's slower, but better than crashing. --- panda/src/pgraphnodes/shaderGenerator.cxx | 45 +++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index c66a325124..77575371dd 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -876,20 +876,26 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { text << "\t uniform float4 mspos_view,\n"; text << "\t out float3 l_eyevec,\n"; } - for (size_t i = 0; i < key._lights.size(); ++i) { - const ShaderKey::LightInfo &light = key._lights[i]; - if (light._flags & ShaderKey::LF_has_shadows) { - lightcoord_fregs.push_back(alloc_freg()); - text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; - text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; - } else { - lightcoord_fregs.push_back(nullptr); - } - } if (key._fog_mode != 0) { hpos_freg = alloc_freg(); text << "\t out float4 l_hpos : " << hpos_freg << ",\n"; } + for (size_t i = 0; i < key._lights.size(); ++i) { + const ShaderKey::LightInfo &light = key._lights[i]; + if (light._flags & ShaderKey::LF_has_shadows) { + if (_ftregs_used >= 8) { + // We ran out of TEXCOORD registers. That means we have to do this + // calculation in the fragment shader, which is slower. + lightcoord_fregs.push_back(nullptr); + } else { + lightcoord_fregs.push_back(alloc_freg()); + text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; + text << "\t out float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } + } else { + lightcoord_fregs.push_back(nullptr); + } + } if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware && key._anim_spec.get_num_transforms() > 0) { int num_transforms; @@ -970,7 +976,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } for (size_t i = 0; i < key._lights.size(); ++i) { if (key._lights[i]._flags & ShaderKey::LF_has_shadows) { - text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n"; + if (lightcoord_fregs[i] != nullptr) { + text << "\t l_lightcoord" << i << " = mul(mat_shadow_" << i << ", l_eye_position);\n"; + } } } if (key._texture_flags & ShaderKey::TF_map_height) { @@ -1051,7 +1059,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } else { text << "\t uniform sampler2D shadow_" << i << ",\n"; } - text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + if (lightcoord_fregs[i] != nullptr) { + text << "\t in float4 l_lightcoord" << i << " : " << lightcoord_fregs[i] << ",\n"; + } else { + text << "\t uniform float4x4 mat_shadow_" << i << ",\n"; + } } if (light._flags & ShaderKey::LF_has_specular_color) { text << "\t uniform float4 attr_lspec" << i << ",\n"; @@ -1272,6 +1284,15 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } for (size_t i = 0; i < key._lights.size(); ++i) { const ShaderKey::LightInfo &light = key._lights[i]; + + if (light._flags & ShaderKey::LF_has_shadows) { + if (lightcoord_fregs[i] == nullptr) { + // We have to do this one in the fragment shader if we ran out of + // varyings. + text << "\t float4 l_lightcoord" << i << " = mul(mat_shadow_" << i << ", float4(l_eye_position.xyz, 1.0f));\n"; + } + } + if (light._type.is_derived_from(DirectionalLight::get_class_type())) { text << "\t // Directional Light " << i << "\n"; text << "\t lcolor = attr_light" << i << "[0];\n"; From 1d9334f578491230418501c1bd645062dd4efdda Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 30 Jan 2019 23:59:34 +0100 Subject: [PATCH 3/6] parser-inc: add atomic_int, etc. typedefs --- dtool/src/parser-inc/atomic | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dtool/src/parser-inc/atomic b/dtool/src/parser-inc/atomic index a7e174937b..8167308f33 100644 --- a/dtool/src/parser-inc/atomic +++ b/dtool/src/parser-inc/atomic @@ -16,4 +16,50 @@ namespace std { template struct atomic; struct atomic_flag; + + using atomic_bool = atomic; + using atomic_char = atomic; + using atomic_schar = atomic; + using atomic_uchar = atomic; + using atomic_short = atomic; + using atomic_ushort = atomic; + using atomic_int = atomic; + using atomic_uint = atomic; + using atomic_long = atomic; + using atomic_ulong = atomic; + using atomic_llong = atomic; + using atomic_ullong = atomic; + using atomic_char16_t = atomic; + using atomic_char32_t = atomic; + using atomic_wchar_t = atomic; + using atomic_int8_t = atomic; + using atomic_uint8_t = atomic; + using atomic_int16_t = atomic; + using atomic_uint16_t = atomic; + using atomic_int32_t = atomic; + using atomic_uint32_t = atomic; + using atomic_int64_t = atomic; + using atomic_uint64_t = atomic; + using atomic_int_least8_t = atomic; + using atomic_uint_least8_t = atomic; + using atomic_int_least16_t = atomic; + using atomic_uint_least16_t = atomic; + using atomic_int_least32_t = atomic; + using atomic_uint_least32_t = atomic; + using atomic_int_least64_t = atomic; + using atomic_uint_least64_t = atomic; + using atomic_int_fast8_t = atomic; + using atomic_uint_fast8_t = atomic; + using atomic_int_fast16_t = atomic; + using atomic_uint_fast16_t = atomic; + using atomic_int_fast32_t = atomic; + using atomic_uint_fast32_t = atomic; + using atomic_int_fast64_t = atomic; + using atomic_uint_fast64_t = atomic; + using atomic_intptr_t = atomic; + using atomic_uintptr_t = atomic; + using atomic_size_t = atomic; + using atomic_ptrdiff_t = atomic; + using atomic_intmax_t = atomic; + using atomic_uintmax_t = atomic; } From 0ba1235d350a3136bdfd8691907cf024fd581bc8 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Jan 2019 00:05:23 +0100 Subject: [PATCH 4/6] ShaderGenerator: print out generated shader in spam output mode --- panda/src/pgraphnodes/shaderGenerator.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 77575371dd..7198024648 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -1684,6 +1684,11 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) { } text << "}\n"; + if (pgraphnodes_cat.is_spam()) { + pgraphnodes_cat.spam() << "Generated shader:\n" + << text.str() << "\n"; + } + // Insert the shader into the shader attrib. PT(Shader) shader = Shader::make(text.str(), Shader::SL_Cg); nassertr(shader != nullptr, nullptr); From 2627c433d60837a03c0453d81c9371e99a2227a7 Mon Sep 17 00:00:00 2001 From: John Cote Date: Wed, 30 Jan 2019 14:03:35 -0500 Subject: [PATCH 5/6] particles: Import SpriteAnim in Particles.py Fixes #544 Closes #545 --- direct/src/particles/Particles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/particles/Particles.py b/direct/src/particles/Particles.py index 6ed19af896..d05700c3b1 100644 --- a/direct/src/particles/Particles.py +++ b/direct/src/particles/Particles.py @@ -22,6 +22,7 @@ from panda3d.physics import RingEmitter from panda3d.physics import SphereSurfaceEmitter from panda3d.physics import SphereVolumeEmitter from panda3d.physics import TangentRingEmitter +from panda3d.physics import SpriteAnim from . import SpriteParticleRendererExt From 3a6f7fcde1f89c975ac558aa07e987f11bde0c07 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Jan 2019 00:11:21 +0100 Subject: [PATCH 6/6] dtoolbase: docstring clarification for record_python_type [skip ci] --- dtool/src/dtoolbase/typeRegistry.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 360dfcd9e4..16f551ec33 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -210,7 +210,7 @@ record_alternate_name(TypeHandle type, const string &name) { #ifdef HAVE_PYTHON /** * Records the given Python type pointer in the type registry for the benefit - * of interrogate. + * of interrogate, which expects this to contain a Dtool_PyTypedObject. */ void TypeRegistry:: record_python_type(TypeHandle type, PyObject *python_type) {