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);
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;
579 void ShaderGenerator::
580 rehash_generated_shaders() {
586 for (
size_t si = 0; si < size; ++si) {
589 if (state->_generated_shader !=
nullptr) {
591 analyze_renderstate(key, state);
593 GeneratedShaders::const_iterator si;
594 si = _generated_shaders.find(key);
595 if (si != _generated_shaders.end()) {
596 if (si->second != state->_generated_shader) {
597 state->_generated_shader = si->second;
598 state->_munged_states.
clear();
602 state->_generated_shader.clear();
603 state->_munged_states.
clear();
611 if (!uniquify_states) {
612 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
622 void ShaderGenerator::
623 clear_generated_shaders() {
627 for (
size_t si = 0; si < size; ++si) {
629 state->_generated_shader.clear();
632 _generated_shaders.clear();
636 if (!uniquify_states) {
637 GraphicsStateGuardianBase::mark_rehash_generated_shaders();
676 key._anim_spec = anim;
677 analyze_renderstate(key, rs);
679 GeneratedShaders::const_iterator si;
680 si = _generated_shaders.find(key);
681 if (si != _generated_shaders.end()) {
689 reset_register_allocator();
691 if (pgraphnodes_cat.is_debug()) {
692 pgraphnodes_cat.debug()
693 <<
"Generating shader for render state " << rs <<
":\n";
694 rs->write(pgraphnodes_cat.debug(
false), 2);
699 const char *tangent_freg =
nullptr;
700 const char *binormal_freg =
nullptr;
701 string tangent_input;
702 string binormal_input;
705 const char *world_position_freg =
nullptr;
706 const char *world_normal_freg =
nullptr;
707 const char *eye_position_freg =
nullptr;
708 const char *eye_normal_freg =
nullptr;
709 const char *hpos_freg =
nullptr;
711 const char *position_vreg;
712 const char *transform_weight_vreg =
nullptr;
713 const char *normal_vreg;
714 const char *color_vreg =
nullptr;
715 const char *transform_index_vreg =
nullptr;
717 if (_use_generic_attr) {
718 position_vreg =
"ATTR0";
719 transform_weight_vreg =
"ATTR1";
720 normal_vreg =
"ATTR2";
721 transform_index_vreg =
"ATTR7";
723 position_vreg =
"POSITION";
724 normal_vreg =
"NORMAL";
727 if (key._color_type == ColorAttrib::T_vertex) {
729 color_vreg = _use_generic_attr ?
"ATTR3" :
"COLOR0";
736 std::ostringstream text;
740 text <<
"/* Generated shader for render state:\n";
744 int map_index_glow = -1;
745 int map_index_gloss = -1;
748 bool need_world_position = (key._num_clip_planes > 0);
749 bool need_world_normal =
false;
750 bool need_eye_position = key._lighting;
751 bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
753 bool have_specular =
false;
755 if (key._material_flags & Material::F_specular) {
756 have_specular =
true;
757 }
else if ((key._texture_flags & ShaderKey::TF_map_gloss) != 0) {
758 have_specular =
true;
762 bool need_color =
false;
763 if (key._color_type != ColorAttrib::T_off) {
765 if (((key._material_flags & Material::F_ambient) == 0 && key._have_separate_ambient) ||
766 (key._material_flags & Material::F_diffuse) == 0 ||
767 key._calc_primary_alpha) {
775 text <<
"void vshader(\n";
776 for (
size_t i = 0; i < key._textures.size(); ++i) {
777 const ShaderKey::TextureInfo &tex = key._textures[i];
779 switch (tex._gen_mode) {
780 case TexGenAttrib::M_world_position:
781 need_world_position =
true;
783 case TexGenAttrib::M_world_normal:
784 need_world_normal =
true;
786 case TexGenAttrib::M_eye_position:
787 need_eye_position =
true;
789 case TexGenAttrib::M_eye_normal:
790 need_eye_normal =
true;
796 if (tex._texcoord_name !=
nullptr) {
797 if (texcoord_fregs.count(tex._texcoord_name) == 0) {
798 const char *freg = alloc_freg();
799 texcoord_fregs[tex._texcoord_name] = freg;
801 string tcname = tex._texcoord_name->join(
"_");
802 text <<
"\t in float4 vtx_" << tcname <<
" : " << alloc_vreg() <<
",\n";
803 text <<
"\t out float4 l_" << tcname <<
" : " << freg <<
",\n";
807 if (tangent_input.empty() &&
808 (tex._flags & (ShaderKey::TF_map_normal | ShaderKey::TF_map_height)) != 0) {
809 PT(
InternalName) tangent_name = InternalName::get_tangent();
810 PT(
InternalName) binormal_name = InternalName::get_binormal();
812 if (tex._texcoord_name !=
nullptr &&
813 tex._texcoord_name != InternalName::get_texcoord()) {
814 tangent_name = tangent_name->append(tex._texcoord_name->get_basename());
815 binormal_name = binormal_name->append(tex._texcoord_name->get_basename());
818 tangent_input = tangent_name->join(
"_");
819 binormal_input = binormal_name->join(
"_");
821 text <<
"\t in float4 vtx_" << tangent_input <<
" : " << alloc_vreg() <<
",\n";
822 text <<
"\t in float4 vtx_" << binormal_input <<
" : " << alloc_vreg() <<
",\n";
825 if (tex._flags & ShaderKey::TF_map_glow) {
828 if (tex._flags & ShaderKey::TF_map_gloss) {
832 if (key._texture_flags & ShaderKey::TF_map_normal) {
833 tangent_freg = alloc_freg();
834 binormal_freg = alloc_freg();
835 text <<
"\t out float4 l_tangent : " << tangent_freg <<
",\n";
836 text <<
"\t out float4 l_binormal : " << binormal_freg <<
",\n";
838 if (need_color && key._color_type == ColorAttrib::T_vertex) {
839 text <<
"\t in float4 vtx_color : " << color_vreg <<
",\n";
840 text <<
"\t out float4 l_color : COLOR0,\n";
842 if (need_world_position || need_world_normal) {
843 text <<
"\t uniform float4x4 trans_model_to_world,\n";
845 if (need_world_position) {
846 world_position_freg = alloc_freg();
847 text <<
"\t out float4 l_world_position : " << world_position_freg <<
",\n";
849 if (need_world_normal) {
850 world_normal_freg = alloc_freg();
851 text <<
"\t out float4 l_world_normal : " << world_normal_freg <<
",\n";
853 if (need_eye_position) {
854 text <<
"\t uniform float4x4 trans_model_to_view,\n";
855 eye_position_freg = alloc_freg();
856 text <<
"\t out float4 l_eye_position : " << eye_position_freg <<
",\n";
857 }
else if (key._texture_flags & ShaderKey::TF_map_normal) {
858 text <<
"\t uniform float4x4 trans_model_to_view,\n";
860 if (need_eye_normal) {
861 eye_normal_freg = alloc_freg();
862 text <<
"\t uniform float4x4 tpose_view_to_model,\n";
863 text <<
"\t out float3 l_eye_normal : " << eye_normal_freg <<
",\n";
865 if ((key._texture_flags & ShaderKey::TF_map_height) != 0 || need_world_normal || need_eye_normal) {
866 text <<
"\t in float3 vtx_normal : " << normal_vreg <<
",\n";
868 if (key._texture_flags & ShaderKey::TF_map_height) {
869 text <<
"\t uniform float4 mspos_view,\n";
870 text <<
"\t out float3 l_eyevec,\n";
872 for (
size_t i = 0; i < key._lights.size(); ++i) {
873 const ShaderKey::LightInfo &light = key._lights[i];
874 if (light._flags & ShaderKey::LF_has_shadows) {
875 lightcoord_fregs.push_back(alloc_freg());
876 text <<
"\t uniform float4x4 mat_shadow_" << i <<
",\n";
877 text <<
"\t out float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
879 lightcoord_fregs.push_back(
nullptr);
882 if (key._fog_mode != 0) {
883 hpos_freg = alloc_freg();
884 text <<
"\t out float4 l_hpos : " << hpos_freg <<
",\n";
886 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
887 key._anim_spec.get_num_transforms() > 0) {
889 if (key._anim_spec.get_indexed_transforms()) {
890 num_transforms = 120;
892 num_transforms = key._anim_spec.get_num_transforms();
894 if (transform_weight_vreg ==
nullptr) {
895 transform_weight_vreg = alloc_vreg();
897 if (transform_index_vreg ==
nullptr) {
898 transform_index_vreg = alloc_vreg();
900 text <<
"\t uniform float4x4 tbl_transforms[" << num_transforms <<
"],\n";
901 text <<
"\t in float4 vtx_transform_weight : " << transform_weight_vreg <<
",\n";
902 if (key._anim_spec.get_indexed_transforms()) {
903 text <<
"\t in uint4 vtx_transform_index : " << transform_index_vreg <<
",\n";
906 text <<
"\t in float4 vtx_position : " << position_vreg <<
",\n";
907 text <<
"\t out float4 l_position : POSITION,\n";
908 text <<
"\t uniform float4x4 mat_modelproj\n";
911 if (key._anim_spec.get_animation_type() == GeomEnums::AT_hardware &&
912 key._anim_spec.get_num_transforms() > 0) {
914 if (!key._anim_spec.get_indexed_transforms()) {
915 text <<
"\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
918 text <<
"\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
919 if (key._anim_spec.get_num_transforms() > 1) {
920 text <<
"\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
922 if (key._anim_spec.get_num_transforms() > 2) {
923 text <<
"\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
925 if (key._anim_spec.get_num_transforms() > 3) {
926 text <<
"\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
930 text <<
"\t vtx_position = mul(matrix, vtx_position);\n";
931 if (need_world_normal || need_eye_normal) {
932 text <<
"\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
936 text <<
"\t l_position = mul(mat_modelproj, vtx_position);\n";
937 if (key._fog_mode != 0) {
938 text <<
"\t l_hpos = l_position;\n";
940 if (need_world_position) {
941 text <<
"\t l_world_position = mul(trans_model_to_world, vtx_position);\n";
943 if (need_world_normal) {
944 text <<
"\t l_world_normal = mul(trans_model_to_world, float4(vtx_normal, 0));\n";
946 if (need_eye_position) {
947 text <<
"\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
949 if (need_eye_normal) {
950 text <<
"\t l_eye_normal = normalize(mul((float3x3)tpose_view_to_model, vtx_normal));\n";
953 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
955 string tcname = it->first->join(
"_");
956 text <<
"\t l_" << tcname <<
" = vtx_" << tcname <<
";\n";
958 if (need_color && key._color_type == ColorAttrib::T_vertex) {
959 text <<
"\t l_color = vtx_color;\n";
961 if (key._texture_flags & ShaderKey::TF_map_normal) {
962 text <<
"\t l_tangent.xyz = normalize(mul((float3x3)trans_model_to_view, vtx_" << tangent_input <<
".xyz));\n";
963 text <<
"\t l_tangent.w = 0;\n";
964 text <<
"\t l_binormal.xyz = normalize(mul((float3x3)trans_model_to_view, -vtx_" << binormal_input <<
".xyz));\n";
965 text <<
"\t l_binormal.w = 0;\n";
967 for (
size_t i = 0; i < key._lights.size(); ++i) {
968 if (key._lights[i]._flags & ShaderKey::LF_has_shadows) {
969 text <<
"\t l_lightcoord" << i <<
" = mul(mat_shadow_" << i <<
", l_eye_position);\n";
972 if (key._texture_flags & ShaderKey::TF_map_height) {
973 text <<
"\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n";
974 text <<
"\t l_eyevec.x = dot(vtx_" << tangent_input <<
".xyz, eyedir);\n";
975 text <<
"\t l_eyevec.y = dot(vtx_" << binormal_input <<
".xyz, eyedir);\n";
976 text <<
"\t l_eyevec.z = dot(vtx_normal, eyedir);\n";
977 text <<
"\t l_eyevec = normalize(l_eyevec);\n";
983 text <<
"void fshader(\n";
984 if (key._fog_mode != 0) {
985 text <<
"\t in float4 l_hpos : " << hpos_freg <<
",\n";
986 text <<
"\t in uniform float4 attr_fog,\n";
987 text <<
"\t in uniform float4 attr_fogcolor,\n";
989 if (need_world_position) {
990 text <<
"\t in float4 l_world_position : " << world_position_freg <<
",\n";
992 if (need_world_normal) {
993 text <<
"\t in float4 l_world_normal : " << world_normal_freg <<
",\n";
995 if (need_eye_position) {
996 text <<
"\t in float4 l_eye_position : " << eye_position_freg <<
",\n";
998 if (need_eye_normal) {
999 text <<
"\t in float3 l_eye_normal : " << eye_normal_freg <<
",\n";
1001 for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
1002 text <<
"\t in float4 l_" << it->first->join(
"_") <<
" : " << it->second <<
",\n";
1004 for (
size_t i = 0; i < key._textures.size(); ++i) {
1005 const ShaderKey::TextureInfo &tex = key._textures[i];
1006 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1011 text <<
"\t uniform sampler" << texture_type_as_string(tex._type) <<
" tex_" << i <<
",\n";
1013 if (tex._flags & ShaderKey::TF_has_texscale) {
1014 text <<
"\t uniform float3 texscale_" << i <<
",\n";
1015 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1016 text <<
"\t uniform float4x4 texmat_" << i <<
",\n";
1019 if (tex._flags & ShaderKey::TF_uses_color) {
1020 text <<
"\t uniform float4 texcolor_" << i <<
",\n";
1023 if (key._texture_flags & ShaderKey::TF_map_normal) {
1024 text <<
"\t in float3 l_tangent : " << tangent_freg <<
",\n";
1025 text <<
"\t in float3 l_binormal : " << binormal_freg <<
",\n";
1027 for (
size_t i = 0; i < key._lights.size(); ++i) {
1028 text <<
"\t uniform float4x4 attr_light" << i <<
",\n";
1030 const ShaderKey::LightInfo &light = key._lights[i];
1031 if (light._flags & ShaderKey::LF_has_shadows) {
1032 if (light._type.is_derived_from(PointLight::get_class_type())) {
1033 text <<
"\t uniform samplerCUBE shadow_" << i <<
",\n";
1034 }
else if (_use_shadow_filter) {
1035 text <<
"\t uniform sampler2DShadow shadow_" << i <<
",\n";
1037 text <<
"\t uniform sampler2D shadow_" << i <<
",\n";
1039 text <<
"\t in float4 l_lightcoord" << i <<
" : " << lightcoord_fregs[i] <<
",\n";
1041 if (light._flags & ShaderKey::LF_has_specular_color) {
1042 text <<
"\t uniform float4 attr_lspec" << i <<
",\n";
1047 if (key._material_flags & (Material::F_ambient | Material::F_diffuse | Material::F_emission | Material::F_specular)) {
1048 text <<
"\t uniform float4x4 attr_material,\n";
1050 if (key._texture_flags & ShaderKey::TF_map_height) {
1051 text <<
"\t float3 l_eyevec,\n";
1053 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1054 text <<
"\t out float4 o_aux : COLOR1,\n";
1056 text <<
"\t out float4 o_color : COLOR0,\n";
1059 if (key._color_type == ColorAttrib::T_vertex) {
1060 text <<
"\t in float4 l_color : COLOR0,\n";
1061 }
else if (key._color_type == ColorAttrib::T_flat) {
1062 text <<
"\t uniform float4 attr_color,\n";
1066 for (
int i = 0; i < key._num_clip_planes; ++i) {
1067 text <<
"\t uniform float4 clipplane_" << i <<
",\n";
1070 text <<
"\t uniform float4 attr_ambient,\n";
1071 text <<
"\t uniform float4 attr_colorscale\n";
1075 for (
int i = 0; i < key._num_clip_planes; ++i) {
1076 text <<
"\t if (l_world_position.x * clipplane_" << i <<
".x + l_world_position.y ";
1077 text <<
"* clipplane_" << i <<
".y + l_world_position.z * clipplane_" << i <<
".z + clipplane_" << i <<
".w <= 0) {\n";
1078 text <<
"\t discard;\n";
1081 text <<
"\t float4 result;\n";
1082 if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
1083 text <<
"\t o_aux = float4(0, 0, 0, 0);\n";
1087 for (
size_t i = 0; i < key._textures.size(); ++i) {
1088 const ShaderKey::TextureInfo &tex = key._textures[i];
1089 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1093 switch (tex._gen_mode) {
1094 case TexGenAttrib::M_off:
1096 text <<
"\t float4 texcoord" << i <<
" = l_" << tex._texcoord_name->join(
"_") <<
";\n";
1098 case TexGenAttrib::M_world_position:
1099 text <<
"\t float4 texcoord" << i <<
" = l_world_position;\n";
1101 case TexGenAttrib::M_world_normal:
1102 text <<
"\t float4 texcoord" << i <<
" = l_world_normal;\n";
1104 case TexGenAttrib::M_eye_position:
1105 text <<
"\t float4 texcoord" << i <<
" = l_eye_position;\n";
1107 case TexGenAttrib::M_eye_normal:
1108 text <<
"\t float4 texcoord" << i <<
" = float4(l_eye_normal, 1.0f);\n";
1111 text <<
"\t float4 texcoord" << i <<
" = float4(0, 0, 0, 0);\n";
1112 pgraphnodes_cat.error()
1113 <<
"Unsupported TexGenAttrib mode: " << tex._gen_mode <<
"\n";
1115 if (tex._flags & ShaderKey::TF_has_texscale) {
1116 text <<
"\t texcoord" << i <<
".xyz *= texscale_" << i <<
";\n";
1117 }
else if (tex._flags & ShaderKey::TF_has_texmat) {
1118 text <<
"\t texcoord" << i <<
" = mul(texmat_" << i <<
", texcoord" << i <<
");\n";
1119 text <<
"\t texcoord" << i <<
".xyz /= texcoord" << i <<
".w;\n";
1122 text <<
"\t // Fetch all textures.\n";
1123 for (
size_t i = 0; i < key._textures.size(); ++i) {
1124 const ShaderKey::TextureInfo &tex = key._textures[i];
1125 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1129 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1130 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1131 switch (tex._type) {
1132 case Texture::TT_cube_map:
1133 case Texture::TT_3d_texture:
1134 case Texture::TT_2d_texture_array:
1137 case Texture::TT_2d_texture:
1140 case Texture::TT_1d_texture:
1146 text <<
");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << i;
1147 if (tex._mode == TextureStage::M_normal_height ||
1148 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1153 text <<
" * 2.0 - 1.0) * " << parallax_mapping_scale <<
";\n";
1155 for (
int j = 0; j < parallax_mapping_samples - 1; ++j) {
1156 text <<
"\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << i;
1157 if (tex._mode == TextureStage::M_normal_height ||
1158 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1163 text <<
" * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale <<
";\n";
1166 for (
size_t i = 0; i < key._textures.size(); ++i) {
1167 ShaderKey::TextureInfo &tex = key._textures[i];
1168 if (tex._mode == TextureStage::M_modulate && tex._flags == 0) {
1172 if ((tex._flags & ShaderKey::TF_map_height) == 0) {
1175 if (key._texture_flags & ShaderKey::TF_map_height) {
1176 text <<
"\t texcoord" << i <<
".xyz -= parallax_offset;\n";
1178 text <<
"\t float4 tex" << i <<
" = tex" << texture_type_as_string(tex._type);
1179 text <<
"(tex_" << i <<
", texcoord" << i <<
".";
1180 switch (tex._type) {
1181 case Texture::TT_cube_map:
1182 case Texture::TT_3d_texture:
1183 case Texture::TT_2d_texture_array:
1186 case Texture::TT_2d_texture:
1189 case Texture::TT_1d_texture:
1198 if (need_eye_normal) {
1199 text <<
"\t // Correct the surface normal for interpolation effects\n";
1200 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1202 if (key._texture_flags & ShaderKey::TF_map_normal) {
1203 text <<
"\t // Translate tangent-space normal in map to view-space.\n";
1206 bool is_first =
true;
1207 for (
size_t i = 0; i < key._textures.size(); ++i) {
1208 const ShaderKey::TextureInfo &tex = key._textures[i];
1209 if (tex._flags & ShaderKey::TF_map_normal) {
1211 text <<
"\t float3 tsnormal = normalize((tex" << i <<
".xyz * 2) - 1);\n";
1215 text <<
"\t tsnormal.z += 1;\n";
1216 text <<
"\t float3 tmp" << i <<
" = tex" << i <<
".xyz * float3(-2, -2, 2) + float3(1, 1, -1);\n";
1217 text <<
"\t tsnormal = normalize(tsnormal * dot(tsnormal, tmp" << i <<
") - tmp" << i <<
" * tsnormal.z);\n";
1220 text <<
"\t l_eye_normal *= tsnormal.z;\n";
1221 text <<
"\t l_eye_normal += normalize(l_tangent) * tsnormal.x;\n";
1222 text <<
"\t l_eye_normal += normalize(l_binormal) * tsnormal.y;\n";
1223 text <<
"\t l_eye_normal = normalize(l_eye_normal);\n";
1225 if (key._outputs & AuxBitplaneAttrib::ABO_aux_normal) {
1226 text <<
"\t // Output the camera-space surface normal\n";
1227 text <<
"\t o_aux.rgb = (l_eye_normal*0.5) + float3(0.5,0.5,0.5);\n";
1229 if (key._lighting) {
1230 text <<
"\t // Begin view-space light calculations\n";
1231 text <<
"\t float ldist,lattenv,langle,lshad;\n";
1232 text <<
"\t float4 lcolor,lspec,lpoint,latten,ldir,leye;\n";
1233 text <<
"\t float3 lvec,lhalf;\n";
1234 if (key._have_separate_ambient) {
1235 text <<
"\t float4 tot_ambient = float4(0,0,0,0);\n";
1237 text <<
"\t float4 tot_diffuse = float4(0,0,0,0);\n";
1238 if (have_specular) {
1239 text <<
"\t float4 tot_specular = float4(0,0,0,0);\n";
1240 if (key._material_flags & Material::F_specular) {
1241 text <<
"\t float shininess = attr_material[3].w;\n";
1243 text <<
"\t float shininess = 50; // no shininess specified, using default\n";
1246 if (key._have_separate_ambient) {
1247 text <<
"\t tot_ambient += attr_ambient;\n";
1249 text <<
"\t tot_diffuse += attr_ambient;\n";
1252 for (
size_t i = 0; i < key._lights.size(); ++i) {
1253 const ShaderKey::LightInfo &light = key._lights[i];
1254 if (light._type.is_derived_from(DirectionalLight::get_class_type())) {
1255 text <<
"\t // Directional Light " << i <<
"\n";
1256 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1257 if (light._flags & ShaderKey::LF_has_specular_color) {
1258 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1260 text <<
"\t lspec = lcolor;\n";
1262 text <<
"\t lvec = attr_light" << i <<
"[3].xyz;\n";
1263 text <<
"\t lcolor *= saturate(dot(l_eye_normal, lvec.xyz));\n";
1264 if (light._flags & ShaderKey::LF_has_shadows) {
1265 if (_use_shadow_filter) {
1266 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1268 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1270 text <<
"\t lcolor *= lshad;\n";
1271 text <<
"\t lspec *= lshad;\n";
1273 text <<
"\t tot_diffuse += lcolor;\n";
1274 if (have_specular) {
1275 if (key._material_flags & Material::F_local) {
1276 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1278 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1280 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1281 text <<
"\t tot_specular += lspec;\n";
1283 }
else if (light._type.is_derived_from(PointLight::get_class_type())) {
1284 text <<
"\t // Point Light " << i <<
"\n";
1285 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1286 if (light._flags & ShaderKey::LF_has_specular_color) {
1287 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1289 text <<
"\t lspec = lcolor;\n";
1291 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1292 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1293 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1294 text <<
"\t ldist = length(lvec);\n";
1295 text <<
"\t lvec /= ldist;\n";
1296 if (light._type.is_derived_from(SphereLight::get_class_type())) {
1297 text <<
"\t ldist = max(ldist, attr_light" << i <<
"[2].w);\n";
1299 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1300 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1301 if (light._flags & ShaderKey::LF_has_shadows) {
1302 text <<
"\t ldist = max(abs(l_lightcoord" << i <<
".x), max(abs(l_lightcoord" << i <<
".y), abs(l_lightcoord" << i <<
".z)));\n";
1303 text <<
"\t ldist = ((latten.w+lpoint.w)/(latten.w-lpoint.w))+((-2*latten.w*lpoint.w)/(ldist * (latten.w-lpoint.w)));\n";
1304 text <<
"\t lshad = texCUBE(shadow_" << i <<
", l_lightcoord" << i <<
".xyz).r >= ldist * 0.5 + 0.5;\n";
1305 text <<
"\t lcolor *= lshad;\n";
1306 text <<
"\t lspec *= lshad;\n";
1308 text <<
"\t tot_diffuse += lcolor;\n";
1309 if (have_specular) {
1310 if (key._material_flags & Material::F_local) {
1311 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1313 text <<
"\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
1315 text <<
"\t lspec *= lattenv;\n";
1316 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1317 text <<
"\t tot_specular += lspec;\n";
1319 }
else if (light._type.is_derived_from(Spotlight::get_class_type())) {
1320 text <<
"\t // Spot Light " << i <<
"\n";
1321 text <<
"\t lcolor = attr_light" << i <<
"[0];\n";
1322 if (light._flags & ShaderKey::LF_has_specular_color) {
1323 text <<
"\t lspec = attr_lspec" << i <<
";\n";
1325 text <<
"\t lspec = lcolor;\n";
1327 text <<
"\t latten = attr_light" << i <<
"[1];\n";
1328 text <<
"\t ldir = attr_light" << i <<
"[2];\n";
1329 text <<
"\t lpoint = attr_light" << i <<
"[3];\n";
1330 text <<
"\t lvec = lpoint.xyz - l_eye_position.xyz;\n";
1331 text <<
"\t ldist = length(lvec);\n";
1332 text <<
"\t lvec /= ldist;\n";
1333 text <<
"\t langle = saturate(dot(ldir.xyz, lvec));\n";
1334 text <<
"\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n";
1335 text <<
"\t lattenv *= pow(langle, latten.w);\n";
1336 text <<
"\t if (langle < ldir.w) lattenv = 0;\n";
1337 text <<
"\t lcolor *= lattenv * saturate(dot(l_eye_normal, lvec));\n";
1338 if (light._flags & ShaderKey::LF_has_shadows) {
1339 if (_use_shadow_filter) {
1340 text <<
"\t lshad = shadow2DProj(shadow_" << i <<
", l_lightcoord" << i <<
").r;\n";
1342 text <<
"\t lshad = tex2Dproj(shadow_" << i <<
", l_lightcoord" << i <<
").r > l_lightcoord" << i <<
".z / l_lightcoord" << i <<
".w;\n";
1344 text <<
"\t lcolor *= lshad;\n";
1345 text <<
"\t lspec *= lshad;\n";
1348 text <<
"\t tot_diffuse += lcolor;\n";
1349 if (have_specular) {
1350 if (key._material_flags & Material::F_local) {
1351 text <<
"\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
1353 text <<
"\t lhalf = normalize(lvec - float3(0,1,0));\n";
1355 text <<
"\t lspec *= lattenv;\n";
1356 text <<
"\t lspec *= pow(saturate(dot(l_eye_normal, lhalf)), shininess);\n";
1357 text <<
"\t tot_specular += lspec;\n";
1361 if (key._lighting) {
1362 if (key._light_ramp !=
nullptr) {
1363 switch (key._light_ramp->get_mode()) {
1364 case LightRampAttrib::LRT_single_threshold:
1366 PN_stdfloat t = key._light_ramp->get_threshold(0);
1367 PN_stdfloat l0 = key._light_ramp->get_level(0);
1368 text <<
"\t // Single-threshold light ramp\n";
1369 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1370 text <<
"\t float lr_scale = (lr_in < " << t <<
") ? 0.0 : (" << l0 <<
"/lr_in);\n";
1371 text <<
"\t tot_diffuse = tot_diffuse * lr_scale;\n";
1374 case LightRampAttrib::LRT_double_threshold:
1376 PN_stdfloat t0 = key._light_ramp->get_threshold(0);
1377 PN_stdfloat t1 = key._light_ramp->get_threshold(1);
1378 PN_stdfloat l0 = key._light_ramp->get_level(0);
1379 PN_stdfloat l1 = key._light_ramp->get_level(1);
1380 text <<
"\t // Double-threshold light ramp\n";
1381 text <<
"\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
1382 text <<
"\t float lr_out = 0.0;\n";
1383 text <<
"\t if (lr_in > " << t0 <<
") lr_out=" << l0 <<
";\n";
1384 text <<
"\t if (lr_in > " << t1 <<
") lr_out=" << l1 <<
";\n";
1385 text <<
"\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
1392 text <<
"\t // Begin view-space light summation\n";
1393 if (key._material_flags & Material::F_emission) {
1394 if (key._texture_flags & ShaderKey::TF_map_glow) {
1395 text <<
"\t result = attr_material[2] * saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1397 text <<
"\t result = attr_material[2];\n";
1400 if (key._texture_flags & ShaderKey::TF_map_glow) {
1401 text <<
"\t result = saturate(2 * (tex" << map_index_glow <<
".a - 0.5));\n";
1403 text <<
"\t result = float4(0,0,0,0);\n";
1406 if (key._have_separate_ambient) {
1407 if (key._material_flags & Material::F_ambient) {
1408 text <<
"\t result += tot_ambient * attr_material[0];\n";
1409 }
else if (key._color_type == ColorAttrib::T_vertex) {
1410 text <<
"\t result += tot_ambient * l_color;\n";
1411 }
else if (key._color_type == ColorAttrib::T_flat) {
1412 text <<
"\t result += tot_ambient * attr_color;\n";
1414 text <<
"\t result += tot_ambient;\n";
1417 if (key._material_flags & Material::F_diffuse) {
1418 text <<
"\t result += tot_diffuse * attr_material[1];\n";
1419 }
else if (key._color_type == ColorAttrib::T_vertex) {
1420 text <<
"\t result += tot_diffuse * l_color;\n";
1421 }
else if (key._color_type == ColorAttrib::T_flat) {
1422 text <<
"\t result += tot_diffuse * attr_color;\n";
1424 text <<
"\t result += tot_diffuse;\n";
1426 if (key._light_ramp ==
nullptr ||
1427 key._light_ramp->get_mode() == LightRampAttrib::LRT_default) {
1428 text <<
"\t result = saturate(result);\n";
1430 text <<
"\t // End view-space light calculations\n";
1434 if (key._calc_primary_alpha) {
1435 if (key._color_type == ColorAttrib::T_vertex) {
1436 text <<
"\t result.a = l_color.a;\n";
1437 }
else if (key._color_type == ColorAttrib::T_flat) {
1438 text <<
"\t result.a = attr_color.a;\n";
1440 text <<
"\t result.a = 1;\n";
1444 if (key._color_type == ColorAttrib::T_vertex) {
1445 text <<
"\t result = l_color;\n";
1446 }
else if (key._color_type == ColorAttrib::T_flat) {
1447 text <<
"\t result = attr_color;\n";
1449 text <<
"\t result = float4(1, 1, 1, 1);\n";
1454 text <<
"\t result *= attr_colorscale;\n";
1457 if (key._texture_flags & ShaderKey::TF_uses_primary_color) {
1458 text <<
"\t float4 primary_color = result;\n";
1460 if (key._texture_flags & ShaderKey::TF_uses_last_saved_result) {
1461 text <<
"\t float4 last_saved_result = result;\n";
1465 for (
size_t i = 0; i < key._textures.size(); ++i) {
1466 const ShaderKey::TextureInfo &tex = key._textures[i];
1467 TextureStage::CombineMode combine_rgb, combine_alpha;
1469 switch (tex._mode) {
1470 case TextureStage::M_modulate:
1471 if ((tex._flags & ShaderKey::TF_has_rgb) != 0 &&
1472 (tex._flags & ShaderKey::TF_has_alpha) != 0) {
1473 text <<
"\t result.rgba *= tex" << i <<
".rgba;\n";
1474 }
else if (tex._flags & ShaderKey::TF_has_alpha) {
1475 text <<
"\t result.a *= tex" << i <<
".a;\n";
1476 }
else if (tex._flags & ShaderKey::TF_has_rgb) {
1477 text <<
"\t result.rgb *= tex" << i <<
".rgb;\n";
1480 case TextureStage::M_modulate_glow:
1481 case TextureStage::M_modulate_gloss:
1487 text <<
"\t result.rgb *= tex" << i <<
";\n";
1489 case TextureStage::M_decal:
1490 text <<
"\t result.rgb = lerp(result, tex" << i <<
", tex" << i <<
".a).rgb;\n";
1492 case TextureStage::M_blend:
1493 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb, tex" << i <<
".rgb);\n";
1494 if (key._calc_primary_alpha) {
1495 text <<
"\t result.a *= tex" << i <<
".a;\n";
1498 case TextureStage::M_replace:
1499 text <<
"\t result = tex" << i <<
";\n";
1501 case TextureStage::M_add:
1502 text <<
"\t result.rgb += tex" << i <<
".rgb;\n";
1503 if (key._calc_primary_alpha) {
1504 text <<
"\t result.a *= tex" << i <<
".a;\n";
1507 case TextureStage::M_combine:
1508 combine_rgb = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_RGB_MODE_MASK) >> ShaderKey::TF_COMBINE_RGB_MODE_SHIFT);
1509 combine_alpha = (TextureStage::CombineMode)((tex._flags & ShaderKey::TF_COMBINE_ALPHA_MODE_MASK) >> ShaderKey::TF_COMBINE_ALPHA_MODE_SHIFT);
1510 if (combine_rgb == TextureStage::CM_dot3_rgba) {
1511 text <<
"\t result = ";
1512 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1515 text <<
"\t result.rgb = ";
1516 text << combine_mode_as_string(tex, combine_rgb,
false, i);
1517 text <<
";\n\t result.a = ";
1518 text << combine_mode_as_string(tex, combine_alpha,
true, i);
1521 if (tex._flags & ShaderKey::TF_rgb_scale_2) {
1522 text <<
"\t result.rgb *= 2;\n";
1524 if (tex._flags & ShaderKey::TF_rgb_scale_4) {
1525 text <<
"\t result.rgb *= 4;\n";
1527 if (tex._flags & ShaderKey::TF_alpha_scale_2) {
1528 text <<
"\t result.a *= 2;\n";
1530 if (tex._flags & ShaderKey::TF_alpha_scale_4) {
1531 text <<
"\t result.a *= 4;\n";
1534 case TextureStage::M_blend_color_scale:
1535 text <<
"\t result.rgb = lerp(result.rgb, texcolor_" << i <<
".rgb * attr_colorscale.rgb, tex" << i <<
".rgb);\n";
1536 if (key._calc_primary_alpha) {
1537 text <<
"\t result.a *= texcolor_" << i <<
".a * attr_colorscale.a;\n";
1543 if (tex._flags & ShaderKey::TF_saved_result) {
1544 text <<
"\t last_saved_result = result;\n";
1548 if (key._alpha_test_mode != RenderAttrib::M_none) {
1549 text <<
"\t // Shader includes alpha test:\n";
1550 double ref = key._alpha_test_ref;
1551 switch (key._alpha_test_mode) {
1552 case RenderAttrib::M_never:
1553 text <<
"\t discard;\n";
1555 case RenderAttrib::M_less:
1556 text <<
"\t if (result.a >= " <<
ref <<
") discard;\n";
1558 case RenderAttrib::M_equal:
1559 text <<
"\t if (result.a != " <<
ref <<
") discard;\n";
1561 case RenderAttrib::M_less_equal:
1562 text <<
"\t if (result.a > " <<
ref <<
") discard;\n";
1564 case RenderAttrib::M_greater:
1565 text <<
"\t if (result.a <= " <<
ref <<
") discard;\n";
1567 case RenderAttrib::M_not_equal:
1568 text <<
"\t if (result.a == " <<
ref <<
") discard;\n";
1570 case RenderAttrib::M_greater_equal:
1571 text <<
"\t if (result.a < " <<
ref <<
") discard;\n";
1573 case RenderAttrib::M_none:
1574 case RenderAttrib::M_always:
1579 if (key._outputs & AuxBitplaneAttrib::ABO_glow) {
1580 if (key._texture_flags & ShaderKey::TF_map_glow) {
1581 text <<
"\t result.a = tex" << map_index_glow <<
".a;\n";
1583 text <<
"\t result.a = 0.5;\n";
1586 if (key._outputs & AuxBitplaneAttrib::ABO_aux_glow) {
1587 if (key._texture_flags & ShaderKey::TF_map_glow) {
1588 text <<
"\t o_aux.a = tex" << map_index_glow <<
".a;\n";
1590 text <<
"\t o_aux.a = 0.5;\n";
1594 if (have_specular) {
1595 if (key._material_flags & Material::F_specular) {
1596 text <<
"\t tot_specular *= attr_material[3];\n";
1598 if (key._texture_flags & ShaderKey::TF_map_gloss) {
1599 text <<
"\t tot_specular *= tex" << map_index_gloss <<
".a;\n";
1601 text <<
"\t result.rgb = result.rgb + tot_specular.rgb;\n";
1603 if (key._light_ramp !=
nullptr) {
1604 switch (key._light_ramp->get_mode()) {
1605 case LightRampAttrib::LRT_hdr0:
1606 text <<
"\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n";
1608 case LightRampAttrib::LRT_hdr1:
1609 text <<
"\t result.rgb = (result*result + result) / (result*result + result + 1);\n";
1611 case LightRampAttrib::LRT_hdr2:
1612 text <<
"\t result.rgb = result / (result + 1);\n";
1619 if (key._fog_mode != 0) {
1620 Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
1623 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
1625 case Fog::M_exponential:
1626 text <<
"\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate(exp2(attr_fog.x * l_hpos.z * -1.442695f)));\n";
1628 case Fog::M_exponential_squared:
1629 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";
1636 text <<
"\t o_color = result * 1.000001;\n";
1637 if (key._alpha_test_mode != RenderAttrib::M_none) {
1638 text <<
"\t // Shader subsumes normal alpha test.\n";
1640 if (key._disable_alpha_write) {
1641 text <<
"\t // Shader disables alpha write.\n";
1646 PT(
Shader) shader = Shader::make(text.str(), Shader::SL_Cg);
1647 nassertr(shader !=
nullptr,
nullptr);
1650 if (key._alpha_test_mode != RenderAttrib::M_none) {
1651 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test,
true);
1653 if (key._disable_alpha_write) {
1654 shattr = DCAST(
ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write,
true);
1657 reset_register_allocator();
1660 _generated_shaders[key] = attr;
1667 string ShaderGenerator::
1668 combine_mode_as_string(
const ShaderKey::TextureInfo &info, TextureStage::CombineMode c_mode,
bool alpha,
short texindex) {
1669 std::ostringstream text;
1671 case TextureStage::CM_modulate:
1672 text << combine_source_as_string(info, 0, alpha, texindex);
1674 text << combine_source_as_string(info, 1, alpha, texindex);
1676 case TextureStage::CM_add:
1677 text << combine_source_as_string(info, 0, alpha, texindex);
1679 text << combine_source_as_string(info, 1, alpha, texindex);
1681 case TextureStage::CM_add_signed:
1682 text << combine_source_as_string(info, 0, alpha, texindex);
1684 text << combine_source_as_string(info, 1, alpha, texindex);
1688 text <<
" - float3(0.5, 0.5, 0.5)";
1691 case TextureStage::CM_interpolate:
1693 text << combine_source_as_string(info, 1, alpha, texindex);
1695 text << combine_source_as_string(info, 0, alpha, texindex);
1697 text << combine_source_as_string(info, 2, alpha, texindex);
1700 case TextureStage::CM_subtract:
1701 text << combine_source_as_string(info, 0, alpha, texindex);
1703 text << combine_source_as_string(info, 1, alpha, texindex);
1705 case TextureStage::CM_dot3_rgb:
1706 case TextureStage::CM_dot3_rgba:
1708 text << combine_source_as_string(info, 0, alpha, texindex);
1709 text <<
" - float3(0.5), ";
1710 text << combine_source_as_string(info, 1, alpha, texindex);
1711 text <<
" - float3(0.5))";
1713 case TextureStage::CM_replace:
1715 text << combine_source_as_string(info, 0, alpha, texindex);
1724 string ShaderGenerator::
1725 combine_source_as_string(
const ShaderKey::TextureInfo &info,
short num,
bool alpha,
short texindex) {
1726 TextureStage::CombineSource c_src;
1727 TextureStage::CombineOperand c_op;
1729 c_src = UNPACK_COMBINE_SRC(info._combine_rgb, num);
1730 c_op = UNPACK_COMBINE_OP(info._combine_rgb, num);
1732 c_src = UNPACK_COMBINE_SRC(info._combine_alpha, num);
1733 c_op = UNPACK_COMBINE_OP(info._combine_alpha, num);
1735 std::ostringstream csource;
1736 if (c_op == TextureStage::CO_one_minus_src_color ||
1737 c_op == TextureStage::CO_one_minus_src_alpha) {
1738 csource <<
"saturate(1.0f - ";
1741 case TextureStage::CS_undefined:
1742 case TextureStage::CS_texture:
1743 csource <<
"tex" << texindex;
1745 case TextureStage::CS_constant:
1746 csource <<
"texcolor_" << texindex;
1748 case TextureStage::CS_primary_color:
1749 csource <<
"primary_color";
1751 case TextureStage::CS_previous:
1752 csource <<
"result";
1754 case TextureStage::CS_constant_color_scale:
1755 csource <<
"attr_colorscale";
1757 case TextureStage::CS_last_saved_result:
1758 csource <<
"last_saved_result";
1761 if (c_op == TextureStage::CO_one_minus_src_color ||
1762 c_op == TextureStage::CO_one_minus_src_alpha) {
1765 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) {
1771 return "float3(" + csource.str() +
")";
1774 return csource.str();
1780 const char *ShaderGenerator::
1781 texture_type_as_string(Texture::TextureType ttype) {
1783 case Texture::TT_1d_texture:
1786 case Texture::TT_2d_texture:
1789 case Texture::TT_3d_texture:
1792 case Texture::TT_cube_map:
1795 case Texture::TT_2d_texture_array:
1799 pgraphnodes_cat.error() <<
"Unsupported texture type!\n";
1807 ShaderGenerator::ShaderKey::
1813 _have_separate_ambient(false),
1816 _calc_primary_alpha(false),
1817 _disable_alpha_write(false),
1819 _alpha_test_ref(0.0),
1820 _num_clip_planes(0),
1821 _light_ramp(nullptr) {
1828 bool ShaderGenerator::ShaderKey::
1829 operator < (
const ShaderKey &other)
const {
1830 if (_anim_spec != other._anim_spec) {
1831 return _anim_spec < other._anim_spec;
1833 if (_color_type != other._color_type) {
1834 return _color_type < other._color_type;
1836 if (_material_flags != other._material_flags) {
1837 return _material_flags < other._material_flags;
1839 if (_texture_flags != other._texture_flags) {
1840 return _texture_flags < other._texture_flags;
1842 if (_textures.size() != other._textures.size()) {
1843 return _textures.size() < other._textures.size();
1845 for (
size_t i = 0; i < _textures.size(); ++i) {
1846 const ShaderKey::TextureInfo &tex = _textures[i];
1847 const ShaderKey::TextureInfo &other_tex = other._textures[i];
1848 if (tex._texcoord_name != other_tex._texcoord_name) {
1849 return tex._texcoord_name < other_tex._texcoord_name;
1851 if (tex._type != other_tex._type) {
1852 return tex._type < other_tex._type;
1854 if (tex._mode != other_tex._mode) {
1855 return tex._mode < other_tex._mode;
1857 if (tex._gen_mode != other_tex._gen_mode) {
1858 return tex._gen_mode < other_tex._gen_mode;
1860 if (tex._flags != other_tex._flags) {
1861 return tex._flags < other_tex._flags;
1863 if (tex._combine_rgb != other_tex._combine_rgb) {
1864 return tex._combine_rgb < other_tex._combine_rgb;
1866 if (tex._combine_alpha != other_tex._combine_alpha) {
1867 return tex._combine_alpha < other_tex._combine_alpha;
1870 if (_lights.size() != other._lights.size()) {
1871 return _lights.size() < other._lights.size();
1873 for (
size_t i = 0; i < _lights.size(); ++i) {
1874 const ShaderKey::LightInfo &light = _lights[i];
1875 const ShaderKey::LightInfo &other_light = other._lights[i];
1876 if (light._type != other_light._type) {
1877 return light._type < other_light._type;
1879 if (light._flags != other_light._flags) {
1880 return light._flags < other_light._flags;
1883 if (_lighting != other._lighting) {
1884 return _lighting < other._lighting;
1886 if (_have_separate_ambient != other._have_separate_ambient) {
1887 return _have_separate_ambient < other._have_separate_ambient;
1889 if (_fog_mode != other._fog_mode) {
1890 return _fog_mode < other._fog_mode;
1892 if (_outputs != other._outputs) {
1893 return _outputs < other._outputs;
1895 if (_calc_primary_alpha != other._calc_primary_alpha) {
1896 return _calc_primary_alpha < other._calc_primary_alpha;
1898 if (_disable_alpha_write != other._disable_alpha_write) {
1899 return _disable_alpha_write < other._disable_alpha_write;
1901 if (_alpha_test_mode != other._alpha_test_mode) {
1902 return _alpha_test_mode < other._alpha_test_mode;
1904 if (_alpha_test_ref != other._alpha_test_ref) {
1905 return _alpha_test_ref < other._alpha_test_ref;
1907 if (_num_clip_planes != other._num_clip_planes) {
1908 return _num_clip_planes < other._num_clip_planes;
1910 return _light_ramp < other._light_ramp;
1916 bool ShaderGenerator::ShaderKey::
1917 operator == (
const ShaderKey &other)
const {
1918 if (_anim_spec != other._anim_spec) {
1921 if (_color_type != other._color_type) {
1924 if (_material_flags != other._material_flags) {
1927 if (_texture_flags != other._texture_flags) {
1930 if (_textures.size() != other._textures.size()) {
1933 for (
size_t i = 0; i < _textures.size(); ++i) {
1934 const ShaderKey::TextureInfo &tex = _textures[i];
1935 const ShaderKey::TextureInfo &other_tex = other._textures[i];
1936 if (tex._texcoord_name != other_tex._texcoord_name ||
1937 tex._type != other_tex._type ||
1938 tex._mode != other_tex._mode ||
1939 tex._gen_mode != other_tex._gen_mode ||
1940 tex._flags != other_tex._flags ||
1941 tex._combine_rgb != other_tex._combine_rgb ||
1942 tex._combine_alpha != other_tex._combine_alpha) {
1946 if (_lights.size() != other._lights.size()) {
1949 for (
size_t i = 0; i < _lights.size(); ++i) {
1950 const ShaderKey::LightInfo &light = _lights[i];
1951 const ShaderKey::LightInfo &other_light = other._lights[i];
1952 if (light._type != other_light._type ||
1953 light._flags != other_light._flags) {
1957 return _lighting == other._lighting
1958 && _have_separate_ambient == other._have_separate_ambient
1959 && _fog_mode == other._fog_mode
1960 && _outputs == other._outputs
1961 && _calc_primary_alpha == other._calc_primary_alpha
1962 && _disable_alpha_write == other._disable_alpha_write
1963 && _alpha_test_mode == other._alpha_test_mode
1964 && _alpha_test_ref == other._alpha_test_ref
1965 && _num_clip_planes == other._num_clip_planes
1966 && _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(),...
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.
get_color_type
Returns the type of color specified by this ColorAttrib.
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.