56 #define UNPACK_COMBINE_SRC(from, n) (TextureStage::CombineSource)((from >> ((uint16_t)n * 5u)) & 7u) 57 #define UNPACK_COMBINE_OP(from, n) (TextureStage::CombineOperand)(((from >> (((uint16_t)n * 5u) + 3u)) & 3u) + 1u) 59 static inline uint16_t
60 pack_combine(TextureStage::CombineSource src0, TextureStage::CombineOperand op0,
61 TextureStage::CombineSource src1, TextureStage::CombineOperand op1,
62 TextureStage::CombineSource src2, TextureStage::CombineOperand op2) {
63 if (op0 == TextureStage::CO_undefined) op0 = TextureStage::CO_src_alpha;
64 if (op1 == TextureStage::CO_undefined) op1 = TextureStage::CO_src_alpha;
65 if (op2 == TextureStage::CO_undefined) op2 = TextureStage::CO_src_alpha;
67 return ((uint16_t)src0) | ((((uint16_t)op0 - 1u) & 3u) << 3u) |
68 ((uint16_t)src1 << 5u) | ((((uint16_t)op1 - 1u) & 3u) << 8u) |
69 ((uint16_t)src2 << 10u) | ((((uint16_t)op2 - 1u) & 3u) << 13u);
72 static PStatCollector lookup_collector(
"*:Munge:ShaderGen:Lookup");
73 static PStatCollector synthesize_collector(
"*:Munge:ShaderGen:Synthesize");
86 _use_generic_attr = !gsg->get_supports_hlsl();
88 _use_generic_attr =
true;
93 _use_shadow_filter = gsg->get_supports_shadow_filter();
107 void ShaderGenerator::
108 reset_register_allocator() {
118 const char *ShaderGenerator::
120 if (_use_generic_attr) {
122 switch (_vtregs_used) {
123 case 0: _vtregs_used += 1;
return "ATTR8";
124 case 1: _vtregs_used += 1;
return "ATTR9";
125 case 2: _vtregs_used += 1;
return "ATTR10";
126 case 3: _vtregs_used += 1;
return "ATTR11";
127 case 4: _vtregs_used += 1;
return "ATTR12";
128 case 5: _vtregs_used += 1;
return "ATTR13";
129 case 6: _vtregs_used += 1;
return "ATTR14";
130 case 7: _vtregs_used += 1;
return "ATTR15";
132 switch (_vcregs_used) {
133 case 0: _vcregs_used += 1;
return "ATTR3";
134 case 1: _vcregs_used += 1;
return "ATTR4";
135 case 2: _vcregs_used += 1;
return "ATTR5";
136 case 3: _vcregs_used += 1;
return "ATTR6";
137 case 4: _vcregs_used += 1;
return "ATTR7";
138 case 5: _vcregs_used += 1;
return "ATTR1";
142 switch (_vtregs_used) {
143 case 0: _vtregs_used += 1;
return "TEXCOORD0";
144 case 1: _vtregs_used += 1;
return "TEXCOORD1";
145 case 2: _vtregs_used += 1;
return "TEXCOORD2";
146 case 3: _vtregs_used += 1;
return "TEXCOORD3";
147 case 4: _vtregs_used += 1;
return "TEXCOORD4";
148 case 5: _vtregs_used += 1;
return "TEXCOORD5";
149 case 6: _vtregs_used += 1;
return "TEXCOORD6";
150 case 7: _vtregs_used += 1;
return "TEXCOORD7";
152 switch (_vcregs_used) {
153 case 0: _vcregs_used += 1;
return "COLOR0";
154 case 1: _vcregs_used += 1;
return "COLOR1";
159 switch (_vtregs_used) {
160 case 8: _vtregs_used += 1;
return "TEXCOORD8";
161 case 9: _vtregs_used += 1;
return "TEXCOORD9";
162 case 10: _vtregs_used += 1;
return "TEXCOORD10";
163 case 11: _vtregs_used += 1;
return "TEXCOORD11";
164 case 12: _vtregs_used += 1;
return "TEXCOORD12";
165 case 13: _vtregs_used += 1;
return "TEXCOORD13";
166 case 14: _vtregs_used += 1;
return "TEXCOORD14";
167 case 15: _vtregs_used += 1;
return "TEXCOORD15";
175 const char *ShaderGenerator::
177 switch (_ftregs_used) {
178 case 0: _ftregs_used += 1;
return "TEXCOORD0";
179 case 1: _ftregs_used += 1;
return "TEXCOORD1";
180 case 2: _ftregs_used += 1;
return "TEXCOORD2";
181 case 3: _ftregs_used += 1;
return "TEXCOORD3";
182 case 4: _ftregs_used += 1;
return "TEXCOORD4";
183 case 5: _ftregs_used += 1;
return "TEXCOORD5";
184 case 6: _ftregs_used += 1;
return "TEXCOORD6";
185 case 7: _ftregs_used += 1;
return "TEXCOORD7";
189 switch (_ftregs_used) {
190 case 8: _ftregs_used += 1;
return "TEXCOORD8";
191 case 9: _ftregs_used += 1;
return "TEXCOORD9";
192 case 10: _ftregs_used += 1;
return "TEXCOORD10";
193 case 11: _ftregs_used += 1;
return "TEXCOORD11";
194 case 12: _ftregs_used += 1;
return "TEXCOORD12";
195 case 13: _ftregs_used += 1;
return "TEXCOORD13";
196 case 14: _ftregs_used += 1;
return "TEXCOORD14";
197 case 15: _ftregs_used += 1;
return "TEXCOORD15";
206 void ShaderGenerator::
207 analyze_renderstate(ShaderKey &key,
const RenderState *rs) {
209 rs->get_attrib_def(shader_attrib);
214 rs->get_attrib_def(aux_bitplane);
215 key._outputs = aux_bitplane->get_outputs();
218 bool have_alpha_test =
false;
219 bool have_alpha_blend =
false;
221 rs->get_attrib_def(alpha_test);
222 if (alpha_test->
get_mode() != RenderAttrib::M_none &&
223 alpha_test->
get_mode() != RenderAttrib::M_always) {
224 have_alpha_test =
true;
227 rs->get_attrib_def(color_blend);
228 if (color_blend->
get_mode() != ColorBlendAttrib::M_none) {
229 have_alpha_blend =
true;
232 rs->get_attrib_def(transparency);
233 if (transparency->
get_mode() == TransparencyAttrib::M_alpha ||
234 transparency->
get_mode() == TransparencyAttrib::M_premultiplied_alpha ||
235 transparency->
get_mode() == TransparencyAttrib::M_dual) {
236 have_alpha_blend =
true;
240 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
241 if (have_alpha_blend) {
243 key._disable_alpha_write =
true;
244 }
else if (have_alpha_test) {
246 key._alpha_test_mode = alpha_test->
get_mode();
251 if (have_alpha_blend || have_alpha_test) {
252 key._calc_primary_alpha =
true;
257 rs->get_attrib_def(
color);
258 key._color_type =
color->get_color_type();
262 rs->get_attrib_def(material);
264 if (mat !=
nullptr) {
267 mat->mark_used_by_auto_shader();
268 key._material_flags = mat->get_flags();
270 if ((key._material_flags & Material::F_base_color) != 0) {
271 key._material_flags |= (Material::F_diffuse | Material::F_specular | Material::F_ambient);
272 key._material_flags &= ~
Material::F_base_color;
278 rs->get_attrib_def(la);
279 bool have_ambient =
false;
285 nassertv(node !=
nullptr);
287 if (node->is_ambient_light()) {
289 key._lighting =
true;
291 ShaderKey::LightInfo info;
292 info._type = node->get_type();
295 if (node->is_of_type(LightLensNode::get_class_type())) {
297 if (shader_attrib->auto_shadow_on()) {
299 info._flags |= ShaderKey::LF_has_shadows;
307 info._flags |= ShaderKey::LF_has_specular_color;
311 key._lights.push_back(info);
312 key._lighting =
true;
320 rs->get_attrib_def(texture);
322 rs->get_attrib_def(tex_gen);
324 rs->get_attrib_def(tex_matrix);
327 for (
size_t i = 0; i < num_textures; ++i) {
330 nassertd(tex !=
nullptr) continue;
335 stage->mark_used_by_auto_shader();
337 ShaderKey::TextureInfo info;
338 info._type = tex->get_texture_type();
339 info._mode = stage->get_mode();
341 info._combine_rgb = 0u;
342 info._combine_alpha = 0u;
346 switch (info._mode) {
347 case TextureStage::M_modulate:
350 if (format != Texture::F_alpha) {
351 info._flags |= ShaderKey::TF_has_rgb;
354 info._flags |= ShaderKey::TF_has_alpha;
359 case TextureStage::M_modulate_glow:
360 if (shader_attrib->auto_glow_on()) {
361 info._flags = ShaderKey::TF_map_glow;
363 info._mode = TextureStage::M_modulate;
364 info._flags = ShaderKey::TF_has_rgb;
368 case TextureStage::M_modulate_gloss:
369 if (shader_attrib->auto_gloss_on()) {
370 info._flags = ShaderKey::TF_map_gloss;
372 info._mode = TextureStage::M_modulate;
373 info._flags = ShaderKey::TF_has_rgb;
377 case TextureStage::M_normal_height:
378 if (parallax_mapping_samples == 0) {
379 info._mode = TextureStage::M_normal;
380 }
else if (!shader_attrib->auto_normal_on() ||
381 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
382 info._mode = TextureStage::M_height;
383 info._flags = ShaderKey::TF_has_alpha;
385 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_height;
389 case TextureStage::M_normal_gloss:
390 if (!shader_attrib->auto_gloss_on() || key._lights.empty()) {
391 info._mode = TextureStage::M_normal;
392 }
else if (!shader_attrib->auto_normal_on()) {
393 info._mode = TextureStage::M_gloss;
395 info._flags = ShaderKey::TF_map_normal | ShaderKey::TF_map_gloss;
399 case TextureStage::M_combine:
405 info._flags |= ShaderKey::TF_rgb_scale_2;
408 info._flags |= ShaderKey::TF_rgb_scale_4;
411 info._flags |= ShaderKey::TF_alpha_scale_2;
414 info._flags |= ShaderKey::TF_alpha_scale_4;
417 info._combine_rgb = pack_combine(
421 info._combine_alpha = pack_combine(
427 info._flags |= ShaderKey::TF_uses_primary_color;
430 info._flags |= ShaderKey::TF_uses_last_saved_result;
440 switch (info._mode) {
441 case TextureStage::M_normal:
442 if (!shader_attrib->auto_normal_on() ||
443 (key._lights.empty() && (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) == 0)) {
446 info._flags = ShaderKey::TF_map_normal;
449 case TextureStage::M_glow:
450 if (shader_attrib->auto_glow_on()) {
451 info._flags = ShaderKey::TF_map_glow;
456 case TextureStage::M_gloss:
457 if (!key._lights.empty() && shader_attrib->auto_gloss_on()) {
458 info._flags = ShaderKey::TF_map_gloss;
463 case TextureStage::M_height:
464 if (parallax_mapping_samples > 0) {
465 info._flags = ShaderKey::TF_map_height;
477 info._type = Texture::TT_1d_texture;
478 info._mode = TextureStage::M_modulate;
480 key._textures.push_back(info);
486 if (tex_matrix->has_stage(stage)) {
488 if (!transform->is_identity()) {
491 if (transform->has_components() && !transform->has_nonzero_shear() &&
492 transform->get_pos() == LPoint3::zero() &&
493 transform->get_hpr() == LVecBase3::zero()) {
494 info._flags |= ShaderKey::TF_has_texscale;
496 info._flags |= ShaderKey::TF_has_texmat;
501 if (tex_gen->has_stage(stage)) {
502 info._texcoord_name =
nullptr;
503 info._gen_mode = tex_gen->get_mode(stage);
506 info._gen_mode = TexGenAttrib::M_off;
511 info._flags |= ShaderKey::TF_saved_result;
516 info._flags |= ShaderKey::TF_uses_color;
519 key._textures.push_back(info);
520 key._texture_flags |= info._flags;
524 if ((key._texture_flags & ShaderKey::TF_uses_last_saved_result) == 0 &&
525 (key._texture_flags & ShaderKey::TF_saved_result) != 0) {
528 for (it = key._textures.begin(); it != key._textures.end(); ++it) {
529 (*it)._flags &= ~ShaderKey::TF_saved_result;
531 key._texture_flags &= ~ShaderKey::TF_saved_result;
536 if (key._material_flags & Material::F_ambient) {
537 key._have_separate_ambient =
true;
539 if (key._material_flags & Material::F_diffuse) {
540 key._have_separate_ambient =
true;
542 key._have_separate_ambient =
false;
547 if (shader_attrib->auto_ramp_on()) {
549 if (rs->get_attrib(light_ramp)) {
550 key._light_ramp = light_ramp;
552 key._have_separate_ambient =
true;
559 rs->get_attrib_def(clip_plane);
564 if (rs->get_attrib(fog) && !fog->
is_off()) {
565 key._fog_mode = (int)fog->
get_fog()->get_mode() + 1;
577 void ShaderGenerator::
578 rehash_generated_shaders() {
584 for (
size_t si = 0; si < size; ++si) {
587 if (state->_generated_shader !=
nullptr) {
589 analyze_renderstate(key, state);
591 GeneratedShaders::const_iterator si;
592 si = _generated_shaders.find(key);
593 if (si != _generated_shaders.end()) {
594 if (si->second != state->_generated_shader) {
595 state->_generated_shader = si->second;
596 state->_munged_states.
clear();
600 state->_generated_shader.clear();
601 state->_munged_states.
clear();
609 if (!uniquify_states) {
610 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
618 void ShaderGenerator::
619 clear_generated_shaders() {
623 for (
size_t si = 0; si < size; ++si) {
625 state->_generated_shader.clear();
628 _generated_shaders.clear();
632 if (!uniquify_states) {
633 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
672 key._anim_spec = anim;
673 analyze_renderstate(key, rs);
675 GeneratedShaders::const_iterator si;
676 si = _generated_shaders.find(key);
677 if (si != _generated_shaders.end()) {
685 reset_register_allocator();
687 if (pgraphnodes_cat.is_debug()) {
688 pgraphnodes_cat.debug()
689 <<
"Generating shader for render state " << rs <<
":\n";
690 rs->write(pgraphnodes_cat.debug(
false), 2);
695 const char *tangent_freg =
nullptr;
696 const char *binormal_freg =
nullptr;
697 string tangent_input;
698 string binormal_input;
701 const char *world_position_freg =
nullptr;
702 const char *world_normal_freg =
nullptr;
703 const char *eye_position_freg =
nullptr;
704 const char *eye_normal_freg =
nullptr;
705 const char *hpos_freg =
nullptr;
707 const char *position_vreg;
708 const char *transform_weight_vreg =
nullptr;
709 const char *normal_vreg;
710 const char *color_vreg =
nullptr;
711 const char *transform_index_vreg =
nullptr;
713 if (_use_generic_attr) {
714 position_vreg =
"ATTR0";
715 transform_weight_vreg =
"ATTR1";
716 normal_vreg =
"ATTR2";
717 transform_index_vreg =
"ATTR7";
719 position_vreg =
"POSITION";
720 normal_vreg =
"NORMAL";
723 if (key._color_type == ColorAttrib::T_vertex) {
725 color_vreg = _use_generic_attr ?
"ATTR3" :
"COLOR0";
732 std::ostringstream text;
736 text <<
"/* Generated shader for render state:\n";
740 int map_index_glow = -1;
741 int map_index_gloss = -1;
744 bool need_world_position = (key._num_clip_planes > 0);
745 bool need_world_normal =
false;
746 bool need_eye_position = key._lighting;
747 bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
749 bool have_specular =
false;
751 if (key._material_flags & Material::F_specular) {
752 have_specular =
true;
753 }
else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) {
754 have_specular =
true;
758 bool need_color =
false;
759 if (key._color_type != ColorAttrib::T_off) {
761 if (((key._material_flags & Material::F_ambient) == 0 && key._have_separate_ambient) ||
762 (key._material_flags & Material::F_diffuse) == 0 ||
763 key._calc_primary_alpha) {
771 text <<
"void vshader(\n";
772 for (
size_t i = 0; i < key._textures.size(); ++i) {
773 const ShaderKey::TextureInfo &tex = key._textures[i];
775 switch (tex._gen_mode) {
776 case TexGenAttrib::M_world_position:
777 need_world_position =
true;
779 case TexGenAttrib::M_world_normal:
780 need_world_normal =
true;
782 case TexGenAttrib::M_eye_position:
783 need_eye_position =
true;
785 case TexGenAttrib::M_eye_normal:
786 need_eye_normal =
true;
792 if (tex._texcoord_name !=
nullptr) {
793 if (texcoord_fregs.count(tex._texcoord_name) == 0) {
794 const char *freg = alloc_freg();
795 texcoord_fregs[tex._texcoord_name] = freg;
797 string tcname = tex._texcoord_name->join(
"_");
798 text <<
"\t in float4 vtx_" << tcname <<
" : " << alloc_vreg() <<
",\n";
799 text <<
"\t out float4 l_" << tcname <<
" : " << freg <<
",\n";
803 if (tangent_input.empty() &&
804 (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) != 0) {
805 PT(
InternalName) tangent_name = InternalName::get_tangent();
806 PT(
InternalName) binormal_name = InternalName::get_binormal();
808 if (tex._texcoord_name !=
nullptr &&
809 tex._texcoord_name != InternalName::get_texcoord()) {
810 tangent_name = tangent_name->append(tex._texcoord_name->get_basename());
811 binormal_name = binormal_name->append(tex._texcoord_name->get_basename());
814 tangent_input = tangent_name->join(
"_");
815 binormal_input = binormal_name->join(
"_");
817 text <<
"\t in float4 vtx_" << tangent_input <<
" : " << alloc_vreg() <<
",\n";
818 text <<
"\t in float4 vtx_" << binormal_input <<
" : " << alloc_vreg() <<
",\n";
821 if (tex._flags & ShaderKey::TF_map_glow) {
824 if (tex._flags & ShaderKey::TF_map_gloss) {
828 if (key._texture_flags & ShaderKey::TF_map_normal) {
829 tangent_freg = alloc_freg();
830 binormal_freg = alloc_freg();
831 text <<
"\t out float4 l_tangent : " << tangent_freg <<
",\n";
832 text <<
"\t out float4 l_binormal : " << binormal_freg <<
",\n";
834 if (need_color && key._color_type == ColorAttrib::T_vertex) {
835 text <<
"\t in float4 vtx_color : " << color_vreg <<
",\n";
836 text <<
"\t out float4 l_color : COLOR0,\n";
838 if (need_world_position || need_world_normal) {
839 text <<
"\t uniform float4x4 trans_model_to_world,\n";
841 if (need_world_position) {
842 world_position_freg = alloc_freg();
843 text <<
"\t out float4 l_world_position : " << world_position_freg <<
",\n";
845 if (need_world_normal) {
846 world_normal_freg = alloc_freg();
847 text <<
"\t out float4 l_world_normal : " << world_normal_freg <<
",\n";
849 if (need_eye_position) {
850 text <<
"\t uniform float4x4 trans_model_to_view,\n";
851 eye_position_freg = alloc_freg();
852 text <<
"\t out float4 l_eye_position : " << eye_position_freg <<
",\n";
853 }
else if (key._texture_flags & ShaderKey::TF_map_normal) {
854 text <<
"\t uniform float4x4 trans_model_to_view,\n";
856 if (need_eye_normal) {
857 eye_normal_freg = alloc_freg();
858 text <<
"\t uniform float4x4 tpose_view_to_model,\n";
859 text <<
"\t out float3 l_eye_normal : " << eye_normal_freg <<
",\n";
861 if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
862 text <<
"\t in float3 vtx_normal : " << normal_vreg <<
",\n";
864 if (key._texture_flags & ShaderKey::TF_map_height) {
865 text <<
"\t uniform float4 mspos_view,\n";
866 text <<
"\t out float3 l_eyevec,\n";
868 for (
size_t i = 0; i < key._lights.size(); ++i) {
869 const ShaderKey::LightInfo &light = key._lights[i];
870 if (light._flags & ShaderKey::LF_has_shadows) {
871 lightcoord_fregs.push_back(alloc_freg());
872 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
873 text <<
"\t out float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
875 lightcoord_fregs.push_back(
nullptr);
878 if (key._fog_mode != 0) {
879 hpos_freg = alloc_freg();
880 text <<
"\t out float4 l_hpos : " << hpos_freg <<
",\n";
882 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
883 key._anim_spec.get_num_transforms() > 0) {
885 if (key._anim_spec.get_indexed_transforms()) {
886 num_transforms = 120;
888 num_transforms = key._anim_spec.get_num_transforms();
890 if (transform_weight_vreg ==
nullptr) {
891 transform_weight_vreg = alloc_vreg();
893 if (transform_index_vreg ==
nullptr) {
894 transform_index_vreg = alloc_vreg();
896 text <<
"\t uniform float4x4 tbl_transforms[" << num_transforms <<
"],\n";
897 text <<
"\t in float4 vtx_transform_weight : " << transform_weight_vreg <<
",\n";
898 if (key._anim_spec.get_indexed_transforms()) {
899 text <<
"\t in uint4 vtx_transform_index : " << transform_index_vreg <<
",\n";
902 text <<
"\t in float4 vtx_position : " << position_vreg <<
",\n";
903 text <<
"\t out float4 l_position : POSITION,\n";
904 text <<
"\t uniform float4x4 mat_modelproj\n";
907 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
908 key._anim_spec.get_num_transforms() > 0) {
910 if (!key._anim_spec.get_indexed_transforms()) {
911 text <<
"\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
914 text <<
"\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
915 if (key._anim_spec.get_num_transforms() > 1) {
916 text <<
"\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
918 if (key._anim_spec.get_num_transforms() > 2) {
919 text <<
"\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
921 if (key._anim_spec.get_num_transforms() > 3) {
922 text <<
"\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
926 text <<
"\t vtx_position = mul(matrix, vtx_position);\n";
927 if (need_world_normal || need_eye_normal) {
928 text <<
"\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
932 text <<
"\t l_position = mul(mat_modelproj, vtx_position);\n";
933 if (key._fog_mode != 0) {
934 text <<
"\t l_hpos = l_position;\n";
936 if (need_world_position) {
937 text <<
"\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
939 if (need_world_normal) {
940 text <<
"\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
942 if (need_eye_position) {
943 text <<
"\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
945 if (need_eye_normal) {
946 text <<
"\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
949 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
951 string tcname = it->first->join(
"_");
952 text <<
"\t l_" << tcname <<
" = vtx_" << tcname <<
";\n";
954 if (need_color && key._color_type == ColorAttrib::T_vertex) {
955 text <<
"\t l_color = vtx_color;\n";
957 if (key._texture_flags & ShaderKey::TF_map_normal) {
958 text <<
"\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input <<
".xyz));\n";
959 text <<
"\t l_tangent.w = 0;\n";
960 text <<
"\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input <<
".xyz));\n";
961 text <<
"\t l_binormal.w = 0;\n";
963 for (
size_t i = 0; i < key._lights.size(); ++i) {
964 if (key._lights[i]._flags & ShaderKey::LF_has_shadows) {
965 text <<
"\t l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", l_eye_position);\n";
968 if (key._texture_flags & ShaderKey::TF_map_height) {
969 text <<
"\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
970 text <<
"\t l_eyevec.x = dot(vtx_" << tangent_input <<
".xyz, eyedir);\n";
971 text <<
"\t l_eyevec.y = dot(vtx_" << binormal_input <<
".xyz, eyedir);\n";
972 text <<
"\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
973 text <<
"\t l_eyevec = normalize(l_eyevec);\n";
979 text <<
"void fshader(\n";
980 if (key._fog_mode != 0) {
981 text <<
"\t in float4 l_hpos : " << hpos_freg <<
",\n";
982 text <<
"\t in uniform float4 attr_fog,\n";
983 text <<
"\t in uniform float4 attr_fogcolor,\n";
985 if (need_world_position) {
986 text <<
"\t in float4 l_world_position : " << world_position_freg <<
",\n";
988 if (need_world_normal) {
989 text <<
"\t in float4 l_world_normal : " << world_normal_freg <<
",\n";
991 if (need_eye_position) {
992 text <<
"\t in float4 l_eye_position : " << eye_position_freg <<
",\n";
994 if (need_eye_normal) {
995 text <<
"\t in float3 l_eye_normal : " << eye_normal_freg <<
",\n";
997 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
998 text <<
"\t in float4 l_" << it->first->join(
"_") <<
" : " << it->second <<
",\n";
1000 for (
size_t i = 0; i < key._textures.size(); ++i) {
1001 const ShaderKey::TextureInfo &tex = key._textures[i];
1002 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1007 text <<
"\t uniform sampler" << texture_type_as_string(tex._type) <<
" tex_" << i <<
",\n";
1009 if (tex._flags & ShaderKey::TF_has_texscale) {
1010 text <<
"\t uniform float3 texscale_" << i <<
",\n";
1011 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1012 text <<
"\t uniform float4x4 texmat_" << i <<
",\n";
1015 if (tex._flags & ShaderKey::TF_uses_color) {
1016 text <<
"\t uniform float4 texcolor_" << i <<
",\n";
1019 if (key._texture_flags & ShaderKey::TF_map_normal) {
1020 text <<
"\t in float3 l_tangent : " << tangent_freg <<
",\n";
1021 text <<
"\t in float3 l_binormal : " << binormal_freg <<
",\n";
1023 for (
size_t i = 0; i < key._lights.size(); ++i) {
1024 text <<
"\t uniform float4x4 attr_light" << i <<
",\n";
1026 const ShaderKey::LightInfo &light = key._lights[i];
1027 if (light._flags & ShaderKey::LF_has_shadows) {
1028 if (light._type.is_derived_from(PointLight::get_class_type())) {
1029 text <<
"\t uniform samplerCUBE shadow_" << i <<
",\n";
1030 }
else if (_use_shadow_filter) {
1031 text <<
"\t uniform sampler2DShadow shadow_" << i <<
",\n";
1033 text <<
"\t uniform sampler2D shadow_" << i <<
",\n";
1035 text <<
"\t in float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
1037 if (light._flags & ShaderKey::LF_has_specular_color) {
1038 text <<
"\t uniform float4 attr_lspec" << i <<
",\n";
1043 if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) {
1044 text <<
"\t uniform float4x4 attr_material,\n";
1046 if (key._texture_flags & ShaderKey::TF_map_height) {
1047 text <<
"\t float3 l_eyevec,\n";
1049 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1050 text <<
"\t out float4 o_aux : COLOR1,\n";
1052 text <<
"\t out float4 o_color : COLOR0,\n";
1055 if (key._color_type == ColorAttrib::T_vertex) {
1056 text <<
"\t in float4 l_color : COLOR0,\n";
1057 }
else if (key._color_type == ColorAttrib::T_flat) {
1058 text <<
"\t uniform float4 attr_color,\n";
1062 for (
int i = 0; i < key._num_clip_planes; ++i) {
1063 text <<
"\t uniform float4 clipplane_" << i <<
",\n";
1066 text <<
"\t uniform float4 attr_ambient,\n";
1067 text <<
"\t uniform float4 attr_colorscale\n";
1071 for (
int i = 0; i < key._num_clip_planes; ++i) {
1072 text <<
"\t if (l_world_position.x * clipplane_" << i <<
".x + l_world_position.y ";
1073 text <<
"* clipplane_" << i <<
".y + l_world_position.z * clipplane_" << i <<
".z + clipplane_" << i <<
".w <= 0) {\n";
1074 text <<
"\t discard;\n";
1077 text <<
"\t float4 result;\n";
1078 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1079 text <<
"\t o_aux = float4(0, 0, 0, 0);\n";
1083 for (
size_t i = 0; i < key._textures.size(); ++i) {
1084 const ShaderKey::TextureInfo &tex = key._textures[i];
1085 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1089 switch (tex._gen_mode) {
1090 case TexGenAttrib::M_off:
1092 text <<
"\t float4 texcoord" << i <<
" = l_" << tex._texcoord_name->join(
"_") <<
";\n";
1094 case TexGenAttrib::M_world_position:
1095 text <<
"\t float4 texcoord" << i <<
" = l_world_position;\n";
1097 case TexGenAttrib::M_world_normal:
1098 text <<
"\t float4 texcoord" << i <<
" = l_world_normal;\n";
1100 case TexGenAttrib::M_eye_position:
1101 text <<
"\t float4 texcoord" << i <<
" = l_eye_position;\n";
1103 case TexGenAttrib::M_eye_normal:
1104 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_normal, 1.0f);\n";
1107 text <<
"\t float4 texcoord" << i <<
" = float4(0, 0, 0, 0);\n";
1108 pgraphnodes_cat.error()
1109 <<
"Unsupported TexGenAttrib mode: " << tex._gen_mode <<
"\n";
1111 if (tex._flags & ShaderKey::TF_has_texscale) {
1112 text <<
"\t texcoord" << i <<
".xyz *= texscale_" << i <<
";\n";
1113 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1114 text <<
"\t texcoord" << i <<
" = mul(texmat_" << i <<
", texcoord" << i <<
");\n";
1115 text <<
"\t texcoord" << i <<
".xyz /= texcoord" << i <<
".w;\n";
1118 text <<
"\t // Fetch all textures.\n";
1119 for (
size_t i = 0; i < key._textures.size(); ++i) {
1120 const ShaderKey::TextureInfo &tex = key._textures[i];
1121 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1125 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1126 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1127 switch (tex._type) {
1128 case Texture::TT_cube_map:
1129 case Texture::TT_3d_texture:
1130 case Texture::TT_2d_texture_array:
1133 case Texture::TT_2d_texture:
1136 case Texture::TT_1d_texture:
1142 text <<
");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i;
1143 if (tex._mode == TextureStage::M_normal_height ||
1144 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1149 text <<
" * 2.0 - 1.0) * " << parallax_mapping_scale <<
";\n";
1151 for (
int j = 0; j < parallax_mapping_samples - 1; ++j) {
1152 text <<
"\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << i;
1153 if (tex._mode == TextureStage::M_normal_height ||
1154 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1159 text <<
" * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale <<
";\n";
1162 for (
size_t i = 0; i < key._textures.size(); ++i) {
1163 ShaderKey::TextureInfo &tex = key._textures[i];
1164 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1168 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1171 if (key._texture_flags & ShaderKey::TF_map_height) {
1172 text <<
"\t texcoord" << i <<
".xyz -= parallax_offset;\n";
1174 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1175 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1176 switch (tex._type) {
1177 case Texture::TT_cube_map:
1178 case Texture::TT_3d_texture:
1179 case Texture::TT_2d_texture_array:
1182 case Texture::TT_2d_texture:
1185 case Texture::TT_1d_texture:
1194 if (need_eye_normal) {
1195 text <<
"\t // Correct the surface normal for interpolation effects\n";
1196 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1198 if (key._texture_flags & ShaderKey::TF_map_normal) {
1199 text <<
"\t // Translate tangent-space normal in map to view-space.\n";
1202 bool is_first =
true;
1203 for (
size_t i = 0; i < key._textures.size(); ++i) {
1204 const ShaderKey::TextureInfo &tex = key._textures[i];
1205 if (tex._flags & ShaderKey::TF_map_normal) {
1207 text <<
"\t float3 tsnormal = normalize((tex" << i <<
".xyz * 2) - 1);\n";
1211 text <<
"\t tsnormal.z += 1;\n";
1212 text <<
"\t float3 tmp" << i <<
" = tex" << i <<
".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1213 text <<
"\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i <<
") - tmp" << i <<
" * tsnormal.z);\n";
1216 text <<
"\t l_eye_normal *= tsnormal.z;\n";
1217 text <<
"\t l_eye_normal += normalize(l_tangent) * tsnormal.x;\n";
1218 text <<
"\t l_eye_normal += normalize(l_binormal) * tsnormal.y;\n";
1219 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1221 if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1222 text <<
"\t // Output the camera-space surface normal\n";
1223 text <<
"\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1225 if (key._lighting) {
1226 text <<
"\t // Begin view-space light calculations\n";
1227 text <<
"\t float ldist,lattenv,langle,lshad;\n";
1228 text <<
"\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1229 text <<
"\t float3 lvec,lhalf;\n";
1230 if (key._have_separate_ambient) {
1231 text <<
"\t float4 tot_ambient = float4(0,0,0,0);\n";
1233 text <<
"\t float4 tot_diffuse = float4(0,0,0,0);\n";
1234 if (have_specular) {
1235 text <<
"\t float4 tot_specular = float4(0,0,0,0);\n";
1236 if (key._material_flags & Material::F_specular) {
1237 text <<
"\t float shininess = attr_material[3].w;\n";
1239 text <<
"\t float shininess = 50; // no shininess specified, using default\n";
1242 if (key._have_separate_ambient) {
1243 text <<
"\t tot_ambient += attr_ambient;\n";
1245 text <<
"\t tot_diffuse += attr_ambient;\n";
1248 for (
size_t i = 0; i < key._lights.size(); ++i) {
1249 const ShaderKey::LightInfo &light = key._lights[i];
1250 if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1251 text <<
"\t // Directional Light " << i <<
"\n";
1252 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1253 if (light._flags & ShaderKey::LF_has_specular_color) {
1254 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1256 text <<
"\t lspec = lcolor;\n";
1258 text <<
"\t lvec = attr_light" << i <<
"[3].xyz;\n";
1259 text <<
"\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1260 if (light._flags & ShaderKey::LF_has_shadows) {
1261 if (_use_shadow_filter) {
1262 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1264 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1266 text <<
"\t lcolor *= lshad;\n";
1267 text <<
"\t lspec *= lshad;\n";
1269 text <<
"\t tot_diffuse += lcolor;\n";
1270 if (have_specular) {
1271 if (key._material_flags & Material::F_local) {
1272 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1274 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1276 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1277 text <<
"\t tot_specular += lspec;\n";
1279 }
else if (light._type.is_derived_from(PointLight::get_class_type())) {
1280 text <<
"\t // Point Light " << i <<
"\n";
1281 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1282 if (light._flags & ShaderKey::LF_has_specular_color) {
1283 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1285 text <<
"\t lspec = lcolor;\n";
1287 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1288 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1289 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1290 text <<
"\t ldist = length(lvec);\n";
1291 text <<
"\t lvec /= ldist;\n";
1292 if (light._type.is_derived_from(SphereLight::get_class_type())) {
1293 text <<
"\t ldist = max(ldist, attr_light" << i <<
"[2].w);\n";
1295 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1296 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1297 if (light._flags & ShaderKey::LF_has_shadows) {
1298 text <<
"\t ldist = max(abs(l_lightcoord" << i <<
".x), max(abs(l_lightcoord" << i <<
".y), abs(l_lightcoord" << i <<
".z)));\n";
1299 text <<
"\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1300 text <<
"\t lshad = texCUBE(shadow_" << i <<
", l_lightcoord" << i <<
".xyz).r >= ldist * 0.5 + 0.5;\n";
1301 text <<
"\t lcolor *= lshad;\n";
1302 text <<
"\t lspec *= lshad;\n";
1304 text <<
"\t tot_diffuse += lcolor;\n";
1305 if (have_specular) {
1306 if (key._material_flags & Material::F_local) {
1307 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1309 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1311 text <<
"\t lspec *= lattenv;\n";
1312 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1313 text <<
"\t tot_specular += lspec;\n";
1315 }
else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1316 text <<
"\t // Spot Light " << i <<
"\n";
1317 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1318 if (light._flags & ShaderKey::LF_has_specular_color) {
1319 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1321 text <<
"\t lspec = lcolor;\n";
1323 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1324 text <<
"\t ldir = attr_light" << i <<
"[2];\n";
1325 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1326 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1327 text <<
"\t ldist = length(lvec);\n";
1328 text <<
"\t lvec /= ldist;\n";
1329 text <<
"\t langle = saturate(dot(ldir.xyz, lvec));\n";
1330 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1331 text <<
"\t lattenv *= pow(langle, latten.w);\n";
1332 text <<
"\t if (langle < ldir.w) lattenv = 0;\n";
1333 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1334 if (light._flags & ShaderKey::LF_has_shadows) {
1335 if (_use_shadow_filter) {
1336 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1338 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1340 text <<
"\t lcolor *= lshad;\n";
1341 text <<
"\t lspec *= lshad;\n";
1344 text <<
"\t tot_diffuse += lcolor;\n";
1345 if (have_specular) {
1346 if (key._material_flags & Material::F_local) {
1347 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1349 text <<
"\t lhalf = normalize(lvec - float3(0,1,0));\n";
1351 text <<
"\t lspec *= lattenv;\n";
1352 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1353 text <<
"\t tot_specular += lspec;\n";
1357 if (key._lighting) {
1358 if (key._light_ramp !=
nullptr) {
1359 switch (key._light_ramp->get_mode()) {
1360 case LightRampAttrib::LRT_single_threshold:
1362 PN_stdfloat t = key._light_ramp->get_threshold(0);
1363 PN_stdfloat l0 = key._light_ramp->get_level(0);
1364 text <<
"\t // Single-threshold light ramp\n";
1365 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1366 text <<
"\t float lr_scale = (lr_in < " << t <<
") ? 0.0 : (" << l0 <<
"/lr_in);\n";
1367 text <<
"\t tot_diffuse = tot_diffuse * lr_scale;\n";
1370 case LightRampAttrib::LRT_double_threshold:
1372 PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1373 PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1374 PN_stdfloat l0 = key._light_ramp->get_level(0);
1375 PN_stdfloat l1 = key._light_ramp->get_level(1);
1376 text <<
"\t // Double-threshold light ramp\n";
1377 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1378 text <<
"\t float lr_out = 0.0;\n";
1379 text <<
"\t if (lr_in > " << t0 <<
") lr_out=" << l0 <<
";\n";
1380 text <<
"\t if (lr_in > " << t1 <<
") lr_out=" << l1 <<
";\n";
1381 text <<
"\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1388 text <<
"\t // Begin view-space light summation\n";
1389 if (key._material_flags & Material::F_emission) {
1390 if (key._texture_flags & ShaderKey::TF_map_glow) {
1391 text <<
"\t result = attr_material[2] * saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1393 text <<
"\t result = attr_material[2];\n";
1396 if (key._texture_flags & ShaderKey::TF_map_glow) {
1397 text <<
"\t result = saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1399 text <<
"\t result = float4(0,0,0,0);\n";
1402 if (key._have_separate_ambient) {
1403 if (key._material_flags & Material::F_ambient) {
1404 text <<
"\t result += tot_ambient * attr_material[0];\n";
1405 }
else if (key._color_type == ColorAttrib::T_vertex) {
1406 text <<
"\t result += tot_ambient * l_color;\n";
1407 }
else if (key._color_type == ColorAttrib::T_flat) {
1408 text <<
"\t result += tot_ambient * attr_color;\n";
1410 text <<
"\t result += tot_ambient;\n";
1413 if (key._material_flags & Material::F_diffuse) {
1414 text <<
"\t result += tot_diffuse * attr_material[1];\n";
1415 }
else if (key._color_type == ColorAttrib::T_vertex) {
1416 text <<
"\t result += tot_diffuse * l_color;\n";
1417 }
else if (key._color_type == ColorAttrib::T_flat) {
1418 text <<
"\t result += tot_diffuse * attr_color;\n";
1420 text <<
"\t result += tot_diffuse;\n";
1422 if (key._light_ramp ==
nullptr ||
1423 key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1424 text <<
"\t result = saturate(result);\n";
1426 text <<
"\t // End view-space light calculations\n";
1430 if (key._calc_primary_alpha) {
1431 if (key._color_type == ColorAttrib::T_vertex) {
1432 text <<
"\t result.a = l_color.a;\n";
1433 }
else if (key._color_type == ColorAttrib::T_flat) {
1434 text <<
"\t result.a = attr_color.a;\n";
1436 text <<
"\t result.a = 1;\n";
1440 if (key._color_type == ColorAttrib::T_vertex) {
1441 text <<
"\t result = l_color;\n";
1442 }
else if (key._color_type == ColorAttrib::T_flat) {
1443 text <<
"\t result = attr_color;\n";
1445 text <<
"\t result = float4(1, 1, 1, 1);\n";
1450 text <<
"\t result *= attr_colorscale;\n";
1453 if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1454 text <<
"\t float4 primary_color = result;\n";
1456 if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1457 text <<
"\t float4 last_saved_result = result;\n";
1461 for (
size_t i = 0; i < key._textures.size(); ++i) {
1462 const ShaderKey::TextureInfo &tex = key._textures[i];
1463 TextureStage::CombineMode combine_rgb, combine_alpha;
1465 switch (tex._mode) {
1466 case TextureStage::M_modulate:
1467 if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1468 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1469 text <<
"\t result.rgba *= tex" << i <<
".rgba;\n";
1470 }
else if (tex._flags & ShaderKey::TF_has_alpha) {
1471 text <<
"\t result.a *= tex" << i <<
".a;\n";
1472 }
else if (tex._flags & ShaderKey::TF_has_rgb) {
1473 text <<
"\t result.rgb *= tex" << i <<
".rgb;\n";
1476 case TextureStage::M_modulate_glow:
1477 case TextureStage::M_modulate_gloss:
1483 text <<
"\t result.rgb *= tex" << i <<
";\n";
1485 case TextureStage::M_decal:
1486 text <<
"\t result.rgb = lerp(result, tex" << i <<
", tex" << i <<
".a).rgb;\n";
1488 case TextureStage::M_blend:
1489 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb, tex" << i <<
".rgb);\n";
1490 if (key._calc_primary_alpha) {
1491 text <<
"\t result.a *= tex" << i <<
".a;\n";
1494 case TextureStage::M_replace:
1495 text <<
"\t result = tex" << i <<
";\n";
1497 case TextureStage::M_add:
1498 text <<
"\t result.rgb += tex" << i <<
".rgb;\n";
1499 if (key._calc_primary_alpha) {
1500 text <<
"\t result.a *= tex" << i <<
".a;\n";
1503 case TextureStage::M_combine:
1504 combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1505 combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1506 if (combine_rgb == TextureStage::CM_dot3_rgba) {
1507 text <<
"\t result = ";
1508 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1511 text <<
"\t result.rgb = ";
1512 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1513 text <<
";\n\t result.a = ";
1514 text << combine_mode_as_string(tex, combine_alpha,
true, i);
1517 if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1518 text <<
"\t result.rgb *= 2;\n";
1520 if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1521 text <<
"\t result.rgb *= 4;\n";
1523 if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1524 text <<
"\t result.a *= 2;\n";
1526 if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1527 text <<
"\t result.a *= 4;\n";
1530 case TextureStage::M_blend_color_scale:
1531 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb * attr_colorscale.rgb, tex" << i <<
".rgb);\n";
1532 if (key._calc_primary_alpha) {
1533 text <<
"\t result.a *= texcolor_" << i <<
".a * attr_colorscale.a;\n";
1539 if (tex._flags & ShaderKey::TF_saved_result) {
1540 text <<
"\t last_saved_result = result;\n";
1544 if (key._alpha_test_mode != RenderAttrib::M_none) {
1545 text <<
"\t // Shader includes alpha test:\n";
1546 double ref = key._alpha_test_ref;
1547 switch (key._alpha_test_mode) {
1548 case RenderAttrib::M_never:
1549 text <<
"\t discard;\n";
1551 case RenderAttrib::M_less:
1552 text <<
"\t if (result.a >= " <<
ref <<
") discard;\n";
1554 case RenderAttrib::M_equal:
1555 text <<
"\t if (result.a != " <<
ref <<
") discard;\n";
1557 case RenderAttrib::M_less_equal:
1558 text <<
"\t if (result.a > " <<
ref <<
") discard;\n";
1560 case RenderAttrib::M_greater:
1561 text <<
"\t if (result.a <= " <<
ref <<
") discard;\n";
1563 case RenderAttrib::M_not_equal:
1564 text <<
"\t if (result.a == " <<
ref <<
") discard;\n";
1566 case RenderAttrib::M_greater_equal:
1567 text <<
"\t if (result.a < " <<
ref <<
") discard;\n";
1569 case RenderAttrib::M_none:
1570 case RenderAttrib::M_always:
1575 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1576 if (key._texture_flags & ShaderKey::TF_map_glow) {
1577 text <<
"\t result.a = tex" << map_index_glow <<
".a;\n";
1579 text <<
"\t result.a = 0.5;\n";
1582 if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1583 if (key._texture_flags & ShaderKey::TF_map_glow) {
1584 text <<
"\t o_aux.a = tex" << map_index_glow <<
".a;\n";
1586 text <<
"\t o_aux.a = 0.5;\n";
1590 if (have_specular) {
1591 if (key._material_flags & Material::F_specular) {
1592 text <<
"\t tot_specular *= attr_material[3];\n";
1594 if (key._texture_flags & ShaderKey::TF_map_gloss) {
1595 text <<
"\t tot_specular *= tex" << map_index_gloss <<
".a;\n";
1597 text <<
"\t result.rgb = result.rgb + tot_specular.rgb;\n";
1599 if (key._light_ramp !=
nullptr) {
1600 switch (key._light_ramp->get_mode()) {
1601 case LightRampAttrib::LRT_hdr0:
1602 text <<
"\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1604 case LightRampAttrib::LRT_hdr1:
1605 text <<
"\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1607 case LightRampAttrib::LRT_hdr2:
1608 text <<
"\t result.rgb = result / (result + 1);\n";
1615 if (key._fog_mode != 0) {
1616 Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1619 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1621 case Fog::M_exponential:
1622 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1624 case Fog::M_exponential_squared:
1625 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * attr_fog.x * l_hpos.z * l_hpos.z * -1.442695f)));\n";
1632 text <<
"\t o_color = result * 1.000001;\n";
1633 if (key._alpha_test_mode != RenderAttrib::M_none) {
1634 text <<
"\t // Shader subsumes normal alpha test.\n";
1636 if (key._disable_alpha_write) {
1637 text <<
"\t // Shader disables alpha write.\n";
1642 PT(
Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1643 nassertr(shader !=
nullptr,
nullptr);
1646 if (key._alpha_test_mode != RenderAttrib::M_none) {
1647 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test,
true);
1649 if (key._disable_alpha_write) {
1650 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write,
true);
1653 reset_register_allocator();
1656 _generated_shaders[key] = attr;
1663 string ShaderGenerator::
1664 combine_mode_as_string(
const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode,
bool alpha,
short texindex) {
1665 std::ostringstream text;
1667 case TextureStage::CM_modulate:
1668 text << combine_source_as_string(info, 0, alpha, texindex);
1670 text << combine_source_as_string(info, 1, alpha, texindex);
1672 case TextureStage::CM_add:
1673 text << combine_source_as_string(info, 0, alpha, texindex);
1675 text << combine_source_as_string(info, 1, alpha, texindex);
1677 case TextureStage::CM_add_signed:
1678 text << combine_source_as_string(info, 0, alpha, texindex);
1680 text << combine_source_as_string(info, 1, alpha, texindex);
1684 text <<
" - float3(0.5, 0.5, 0.5)";
1687 case TextureStage::CM_interpolate:
1689 text << combine_source_as_string(info, 1, alpha, texindex);
1691 text << combine_source_as_string(info, 0, alpha, texindex);
1693 text << combine_source_as_string(info, 2, alpha, texindex);
1696 case TextureStage::CM_subtract:
1697 text << combine_source_as_string(info, 0, alpha, texindex);
1699 text << combine_source_as_string(info, 1, alpha, texindex);
1701 case TextureStage::CM_dot3_rgb:
1702 case TextureStage::CM_dot3_rgba:
1704 text << combine_source_as_string(info, 0, alpha, texindex);
1705 text <<
" - float3(0.5), ";
1706 text << combine_source_as_string(info, 1, alpha, texindex);
1707 text <<
" - float3(0.5))";
1709 case TextureStage::CM_replace:
1711 text << combine_source_as_string(info, 0, alpha, texindex);
1720 string ShaderGenerator::
1721 combine_source_as_string(
const ShaderKey::TextureInfo &info,
short num,
bool alpha,
short texindex) {
1722 TextureStage::CombineSource c_src;
1723 TextureStage::CombineOperand c_op;
1725 c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1726 c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1728 c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1729 c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1731 std::ostringstream csource;
1732 if (c_op == TextureStage::CO_one_minus_src_color ||
1733 c_op == TextureStage::CO_one_minus_src_alpha) {
1734 csource <<
"saturate(1.0f - ";
1737 case TextureStage::CS_undefined:
1738 case TextureStage::CS_texture:
1739 csource <<
"tex" << texindex;
1741 case TextureStage::CS_constant:
1742 csource <<
"texcolor_" << texindex;
1744 case TextureStage::CS_primary_color:
1745 csource <<
"primary_color";
1747 case TextureStage::CS_previous:
1748 csource <<
"result";
1750 case TextureStage::CS_constant_color_scale:
1751 csource <<
"attr_colorscale";
1753 case TextureStage::CS_last_saved_result:
1754 csource <<
"last_saved_result";
1757 if (c_op == TextureStage::CO_one_minus_src_color ||
1758 c_op == TextureStage::CO_one_minus_src_alpha) {
1761 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1767 return "float3(" + csource.str() +
")";
1770 return csource.str();
1776 const char *ShaderGenerator::
1777 texture_type_as_string(Texture::TextureType ttype) {
1779 case Texture::TT_1d_texture:
1782 case Texture::TT_2d_texture:
1785 case Texture::TT_3d_texture:
1788 case Texture::TT_cube_map:
1791 case Texture::TT_2d_texture_array:
1795 pgraphnodes_cat.error() <<
"Unsupported texture type!\n";
1803 ShaderGenerator::ShaderKey::
1809 _have_separate_ambient(false),
1812 _calc_primary_alpha(false),
1813 _disable_alpha_write(false),
1815 _alpha_test_ref(0.0),
1816 _num_clip_planes(0),
1817 _light_ramp(nullptr) {
1824 bool ShaderGenerator::ShaderKey::
1825 operator < (
const ShaderKey &other)
const {
1826 if (_anim_spec != other._anim_spec) {
1827 return _anim_spec < other._anim_spec;
1829 if (_color_type != other._color_type) {
1830 return _color_type < other._color_type;
1832 if (_material_flags != other._material_flags) {
1833 return _material_flags < other._material_flags;
1835 if (_texture_flags != other._texture_flags) {
1836 return _texture_flags < other._texture_flags;
1838 if (_textures.size() != other._textures.size()) {
1839 return _textures.size() < other._textures.size();
1841 for (
size_t i = 0; i < _textures.size(); ++i) {
1842 const ShaderKey::TextureInfo &tex = _textures[i];
1843 const ShaderKey::TextureInfo &other_tex = other._textures[i];
1844 if (tex._texcoord_name != other_tex._texcoord_name) {
1845 return tex._texcoord_name < other_tex._texcoord_name;
1847 if (tex._type != other_tex._type) {
1848 return tex._type < other_tex._type;
1850 if (tex._mode != other_tex._mode) {
1851 return tex._mode < other_tex._mode;
1853 if (tex._gen_mode != other_tex._gen_mode) {
1854 return tex._gen_mode < other_tex._gen_mode;
1856 if (tex._flags != other_tex._flags) {
1857 return tex._flags < other_tex._flags;
1859 if (tex._combine_rgb != other_tex._combine_rgb) {
1860 return tex._combine_rgb < other_tex._combine_rgb;
1862 if (tex._combine_alpha != other_tex._combine_alpha) {
1863 return tex._combine_alpha < other_tex._combine_alpha;
1866 if (_lights.size() != other._lights.size()) {
1867 return _lights.size() < other._lights.size();
1869 for (
size_t i = 0; i < _lights.size(); ++i) {
1870 const ShaderKey::LightInfo &light = _lights[i];
1871 const ShaderKey::LightInfo &other_light = other._lights[i];
1872 if (light._type != other_light._type) {
1873 return light._type < other_light._type;
1875 if (light._flags != other_light._flags) {
1876 return light._flags < other_light._flags;
1879 if (_lighting != other._lighting) {
1880 return _lighting < other._lighting;
1882 if (_have_separate_ambient != other._have_separate_ambient) {
1883 return _have_separate_ambient < other._have_separate_ambient;
1885 if (_fog_mode != other._fog_mode) {
1886 return _fog_mode < other._fog_mode;
1888 if (_outputs != other._outputs) {
1889 return _outputs < other._outputs;
1891 if (_calc_primary_alpha != other._calc_primary_alpha) {
1892 return _calc_primary_alpha < other._calc_primary_alpha;
1894 if (_disable_alpha_write != other._disable_alpha_write) {
1895 return _disable_alpha_write < other._disable_alpha_write;
1897 if (_alpha_test_mode != other._alpha_test_mode) {
1898 return _alpha_test_mode < other._alpha_test_mode;
1900 if (_alpha_test_ref != other._alpha_test_ref) {
1901 return _alpha_test_ref < other._alpha_test_ref;
1903 if (_num_clip_planes != other._num_clip_planes) {
1904 return _num_clip_planes < other._num_clip_planes;
1906 return _light_ramp < other._light_ramp;
1912 bool ShaderGenerator::ShaderKey::
1913 operator == (
const ShaderKey &other)
const {
1914 if (_anim_spec != other._anim_spec) {
1917 if (_color_type != other._color_type) {
1920 if (_material_flags != other._material_flags) {
1923 if (_texture_flags != other._texture_flags) {
1926 if (_textures.size() != other._textures.size()) {
1929 for (
size_t i = 0; i < _textures.size(); ++i) {
1930 const ShaderKey::TextureInfo &tex = _textures[i];
1931 const ShaderKey::TextureInfo &other_tex = other._textures[i];
1932 if (tex._texcoord_name != other_tex._texcoord_name ||
1933 tex._type != other_tex._type ||
1934 tex._mode != other_tex._mode ||
1935 tex._gen_mode != other_tex._gen_mode ||
1936 tex._flags != other_tex._flags ||
1937 tex._combine_rgb != other_tex._combine_rgb ||
1938 tex._combine_alpha != other_tex._combine_alpha) {
1942 if (_lights.size() != other._lights.size()) {
1945 for (
size_t i = 0; i < _lights.size(); ++i) {
1946 const ShaderKey::LightInfo &light = _lights[i];
1947 const ShaderKey::LightInfo &other_light = other._lights[i];
1948 if (light._type != other_light._type ||
1949 light._flags != other_light._flags) {
1953 return _lighting == other._lighting
1954 && _have_separate_ambient == other._have_separate_ambient
1955 && _fog_mode == other._fog_mode
1956 && _outputs == other._outputs
1957 && _calc_primary_alpha == other._calc_primary_alpha
1958 && _disable_alpha_write == other._disable_alpha_write
1959 && _alpha_test_mode == other._alpha_test_mode
1960 && _alpha_test_ref == other._alpha_test_ref
1961 && _num_clip_planes == other._num_clip_planes
1962 && _light_ramp == other._light_ramp;
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
is_shadow_caster
Returns whether this light is configured to cast shadows or not.
A basic node of the scene graph or data graph.
This is our own Panda specialization on the default STL map.
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
get_mode
Returns the transparency mode.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
bool has_specular_color() const
Returns true if this light defines a specular color, false if the specular color is derived automatic...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_reference_alpha
Returns the alpha reference value.
bool is_empty() const
Returns true if the NodePath contains no nodes.
Indicates which, if any, material should be applied to geometry.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded...
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
This controls the enabling of transparency.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This functions similarly to a LightAttrib.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A Light Ramp is any unary operator that takes a rendered pixel as input, and adjusts the brightness o...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear()
Completely empties the table.
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
get_rgb_scale
See set_rgb_scale().
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Applies a Fog to the geometry at and below this node.
Modern frame buffers can have 'aux' bitplanes, which are additional bitplanes above and beyond the st...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
size_t get_num_entries() const
Returns the number of active entries in the table.
A lightweight class that represents a single element that may be timed and/or counted via stats...
get_mode
Returns the blending mode for the RGB channels.
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool uses_last_saved_result() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
bool uses_primary_color() const
Returns true if the TextureStage makes use of the CS_primary_color combine source.
void mark_used_by_auto_shader() const
Marks this light as having been used by the auto shader.
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
get_saved_result
Returns the current setting of the saved_result flag.
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
get_alpha_scale
See set_alpha_scale().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines the way an object appears in the presence of lighting.
Similar to MutexHolder, but for a light reentrant mutex.
Encodes a string name in a hash table, mapping it to a pointer.
void ref() const
Explicitly increments the reference count.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Applies a transform matrix to UV's before they are rendered.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This specifies how colors are blended into the frame buffer, for special effects. ...
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
PandaNode * node() const
Returns the referenced node of the path.
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
A derivative of Light and of Camera.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Indicates what color should be applied to renderable geometry.
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(), false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog...
get_mode
Returns the alpha write mode.
Defines the properties of a named stage of the multitexture pipeline.
Computes texture coordinates for geometry automatically based on vertex position and/or normal...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_texcoord_name
See set_texcoord_name.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated...