Panda3D
|
00001 // Filename: shaderGenerator.cxx 00002 // Created by: jyelon (15Dec07) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "shaderGenerator.h" 00016 #include "renderState.h" 00017 #include "shaderAttrib.h" 00018 #include "auxBitplaneAttrib.h" 00019 #include "alphaTestAttrib.h" 00020 #include "colorBlendAttrib.h" 00021 #include "transparencyAttrib.h" 00022 #include "textureAttrib.h" 00023 #include "colorAttrib.h" 00024 #include "lightAttrib.h" 00025 #include "materialAttrib.h" 00026 #include "lightRampAttrib.h" 00027 #include "texMatrixAttrib.h" 00028 #include "texGenAttrib.h" 00029 #include "colorScaleAttrib.h" 00030 #include "fogAttrib.h" 00031 #include "texture.h" 00032 #include "ambientLight.h" 00033 #include "directionalLight.h" 00034 #include "pointLight.h" 00035 #include "spotlight.h" 00036 #include "lightLensNode.h" 00037 #include "lvector4.h" 00038 00039 TypeHandle ShaderGenerator::_type_handle; 00040 00041 //////////////////////////////////////////////////////////////////// 00042 // Function: ShaderGenerator::Constructor 00043 // Access: Published 00044 // Description: Create a ShaderGenerator. This has no state, 00045 // except possibly to cache certain results. 00046 // The parameter that must be passed is the GSG to 00047 // which the shader generator belongs. 00048 //////////////////////////////////////////////////////////////////// 00049 ShaderGenerator:: 00050 ShaderGenerator(PT(GraphicsStateGuardianBase) gsg, PT(GraphicsOutputBase) host) : 00051 _gsg (gsg), _host (host) { 00052 } 00053 00054 //////////////////////////////////////////////////////////////////// 00055 // Function: ShaderGenerator::Destructor 00056 // Access: Published, Virtual 00057 // Description: Destroy a ShaderGenerator. 00058 //////////////////////////////////////////////////////////////////// 00059 ShaderGenerator:: 00060 ~ShaderGenerator() { 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: ShaderGenerator::reset_register_allocator 00065 // Access: Protected 00066 // Description: Clears the register allocator. Initially, the pool 00067 // of available registers is empty. You have to add 00068 // some if you want there to be any. 00069 //////////////////////////////////////////////////////////////////// 00070 void ShaderGenerator:: 00071 reset_register_allocator() { 00072 _vtregs_used = 0; 00073 _vcregs_used = 0; 00074 _ftregs_used = 0; 00075 _fcregs_used = 0; 00076 } 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Function: ShaderGenerator::alloc_vreg 00080 // Access: Protected 00081 // Description: Allocate a vreg. 00082 //////////////////////////////////////////////////////////////////// 00083 INLINE char *ShaderGenerator:: 00084 alloc_vreg() { 00085 switch (_vtregs_used) { 00086 case 0: _vtregs_used += 1; return (char*)"TEXCOORD0"; 00087 case 1: _vtregs_used += 1; return (char*)"TEXCOORD1"; 00088 case 2: _vtregs_used += 1; return (char*)"TEXCOORD2"; 00089 case 3: _vtregs_used += 1; return (char*)"TEXCOORD3"; 00090 case 4: _vtregs_used += 1; return (char*)"TEXCOORD4"; 00091 case 5: _vtregs_used += 1; return (char*)"TEXCOORD5"; 00092 case 6: _vtregs_used += 1; return (char*)"TEXCOORD6"; 00093 case 7: _vtregs_used += 1; return (char*)"TEXCOORD7"; 00094 case 8: _vtregs_used += 1; return (char*)"TEXCOORD8"; 00095 case 9: _vtregs_used += 1; return (char*)"TEXCOORD9"; 00096 case 10: _vtregs_used += 1; return (char*)"TEXCOORD10"; 00097 case 11: _vtregs_used += 1; return (char*)"TEXCOORD11"; 00098 case 12: _vtregs_used += 1; return (char*)"TEXCOORD12"; 00099 case 13: _vtregs_used += 1; return (char*)"TEXCOORD13"; 00100 case 14: _vtregs_used += 1; return (char*)"TEXCOORD14"; 00101 case 15: _vtregs_used += 1; return (char*)"TEXCOORD15"; 00102 } 00103 switch (_vcregs_used) { 00104 case 0: _vcregs_used += 1; return (char*)"COLOR0"; 00105 case 1: _vcregs_used += 1; return (char*)"COLOR1"; 00106 case 2: _vcregs_used += 1; return (char*)"COLOR2"; 00107 case 3: _vcregs_used += 1; return (char*)"COLOR3"; 00108 case 4: _vcregs_used += 1; return (char*)"COLOR4"; 00109 case 5: _vcregs_used += 1; return (char*)"COLOR5"; 00110 case 6: _vcregs_used += 1; return (char*)"COLOR6"; 00111 case 7: _vcregs_used += 1; return (char*)"COLOR7"; 00112 case 8: _vcregs_used += 1; return (char*)"COLOR8"; 00113 case 9: _vcregs_used += 1; return (char*)"COLOR9"; 00114 case 10: _vcregs_used += 1; return (char*)"COLOR10"; 00115 case 11: _vcregs_used += 1; return (char*)"COLOR11"; 00116 case 12: _vcregs_used += 1; return (char*)"COLOR12"; 00117 case 13: _vcregs_used += 1; return (char*)"COLOR13"; 00118 case 14: _vcregs_used += 1; return (char*)"COLOR14"; 00119 case 15: _vcregs_used += 1; return (char*)"COLOR15"; 00120 } 00121 return (char*)"UNKNOWN"; 00122 } 00123 00124 //////////////////////////////////////////////////////////////////// 00125 // Function: ShaderGenerator::alloc_freg 00126 // Access: Protected 00127 // Description: Allocate a freg. 00128 //////////////////////////////////////////////////////////////////// 00129 INLINE char *ShaderGenerator:: 00130 alloc_freg() { 00131 switch (_ftregs_used) { 00132 case 0: _ftregs_used += 1; return (char*)"TEXCOORD0"; 00133 case 1: _ftregs_used += 1; return (char*)"TEXCOORD1"; 00134 case 2: _ftregs_used += 1; return (char*)"TEXCOORD2"; 00135 case 3: _ftregs_used += 1; return (char*)"TEXCOORD3"; 00136 case 4: _ftregs_used += 1; return (char*)"TEXCOORD4"; 00137 case 5: _ftregs_used += 1; return (char*)"TEXCOORD5"; 00138 case 6: _ftregs_used += 1; return (char*)"TEXCOORD6"; 00139 case 7: _ftregs_used += 1; return (char*)"TEXCOORD7"; 00140 case 8: _ftregs_used += 1; return (char*)"TEXCOORD8"; 00141 case 9: _ftregs_used += 1; return (char*)"TEXCOORD9"; 00142 case 10: _ftregs_used += 1; return (char*)"TEXCOORD10"; 00143 case 11: _ftregs_used += 1; return (char*)"TEXCOORD11"; 00144 case 12: _ftregs_used += 1; return (char*)"TEXCOORD12"; 00145 case 13: _ftregs_used += 1; return (char*)"TEXCOORD13"; 00146 case 14: _ftregs_used += 1; return (char*)"TEXCOORD14"; 00147 case 15: _ftregs_used += 1; return (char*)"TEXCOORD15"; 00148 } 00149 switch (_fcregs_used) { 00150 case 0: _fcregs_used += 1; return (char*)"COLOR0"; 00151 case 1: _fcregs_used += 1; return (char*)"COLOR1"; 00152 case 2: _fcregs_used += 1; return (char*)"COLOR2"; 00153 case 3: _fcregs_used += 1; return (char*)"COLOR3"; 00154 case 4: _fcregs_used += 1; return (char*)"COLOR4"; 00155 case 5: _fcregs_used += 1; return (char*)"COLOR5"; 00156 case 6: _fcregs_used += 1; return (char*)"COLOR6"; 00157 case 7: _fcregs_used += 1; return (char*)"COLOR7"; 00158 case 8: _fcregs_used += 1; return (char*)"COLOR8"; 00159 case 9: _fcregs_used += 1; return (char*)"COLOR9"; 00160 case 10: _fcregs_used += 1; return (char*)"COLOR10"; 00161 case 11: _fcregs_used += 1; return (char*)"COLOR11"; 00162 case 12: _fcregs_used += 1; return (char*)"COLOR12"; 00163 case 13: _fcregs_used += 1; return (char*)"COLOR13"; 00164 case 14: _fcregs_used += 1; return (char*)"COLOR14"; 00165 case 15: _fcregs_used += 1; return (char*)"COLOR15"; 00166 } 00167 return (char*)"UNKNOWN"; 00168 } 00169 00170 //////////////////////////////////////////////////////////////////// 00171 // Function: ShaderGenerator::analyze_renderstate 00172 // Access: Protected 00173 // Description: Analyzes the RenderState prior to shader generation. 00174 // The results of the analysis are stored in instance 00175 // variables of the Shader Generator. 00176 //////////////////////////////////////////////////////////////////// 00177 void ShaderGenerator:: 00178 analyze_renderstate(const RenderState *rs) { 00179 clear_analysis(); 00180 00181 // verify_enforce_attrib_lock(); 00182 _state = rs; 00183 const AuxBitplaneAttrib *aux_bitplane = DCAST(AuxBitplaneAttrib, rs->get_attrib_def(AuxBitplaneAttrib::get_class_slot())); 00184 int outputs = aux_bitplane->get_outputs(); 00185 00186 // Decide whether or not we need alpha testing or alpha blending. 00187 00188 const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot())); 00189 if ((alpha_test->get_mode() != RenderAttrib::M_none)&& 00190 (alpha_test->get_mode() != RenderAttrib::M_always)) { 00191 _have_alpha_test = true; 00192 } 00193 const ColorBlendAttrib *color_blend = DCAST(ColorBlendAttrib, rs->get_attrib_def(ColorBlendAttrib::get_class_slot())); 00194 if (color_blend->get_mode() != ColorBlendAttrib::M_none) { 00195 _have_alpha_blend = true; 00196 } 00197 const TransparencyAttrib *transparency = DCAST(TransparencyAttrib, rs->get_attrib_def(TransparencyAttrib::get_class_slot())); 00198 if ((transparency->get_mode() == TransparencyAttrib::M_alpha)|| 00199 (transparency->get_mode() == TransparencyAttrib::M_dual)) { 00200 _have_alpha_blend = true; 00201 } 00202 00203 // Decide what to send to the framebuffer alpha, if anything. 00204 00205 if (outputs & AuxBitplaneAttrib::ABO_glow) { 00206 if (_have_alpha_blend) { 00207 _calc_primary_alpha = true; 00208 _out_primary_glow = false; 00209 _disable_alpha_write = true; 00210 } else if (_have_alpha_test) { 00211 _calc_primary_alpha = true; 00212 _out_primary_glow = true; 00213 _subsume_alpha_test = true; 00214 } else { 00215 _calc_primary_alpha = false; 00216 _out_primary_glow = true; 00217 } 00218 } else { 00219 if (_have_alpha_blend || _have_alpha_test) { 00220 _calc_primary_alpha = true; 00221 } 00222 } 00223 00224 // Determine what to put into the aux bitplane. 00225 00226 _out_aux_normal = (outputs & AuxBitplaneAttrib::ABO_aux_normal) ? true:false; 00227 _out_aux_glow = (outputs & AuxBitplaneAttrib::ABO_aux_glow) ? true:false; 00228 _out_aux_any = (_out_aux_normal || _out_aux_glow); 00229 00230 if (_out_aux_normal) { 00231 _need_eye_normal = true; 00232 } 00233 00234 // Count number of textures. 00235 00236 const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot())); 00237 _num_textures = texture->get_num_on_stages(); 00238 00239 // Determine whether or not vertex colors or flat colors are present. 00240 00241 const ColorAttrib *color = DCAST(ColorAttrib, rs->get_attrib_def(ColorAttrib::get_class_slot())); 00242 if (color->get_color_type() == ColorAttrib::T_vertex) { 00243 _vertex_colors = true; 00244 } else if (color->get_color_type() == ColorAttrib::T_flat) { 00245 _flat_colors = true; 00246 } 00247 00248 // Break out the lights by type. 00249 00250 _shadows = false; 00251 const LightAttrib *la = DCAST(LightAttrib, rs->get_attrib_def(LightAttrib::get_class_slot())); 00252 for (int i=0; i<la->get_num_on_lights(); i++) { 00253 NodePath light = la->get_on_light(i); 00254 nassertv(!light.is_empty()); 00255 PandaNode *light_obj = light.node(); 00256 nassertv(light_obj != (PandaNode *)NULL); 00257 00258 if (light_obj->get_type() == AmbientLight::get_class_type()) { 00259 _alights_np.push_back(light); 00260 _alights.push_back((AmbientLight*)light_obj); 00261 } 00262 else if (light_obj->get_type() == DirectionalLight::get_class_type()) { 00263 _dlights_np.push_back(light); 00264 _dlights.push_back((DirectionalLight*)light_obj); 00265 if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) { 00266 _shadows = true; 00267 } 00268 } 00269 else if (light_obj->get_type() == PointLight::get_class_type()) { 00270 _plights_np.push_back(light); 00271 _plights.push_back((PointLight*)light_obj); 00272 } 00273 else if (light_obj->get_type() == Spotlight::get_class_type()) { 00274 _slights_np.push_back(light); 00275 _slights.push_back((Spotlight*)light_obj); 00276 if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) { 00277 _shadows = true; 00278 } 00279 } 00280 } 00281 00282 // See if there is a normal map, height map, gloss map, or glow map. 00283 // Also check if anything has TexGen. 00284 00285 const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot())); 00286 for (int i=0; i<_num_textures; i++) { 00287 TextureStage *stage = texture->get_on_stage(i); 00288 TextureStage::Mode mode = stage->get_mode(); 00289 if ((mode == TextureStage::M_normal)||(mode == TextureStage::M_normal_height)) { 00290 _map_index_normal = i; 00291 } 00292 if ((mode == TextureStage::M_height)||(mode == TextureStage::M_normal_height)) { 00293 _map_index_height = i; 00294 } 00295 if ((mode == TextureStage::M_glow)||(mode == TextureStage::M_modulate_glow)) { 00296 _map_index_glow = i; 00297 } 00298 if ((mode == TextureStage::M_gloss)||(mode == TextureStage::M_modulate_gloss)) { 00299 _map_index_gloss = i; 00300 } 00301 if (mode == TextureStage::M_height) { 00302 _map_height_in_alpha = false; 00303 } 00304 if (mode == TextureStage::M_normal_height) { 00305 _map_height_in_alpha = true; 00306 } 00307 if (tex_gen->has_stage(stage)) { 00308 switch (tex_gen->get_mode(stage)) { 00309 case TexGenAttrib::M_world_position: 00310 _need_world_position = true; 00311 break; 00312 case TexGenAttrib::M_world_normal: 00313 _need_world_normal = true; 00314 break; 00315 case TexGenAttrib::M_eye_position: 00316 _need_eye_position = true; 00317 break; 00318 case TexGenAttrib::M_eye_normal: 00319 _need_eye_normal = true; 00320 break; 00321 } 00322 } 00323 } 00324 00325 // Determine whether lighting is needed. 00326 00327 if (la->get_num_on_lights() > 0) { 00328 _lighting = true; 00329 _need_eye_position = true; 00330 _need_eye_normal = true; 00331 } 00332 00333 // Find the material. 00334 00335 const MaterialAttrib *material = DCAST(MaterialAttrib, rs->get_attrib_def(MaterialAttrib::get_class_slot())); 00336 00337 if (!material->is_off()) { 00338 _material = material->get_material(); 00339 } else { 00340 _material = Material::get_default(); 00341 } 00342 00343 // Decide which material modes need to be calculated. 00344 00345 if (_lighting && (_alights.size() > 0)) { 00346 if (_material->has_ambient()) { 00347 Colorf a = _material->get_ambient(); 00348 if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) { 00349 _have_ambient = true; 00350 } 00351 } else { 00352 _have_ambient = true; 00353 } 00354 } 00355 00356 if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) { 00357 if (_material->has_diffuse()) { 00358 Colorf d = _material->get_diffuse(); 00359 if ((d[0]!=0.0)||(d[1]!=0.0)||(d[2]!=0.0)) { 00360 _have_diffuse = true; 00361 } 00362 } else { 00363 _have_diffuse = true; 00364 } 00365 } 00366 00367 if (_lighting && (_material->has_emission())) { 00368 Colorf e = _material->get_emission(); 00369 if ((e[0]!=0.0)||(e[1]!=0.0)||(e[2]!=0.0)) { 00370 _have_emission = true; 00371 } 00372 } 00373 00374 if (_lighting && (_dlights.size() + _plights.size() + _slights.size())) { 00375 if (_material->has_specular()) { 00376 Colorf s = _material->get_specular(); 00377 if ((s[0]!=0.0)||(s[1]!=0.0)||(s[2]!=0.0)) { 00378 _have_specular = true; 00379 } 00380 } else if (_map_index_gloss >= 0) { 00381 _have_specular = true; 00382 } 00383 } 00384 00385 // Decide whether to separate ambient and diffuse calculations. 00386 00387 if (_have_ambient && _have_diffuse) { 00388 if (_material->has_ambient()) { 00389 if (_material->has_diffuse()) { 00390 _separate_ambient_diffuse = _material->get_ambient() != _material->get_diffuse(); 00391 } else { 00392 _separate_ambient_diffuse = true; 00393 } 00394 } else { 00395 if (_material->has_diffuse()) { 00396 _separate_ambient_diffuse = true; 00397 } else { 00398 _separate_ambient_diffuse = false; 00399 } 00400 } 00401 } 00402 00403 const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); 00404 if (_lighting && 00405 (light_ramp->get_mode() != LightRampAttrib::LRT_identity)) { 00406 _separate_ambient_diffuse = true; 00407 } 00408 00409 // Do we want to use the ARB_shadow extension? 00410 // This also allows us to use hardware shadows / PCF. 00411 00412 _use_shadow_filter = _gsg->get_supports_shadow_filter(); 00413 00414 // Does the shader need material properties as input? 00415 00416 _need_material_props = 00417 (_have_ambient && (_material->has_ambient()))|| 00418 (_have_diffuse && (_material->has_diffuse()))|| 00419 (_have_emission && (_material->has_emission()))|| 00420 (_have_specular && (_material->has_specular())); 00421 00422 // Check for clip planes. 00423 00424 const ClipPlaneAttrib *clip_plane = DCAST(ClipPlaneAttrib, rs->get_attrib_def(ClipPlaneAttrib::get_class_slot())); 00425 _num_clip_planes = clip_plane->get_num_on_planes(); 00426 if (_num_clip_planes > 0) { 00427 _need_world_position = true; 00428 } 00429 00430 // Check for unimplemented features and issue warnings. 00431 const FogAttrib *fog = DCAST(FogAttrib, rs->get_attrib_def(FogAttrib::get_class_slot())); 00432 if (!fog->is_off()) { 00433 pgraph_cat.error() << "Shader Generator does not support Fog yet.\n"; 00434 } 00435 } 00436 00437 //////////////////////////////////////////////////////////////////// 00438 // Function: ShaderGenerator::clear_analysis 00439 // Access: Protected 00440 // Description: Called after analyze_renderstate to discard all 00441 // the results of the analysis. This is generally done 00442 // after shader generation is complete. 00443 //////////////////////////////////////////////////////////////////// 00444 void ShaderGenerator:: 00445 clear_analysis() { 00446 _vertex_colors = false; 00447 _flat_colors = false; 00448 _lighting = false; 00449 _shadows = false; 00450 _have_ambient = false; 00451 _have_diffuse = false; 00452 _have_emission = false; 00453 _have_specular = false; 00454 _separate_ambient_diffuse = false; 00455 _map_index_normal = -1; 00456 _map_index_glow = -1; 00457 _map_index_gloss = -1; 00458 _map_index_height = -1; 00459 _map_height_in_alpha = false; 00460 _calc_primary_alpha = false; 00461 _have_alpha_test = false; 00462 _have_alpha_blend = false; 00463 _subsume_alpha_test = false; 00464 _disable_alpha_write = false; 00465 _num_clip_planes = 0; 00466 _use_shadow_filter = false; 00467 _out_primary_glow = false; 00468 _out_aux_normal = false; 00469 _out_aux_glow = false; 00470 _out_aux_any = false; 00471 _material = (Material*)NULL; 00472 _need_material_props = false; 00473 _need_world_position = false; 00474 _need_world_normal = false; 00475 _need_eye_position = false; 00476 _need_eye_normal = false; 00477 _alights.clear(); 00478 _dlights.clear(); 00479 _plights.clear(); 00480 _slights.clear(); 00481 _alights_np.clear(); 00482 _dlights_np.clear(); 00483 _plights_np.clear(); 00484 _slights_np.clear(); 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: ShaderGenerator::create_shader_attrib 00489 // Access: Protected 00490 // Description: Creates a ShaderAttrib given a generated shader's 00491 // body. Also inserts the lights into the shader 00492 // attrib. 00493 //////////////////////////////////////////////////////////////////// 00494 CPT(RenderAttrib) ShaderGenerator:: 00495 create_shader_attrib(const string &txt) { 00496 PT(Shader) shader = Shader::make(txt); 00497 CPT(RenderAttrib) shattr = ShaderAttrib::make(); 00498 shattr=DCAST(ShaderAttrib, shattr)->set_shader(shader); 00499 if (_lighting) { 00500 for (int i=0; i<(int)_alights.size(); i++) { 00501 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("alight", i), _alights_np[i]); 00502 } 00503 for (int i=0; i<(int)_dlights.size(); i++) { 00504 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlight", i), _dlights_np[i]); 00505 if (_shadows && _dlights[i]->_shadow_caster) { 00506 PT(Texture) tex = update_shadow_buffer(_dlights_np[i]); 00507 if (tex == NULL) { 00508 pgraph_cat.error() << "Failed to create shadow buffer for DirectionalLight '" << _dlights[i]->get_name() << "'!\n"; 00509 } 00510 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("dlighttex", i), tex); 00511 } else { 00512 _dlights[i]->clear_shadow_buffers(); 00513 } 00514 } 00515 for (int i=0; i<(int)_plights.size(); i++) { 00516 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("plight", i), _plights_np[i]); 00517 } 00518 for (int i=0; i<(int)_slights.size(); i++) { 00519 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slight", i), _slights_np[i]); 00520 if (_shadows && _slights[i]->_shadow_caster) { 00521 PT(Texture) tex = update_shadow_buffer(_slights_np[i]); 00522 if (tex == NULL) { 00523 pgraph_cat.error() << "Failed to create shadow buffer for Spotlight '" << _slights[i]->get_name() << "'!\n"; 00524 } 00525 shattr=DCAST(ShaderAttrib, shattr)->set_shader_input(InternalName::make("slighttex", i), tex); 00526 } else { 00527 _slights[i]->clear_shadow_buffers(); 00528 } 00529 } 00530 } 00531 return shattr; 00532 } 00533 00534 //////////////////////////////////////////////////////////////////// 00535 // Function: ShaderGenerator::update_shadow_buffer 00536 // Access: Protected, Virtual 00537 // Description: Updates the depth buffer of the specified light, 00538 // if it is configured to cast shadows. 00539 // Only call this function for DirectionalLights 00540 // and Spotlights. Returns the depth texture. 00541 //////////////////////////////////////////////////////////////////// 00542 PT(Texture) ShaderGenerator:: 00543 update_shadow_buffer(NodePath light_np) { 00544 // Make sure everything is valid. 00545 nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || 00546 light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); 00547 PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); 00548 if (light == NULL || !light->_shadow_caster) { 00549 return NULL; 00550 } 00551 00552 // See if we already have a buffer. If not, create one. 00553 PT(Texture) tex; 00554 if (light->_sbuffers.count(_gsg) == 0) { 00555 // Nope, the light doesn't have a buffer for our GSG. Make one. 00556 tex = _gsg->make_shadow_buffer(light_np, _host); 00557 } else { 00558 // There's already a buffer - use that. 00559 tex = light->_sbuffers[_gsg]->get_texture(); 00560 } 00561 nassertr(tex != NULL, NULL); 00562 00563 return tex; 00564 } 00565 00566 //////////////////////////////////////////////////////////////////// 00567 // Function: ShaderGenerator::synthesize_shader 00568 // Access: Published, Virtual 00569 // Description: This is the routine that implements the next-gen 00570 // fixed function pipeline by synthesizing a shader. 00571 // It also takes care of setting up any buffers 00572 // needed to produce the requested effects. 00573 // 00574 // Currently supports: 00575 // - flat colors 00576 // - vertex colors 00577 // - lighting 00578 // - normal maps, but not multiple 00579 // - gloss maps, but not multiple 00580 // - glow maps, but not multiple 00581 // - materials, but not updates to materials 00582 // - 2D textures 00583 // - all texture stage modes, including combine modes 00584 // - color scale attrib 00585 // - light ramps (for cartoon shading) 00586 // - shadow mapping 00587 // - most texgen modes 00588 // - texmatrix 00589 // - 1D/2D/3D textures, cube textures 00590 // 00591 // Not yet supported: 00592 // - dot3_rgb and dot3_rgba combine modes 00593 // - fog 00594 // 00595 // Potential optimizations 00596 // - omit attenuation calculations if attenuation off 00597 // 00598 //////////////////////////////////////////////////////////////////// 00599 CPT(RenderAttrib) ShaderGenerator:: 00600 synthesize_shader(const RenderState *rs) { 00601 analyze_renderstate(rs); 00602 reset_register_allocator(); 00603 00604 pgraph_cat.info() << "Generating shader for render state " << rs << "\n"; 00605 00606 // These variables will hold the results of register allocation. 00607 00608 char *normal_vreg = 0; 00609 char *ntangent_vreg = 0; 00610 char *ntangent_freg = 0; 00611 char *nbinormal_vreg = 0; 00612 char *nbinormal_freg = 0; 00613 char *htangent_vreg = 0; 00614 char *hbinormal_vreg = 0; 00615 pvector<char *> texcoord_vreg; 00616 pvector<char *> texcoord_freg; 00617 pvector<char *> tslightvec_freg; 00618 char *world_position_freg = 0; 00619 char *world_normal_freg = 0; 00620 char *eye_position_freg = 0; 00621 char *eye_normal_freg = 0; 00622 00623 if (_vertex_colors) { 00624 _vcregs_used = 1; 00625 _fcregs_used = 1; 00626 } 00627 00628 // Generate the shader's text. 00629 00630 ostringstream text; 00631 00632 text << "//Cg\n"; 00633 00634 text << "void vshader(\n"; 00635 const TextureAttrib *texture = DCAST(TextureAttrib, rs->get_attrib_def(TextureAttrib::get_class_slot())); 00636 const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, rs->get_attrib_def(TexGenAttrib::get_class_slot())); 00637 for (int i=0; i<_num_textures; i++) { 00638 texcoord_vreg.push_back(alloc_vreg()); 00639 texcoord_freg.push_back(alloc_freg()); 00640 text << "\t in float4 vtx_texcoord" << i << " : " << texcoord_vreg[i] << ",\n"; 00641 text << "\t out float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n"; 00642 } 00643 if (_vertex_colors) { 00644 text << "\t in float4 vtx_color : COLOR,\n"; 00645 text << "\t out float4 l_color : COLOR,\n"; 00646 } 00647 if (_need_world_position || _need_world_normal) { 00648 text << "\t uniform float4x4 trans_model_to_world,\n"; 00649 } 00650 if (_need_world_position) { 00651 world_position_freg = alloc_freg(); 00652 text << "\t out float4 l_world_position : " << world_position_freg << ",\n"; 00653 } 00654 if (_need_world_normal) { 00655 world_normal_freg = alloc_freg(); 00656 text << "\t out float4 l_world_normal : " << world_normal_freg << ",\n"; 00657 } 00658 if (_need_eye_position) { 00659 text << "\t uniform float4x4 trans_model_to_view,\n"; 00660 eye_position_freg = alloc_freg(); 00661 text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n"; 00662 } 00663 if (_need_eye_normal) { 00664 eye_normal_freg = alloc_freg(); 00665 text << "\t uniform float4x4 tpose_view_to_model,\n"; 00666 text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n"; 00667 } 00668 if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) { 00669 normal_vreg = alloc_vreg(); 00670 text << "\t in float4 vtx_normal : " << normal_vreg << ",\n"; 00671 } 00672 if (_map_index_height >= 0) { 00673 htangent_vreg = alloc_vreg(); 00674 hbinormal_vreg = alloc_vreg(); 00675 if (_map_index_normal == _map_index_height) { 00676 ntangent_vreg = htangent_vreg; 00677 nbinormal_vreg = hbinormal_vreg; 00678 } 00679 text << "\t in float4 vtx_tangent" << _map_index_height << " : " << htangent_vreg << ",\n"; 00680 text << "\t in float4 vtx_binormal" << _map_index_height << " : " << hbinormal_vreg << ",\n"; 00681 text << "\t uniform float4 mspos_view,\n"; 00682 text << "\t out float3 l_eyevec,\n"; 00683 } 00684 if (_lighting) { 00685 if (_map_index_normal >= 0) { 00686 // If we had a height map and it used the same stage, that means we already have those inputs. 00687 if (_map_index_normal != _map_index_height) { 00688 ntangent_vreg = alloc_vreg(); 00689 nbinormal_vreg = alloc_vreg(); 00690 text << "\t in float4 vtx_tangent" << _map_index_normal << " : " << ntangent_vreg << ",\n"; 00691 text << "\t in float4 vtx_binormal" << _map_index_normal << " : " << nbinormal_vreg << ",\n"; 00692 } 00693 ntangent_freg = alloc_freg(); 00694 nbinormal_freg = alloc_freg(); 00695 text << "\t out float4 l_tangent : " << ntangent_freg << ",\n"; 00696 text << "\t out float4 l_binormal : " << nbinormal_freg << ",\n"; 00697 } 00698 if (_shadows) { 00699 for (int i=0; i<(int)_dlights.size(); i++) { 00700 if (_dlights[i]->_shadow_caster) { 00701 text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n"; 00702 text << "\t out float4 l_dlightcoord" << i << ",\n"; 00703 } 00704 } 00705 for (int i=0; i<(int)_slights.size(); i++) { 00706 if (_slights[i]->_shadow_caster) { 00707 text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n"; 00708 text << "\t out float4 l_slightcoord" << i << ",\n"; 00709 } 00710 } 00711 } 00712 } 00713 text << "\t float4 vtx_position : POSITION,\n"; 00714 text << "\t out float4 l_position : POSITION,\n"; 00715 text << "\t uniform float4x4 mat_modelproj\n"; 00716 text << ") {\n"; 00717 00718 text << "\t l_position = mul(mat_modelproj, vtx_position);\n"; 00719 if (_need_world_position) { 00720 text << "\t l_world_position = mul(trans_model_to_world, vtx_position);\n"; 00721 } 00722 if (_need_world_normal) { 00723 text << "\t l_world_normal = mul(trans_model_to_world, vtx_normal);\n"; 00724 } 00725 if (_need_eye_position) { 00726 text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n"; 00727 } 00728 if (_need_eye_normal) { 00729 text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal.xyz);\n"; 00730 text << "\t l_eye_normal.w = 0;\n"; 00731 } 00732 for (int i=0; i<_num_textures; i++) { 00733 if (!tex_gen->has_stage(texture->get_on_stage(i))) { 00734 text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n"; 00735 } 00736 } 00737 if (_vertex_colors) { 00738 text << "\t l_color = vtx_color;\n"; 00739 } 00740 if (_lighting && (_map_index_normal >= 0)) { 00741 text << "\t l_tangent.xyz = mul((float3x3)tpose_view_to_model, vtx_tangent" << _map_index_normal << ".xyz);\n"; 00742 text << "\t l_tangent.w = 0;\n"; 00743 text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n"; 00744 text << "\t l_binormal.w = 0;\n"; 00745 } 00746 if (_shadows) { 00747 text << "\t float4x4 biasmat = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};\n"; 00748 for (int i=0; i<(int)_dlights.size(); i++) { 00749 if (_dlights[i]->_shadow_caster) { 00750 text << "\t l_dlightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_dlight" << i << ", vtx_position));\n"; 00751 } 00752 } 00753 for (int i=0; i<(int)_slights.size(); i++) { 00754 if (_slights[i]->_shadow_caster) { 00755 text << "\t l_slightcoord" << i << " = mul(biasmat, mul(trans_model_to_clip_of_slight" << i << ", vtx_position));\n"; 00756 } 00757 } 00758 } 00759 if (_map_index_height >= 0) { 00760 text << "\t float3 eyedir = mspos_view.xyz - vtx_position.xyz;\n"; 00761 text << "\t l_eyevec.x = dot(vtx_tangent" << _map_index_height << ".xyz, eyedir);\n"; 00762 text << "\t l_eyevec.y = dot(vtx_binormal" << _map_index_height << ".xyz, eyedir);\n"; 00763 text << "\t l_eyevec.z = dot(vtx_normal.xyz, eyedir);\n"; 00764 text << "\t l_eyevec = normalize(l_eyevec);\n"; 00765 } 00766 text << "}\n\n"; 00767 00768 text << "void fshader(\n"; 00769 if (_need_world_position) { 00770 text << "\t in float4 l_world_position : " << world_position_freg << ",\n"; 00771 } 00772 if (_need_world_normal) { 00773 text << "\t in float4 l_world_normal : " << world_normal_freg << ",\n"; 00774 } 00775 if (_need_eye_position) { 00776 text << "\t in float4 l_eye_position : " << eye_position_freg << ",\n"; 00777 } 00778 if (_need_eye_normal) { 00779 text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n"; 00780 } 00781 const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot())); 00782 for (int i=0; i<_num_textures; i++) { 00783 TextureStage *stage = texture->get_on_stage(i); 00784 Texture *tex = texture->get_on_texture(stage); 00785 nassertr(tex != NULL, NULL); 00786 text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n"; 00787 if (!tex_gen->has_stage(stage)) { 00788 text << "\t in float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n"; 00789 } 00790 if (tex_matrix->has_stage(stage)) { 00791 text << "\t uniform float4x4 texmat_" << i << ",\n"; 00792 } 00793 } 00794 if (_lighting && (_map_index_normal >= 0)) { 00795 text << "\t in float3 l_tangent : " << ntangent_freg << ",\n"; 00796 text << "\t in float3 l_binormal : " << nbinormal_freg << ",\n"; 00797 } 00798 if (_lighting) { 00799 for (int i=0; i<(int)_alights.size(); i++) { 00800 text << "\t uniform float4 alight_alight" << i << ",\n"; 00801 } 00802 for (int i=0; i<(int)_dlights.size(); i++) { 00803 text << "\t uniform float4x4 dlight_dlight" << i << "_rel_view,\n"; 00804 if (_shadows && _dlights[i]->_shadow_caster) { 00805 if (_use_shadow_filter) { 00806 text << "\t uniform sampler2DShadow k_dlighttex" << i << ",\n"; 00807 } else { 00808 text << "\t uniform sampler2D k_dlighttex" << i << ",\n"; 00809 } 00810 text << "\t float4 l_dlightcoord" << i << ",\n"; 00811 } 00812 } 00813 for (int i=0; i<(int)_plights.size(); i++) { 00814 text << "\t uniform float4x4 plight_plight" << i << "_rel_view,\n"; 00815 } 00816 for (int i=0; i<(int)_slights.size(); i++) { 00817 text << "\t uniform float4x4 slight_slight" << i << "_rel_view,\n"; 00818 text << "\t uniform float4 satten_slight" << i << ",\n"; 00819 if (_shadows && _slights[i]->_shadow_caster) { 00820 if (_use_shadow_filter) { 00821 text << "\t uniform sampler2DShadow k_slighttex" << i << ",\n"; 00822 } else { 00823 text << "\t uniform sampler2D k_slighttex" << i << ",\n"; 00824 } 00825 text << "\t float4 l_slightcoord" << i << ",\n"; 00826 } 00827 } 00828 if (_need_material_props) { 00829 text << "\t uniform float4x4 attr_material,\n"; 00830 } 00831 if (_have_specular) { 00832 if (_material->get_local()) { 00833 text << "\t uniform float4 mspos_view,\n"; 00834 } else { 00835 text << "\t uniform float4 row1_view_to_model,\n"; 00836 } 00837 } 00838 } 00839 if (_map_index_height >= 0) { 00840 text << "\t float3 l_eyevec,\n"; 00841 } 00842 if (_out_aux_any) { 00843 text << "\t out float4 o_aux : COLOR1,\n"; 00844 } 00845 text << "\t out float4 o_color : COLOR0,\n"; 00846 if (_vertex_colors) { 00847 text << "\t in float4 l_color : COLOR,\n"; 00848 } else { 00849 text << "\t uniform float4 attr_color,\n"; 00850 } 00851 for (int i=0; i<_num_clip_planes; ++i) { 00852 text << "\t uniform float4 clipplane_" << i << ",\n"; 00853 } 00854 text << "\t uniform float4 attr_colorscale\n"; 00855 text << ") {\n"; 00856 // Clipping first! 00857 for (int i=0; i<_num_clip_planes; ++i) { 00858 text << "\t if (l_world_position.x * clipplane_" << i << ".x + l_world_position.y "; 00859 text << "* clipplane_" << i << ".y + l_world_position.z * clipplane_" << i << ".z + clipplane_" << i << ".w <= 0) {\n"; 00860 text << "\t discard;\n"; 00861 text << "\t }\n"; 00862 } 00863 text << "\t float4 result;\n"; 00864 if (_out_aux_any) { 00865 text << "\t o_aux = float4(0,0,0,0);\n"; 00866 } 00867 // Now generate any texture coordinates according to TexGenAttrib. If it has a TexMatrixAttrib, also transform them. 00868 for (int i=0; i<_num_textures; i++) { 00869 TextureStage *stage = texture->get_on_stage(i); 00870 if (tex_gen != NULL && tex_gen->has_stage(stage)) { 00871 switch (tex_gen->get_mode(stage)) { 00872 case TexGenAttrib::M_world_position: 00873 text << "\t float4 l_texcoord" << i << " = l_world_position;\n"; 00874 break; 00875 case TexGenAttrib::M_world_normal: 00876 text << "\t float4 l_texcoord" << i << " = l_world_normal;\n"; 00877 break; 00878 case TexGenAttrib::M_eye_position: 00879 text << "\t float4 l_texcoord" << i << " = l_eye_position;\n"; 00880 break; 00881 case TexGenAttrib::M_eye_normal: 00882 text << "\t float4 l_texcoord" << i << " = l_eye_normal;\n"; 00883 text << "\t l_texcoord" << i << ".w = 1.0f;\n"; 00884 break; 00885 default: 00886 pgraph_cat.error() << "Unsupported TexGenAttrib mode\n"; 00887 text << "\t float4 l_texcoord" << i << " = float4(0, 0, 0, 0);\n"; 00888 } 00889 } 00890 if (tex_matrix != NULL && tex_matrix->has_stage(stage)) { 00891 text << "\t l_texcoord" << i << " = mul(texmat_" << i << ", l_texcoord" << i << ");\n"; 00892 text << "\t l_texcoord" << i << ".xyz /= l_texcoord" << i << ".w;\n"; 00893 } 00894 } 00895 text << "\t // Fetch all textures.\n"; 00896 if (_map_index_height >= 0 && parallax_mapping_samples > 0) { 00897 Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height)); 00898 nassertr(tex != NULL, NULL); 00899 text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type()); 00900 text << "(tex_" << _map_index_height << ", l_texcoord" << _map_index_height << "."; 00901 switch(tex->get_texture_type()) { 00902 case Texture::TT_cube_map: 00903 case Texture::TT_3d_texture: text << "xyz"; break; 00904 case Texture::TT_2d_texture: text << "xy"; break; 00905 case Texture::TT_1d_texture: text << "x"; break; 00906 } 00907 text << ");\n\t float3 parallax_offset = l_eyevec.xyz * (tex" << _map_index_height; 00908 if (_map_height_in_alpha) { 00909 text << ".aaa"; 00910 } else { 00911 text << ".rgb"; 00912 } 00913 text << " * 2.0 - 1.0) * " << parallax_mapping_scale << ";\n"; 00914 // Additional samples 00915 for (int i=0; i<parallax_mapping_samples-1; i++) { 00916 text << "\t parallax_offset = l_eyevec.xyz * (parallax_offset + (tex" << _map_index_height; 00917 if (_map_height_in_alpha) { 00918 text << ".aaa"; 00919 } else { 00920 text << ".rgb"; 00921 } 00922 text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n"; 00923 } 00924 } 00925 for (int i=0; i<_num_textures; i++) { 00926 if (i != _map_index_height) { 00927 Texture *tex = texture->get_on_texture(texture->get_on_stage(i)); 00928 nassertr(tex != NULL, NULL); 00929 // Parallax mapping pushes the texture coordinates of the other textures away from the camera. 00930 if (_map_index_height >= 0 && parallax_mapping_samples > 0) { 00931 text << "\t l_texcoord" << i << ".xyz -= parallax_offset;\n"; 00932 } 00933 text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type()); 00934 text << "(tex_" << i << ", l_texcoord" << i << "."; 00935 switch(tex->get_texture_type()) { 00936 case Texture::TT_cube_map: 00937 case Texture::TT_3d_texture: text << "xyz"; break; 00938 case Texture::TT_2d_texture: text << "xy"; break; 00939 case Texture::TT_1d_texture: text << "x"; break; 00940 } 00941 text << ");\n"; 00942 } 00943 } 00944 if (_lighting) { 00945 if (_map_index_normal >= 0) { 00946 text << "\t // Translate tangent-space normal in map to view-space.\n"; 00947 text << "\t float3 tsnormal = ((float3)tex" << _map_index_normal << " * 2) - 1;\n"; 00948 text << "\t l_eye_normal.xyz *= tsnormal.z;\n"; 00949 text << "\t l_eye_normal.xyz += l_tangent * tsnormal.x;\n"; 00950 text << "\t l_eye_normal.xyz += l_binormal * tsnormal.y;\n"; 00951 text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n"; 00952 } else { 00953 text << "\t // Correct the surface normal for interpolation effects\n"; 00954 text << "\t l_eye_normal.xyz = normalize(l_eye_normal.xyz);\n"; 00955 } 00956 } 00957 if (_out_aux_normal) { 00958 text << "\t // Output the camera-space surface normal\n"; 00959 text << "\t o_aux.rgb = (l_eye_normal.xyz*0.5) + float3(0.5,0.5,0.5);\n"; 00960 } 00961 if (_lighting) { 00962 text << "\t // Begin view-space light calculations\n"; 00963 text << "\t float ldist,lattenv,langle;\n"; 00964 text << "\t float4 lcolor,lspec,lvec,lpoint,latten,ldir,leye,lhalf;"; 00965 if (_shadows) { 00966 text << "\t float lshad;\n"; 00967 } 00968 if (_separate_ambient_diffuse) { 00969 if (_have_ambient) { 00970 text << "\t float4 tot_ambient = float4(0,0,0,0);\n"; 00971 } 00972 if (_have_diffuse) { 00973 text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; 00974 } 00975 } else { 00976 if (_have_ambient || _have_diffuse) { 00977 text << "\t float4 tot_diffuse = float4(0,0,0,0);\n"; 00978 } 00979 } 00980 if (_have_specular) { 00981 text << "\t float4 tot_specular = float4(0,0,0,0);\n"; 00982 if (_material->has_specular()) { 00983 text << "\t float shininess = attr_material[3].w;\n"; 00984 } else { 00985 text << "\t float shininess = 50; // no shininess specified, using default\n"; 00986 } 00987 } 00988 for (int i=0; i<(int)_alights.size(); i++) { 00989 text << "\t // Ambient Light " << i << "\n"; 00990 text << "\t lcolor = alight_alight" << i << ";\n"; 00991 if (_separate_ambient_diffuse && _have_ambient) { 00992 text << "\t tot_ambient += lcolor;\n"; 00993 } else if(_have_diffuse) { 00994 text << "\t tot_diffuse += lcolor;\n"; 00995 } 00996 } 00997 for (int i=0; i<(int)_dlights.size(); i++) { 00998 text << "\t // Directional Light " << i << "\n"; 00999 text << "\t lcolor = dlight_dlight" << i << "_rel_view[0];\n"; 01000 text << "\t lspec = dlight_dlight" << i << "_rel_view[1];\n"; 01001 text << "\t lvec = dlight_dlight" << i << "_rel_view[2];\n"; 01002 text << "\t lcolor *= saturate(dot(l_eye_normal.xyz, lvec.xyz));\n"; 01003 if (_shadows && _dlights[i]->_shadow_caster) { 01004 if (_use_shadow_filter) { 01005 text << "\t lshad = shadow2DProj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r;\n"; 01006 } else { 01007 text << "\t lshad = tex2Dproj(k_dlighttex" << i << ", l_dlightcoord" << i << ").r > l_dlightcoord" << i << ".z / l_dlightcoord" << i << ".w;\n"; 01008 } 01009 text << "\t lcolor *= lshad;\n"; 01010 text << "\t lspec *= lshad;\n"; 01011 } 01012 if (_have_diffuse) { 01013 text << "\t tot_diffuse += lcolor;\n"; 01014 } 01015 if (_have_specular) { 01016 if (_material->get_local()) { 01017 text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n"; 01018 } else { 01019 text << "\t lhalf = dlight_dlight" << i << "_rel_view[3];\n"; 01020 } 01021 text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n"; 01022 text << "\t tot_specular += lspec;\n"; 01023 } 01024 } 01025 for (int i=0; i<(int)_plights.size(); i++) { 01026 text << "\t // Point Light " << i << "\n"; 01027 text << "\t lcolor = plight_plight" << i << "_rel_view[0];\n"; 01028 text << "\t lspec = plight_plight" << i << "_rel_view[1];\n"; 01029 text << "\t lpoint = plight_plight" << i << "_rel_view[2];\n"; 01030 text << "\t latten = plight_plight" << i << "_rel_view[3];\n"; 01031 text << "\t lvec = lpoint - l_eye_position;\n"; 01032 text << "\t ldist = length(float3(lvec));\n"; 01033 text << "\t lvec /= ldist;\n"; 01034 text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n"; 01035 text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n"; 01036 if (_have_diffuse) { 01037 text << "\t tot_diffuse += lcolor;\n"; 01038 } 01039 if (_have_specular) { 01040 if (_material->get_local()) { 01041 text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n"; 01042 } else { 01043 text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n"; 01044 } 01045 text << "\t lspec *= lattenv;\n"; 01046 text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n"; 01047 text << "\t tot_specular += lspec;\n"; 01048 } 01049 } 01050 for (int i=0; i<(int)_slights.size(); i++) { 01051 text << "\t // Spot Light " << i << "\n"; 01052 text << "\t lcolor = slight_slight" << i << "_rel_view[0];\n"; 01053 text << "\t lspec = slight_slight" << i << "_rel_view[1];\n"; 01054 text << "\t lpoint = slight_slight" << i << "_rel_view[2];\n"; 01055 text << "\t ldir = slight_slight" << i << "_rel_view[3];\n"; 01056 text << "\t latten = satten_slight" << i << ";\n"; 01057 text << "\t lvec = lpoint - l_eye_position;\n"; 01058 text << "\t ldist = length(float3(lvec));\n"; 01059 text << "\t lvec /= ldist;\n"; 01060 text << "\t langle = saturate(dot(ldir.xyz, lvec.xyz));\n"; 01061 text << "\t lattenv = 1/(latten.x + latten.y*ldist + latten.z*ldist*ldist);\n"; 01062 text << "\t lattenv *= pow(langle, latten.w);\n"; 01063 text << "\t if (langle < ldir.w) lattenv = 0;\n"; 01064 text << "\t lcolor *= lattenv * saturate(dot(l_eye_normal.xyz, lvec.xyz));\n"; 01065 if (_shadows && _slights[i]->_shadow_caster) { 01066 if (_use_shadow_filter) { 01067 text << "\t lshad = shadow2DProj(k_slighttex" << i << ", l_slightcoord" << i << ").r;\n"; 01068 } else { 01069 text << "\t lshad = tex2Dproj(k_slighttex" << i << ", l_slightcoord" << i << ").r > l_slightcoord" << i << ".z / l_slightcoord" << i << ".w;\n"; 01070 } 01071 text << "\t lcolor *= lshad;\n"; 01072 text << "\t lspec *= lshad;\n"; 01073 } 01074 01075 if (_have_diffuse) { 01076 text << "\t tot_diffuse += lcolor;\n"; 01077 } 01078 if (_have_specular) { 01079 if (_material->get_local()) { 01080 text << "\t lhalf = normalize(lvec - normalize(l_eye_position));\n"; 01081 } else { 01082 text << "\t lhalf = normalize(lvec - float4(0,1,0,0));\n"; 01083 } 01084 text << "\t lspec *= lattenv;\n"; 01085 text << "\t lspec *= pow(saturate(dot(l_eye_normal.xyz, lhalf.xyz)), shininess);\n"; 01086 text << "\t tot_specular += lspec;\n"; 01087 } 01088 } 01089 01090 const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); 01091 switch (light_ramp->get_mode()) { 01092 case LightRampAttrib::LRT_single_threshold: 01093 { 01094 float t = light_ramp->get_threshold(0); 01095 float l0 = light_ramp->get_level(0); 01096 text << "\t // Single-threshold light ramp\n"; 01097 text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; 01098 text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n"; 01099 text << "\t tot_diffuse = tot_diffuse * lr_scale;\n"; 01100 break; 01101 } 01102 case LightRampAttrib::LRT_double_threshold: 01103 { 01104 float t0 = light_ramp->get_threshold(0); 01105 float t1 = light_ramp->get_threshold(1); 01106 float l0 = light_ramp->get_level(0); 01107 float l1 = light_ramp->get_level(1); 01108 float l2 = light_ramp->get_level(2); 01109 text << "\t // Double-threshold light ramp\n"; 01110 text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; 01111 text << "\t float lr_out = " << l0 << "\n"; 01112 text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n"; 01113 text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n"; 01114 text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n"; 01115 break; 01116 } 01117 } 01118 text << "\t // Begin view-space light summation\n"; 01119 if (_have_emission) { 01120 if (_map_index_glow >= 0) { 01121 text << "\t result = attr_material[2] * saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n"; 01122 } else { 01123 text << "\t result = attr_material[2];\n"; 01124 } 01125 } else { 01126 if (_map_index_glow >= 0) { 01127 text << "\t result = saturate(2 * (tex" << _map_index_glow << ".a - 0.5));\n"; 01128 } else { 01129 text << "\t result = float4(0,0,0,0);\n"; 01130 } 01131 } 01132 if ((_have_ambient)&&(_separate_ambient_diffuse)) { 01133 if (_material->has_ambient()) { 01134 text << "\t result += tot_ambient * attr_material[0];\n"; 01135 } else if (_vertex_colors) { 01136 text << "\t result += tot_ambient * l_color;\n"; 01137 } else if (_flat_colors) { 01138 text << "\t result += tot_ambient * attr_color;\n"; 01139 } else { 01140 text << "\t result += tot_ambient;\n"; 01141 } 01142 } 01143 if (_have_diffuse) { 01144 if (_material->has_diffuse()) { 01145 text << "\t result += tot_diffuse * attr_material[1];\n"; 01146 } else if (_vertex_colors) { 01147 text << "\t result += tot_diffuse * l_color;\n"; 01148 } else if (_flat_colors) { 01149 text << "\t result += tot_diffuse * attr_color;\n"; 01150 } else { 01151 text << "\t result += tot_diffuse;\n"; 01152 } 01153 } 01154 if (light_ramp->get_mode() == LightRampAttrib::LRT_default) { 01155 text << "\t result = saturate(result);\n"; 01156 } 01157 text << "\t // End view-space light calculations\n"; 01158 01159 // Combine in alpha, which bypasses lighting calculations. 01160 // Use of lerp here is a workaround for a radeon driver bug. 01161 if (_calc_primary_alpha) { 01162 if (_vertex_colors) { 01163 text << "\t result.a = l_color.a;\n"; 01164 } else if (_flat_colors) { 01165 text << "\t result.a = attr_color.a;\n"; 01166 } else { 01167 text << "\t result.a = 1;\n"; 01168 } 01169 } 01170 } else { 01171 if (_vertex_colors) { 01172 text << "\t result = l_color;\n"; 01173 } else if (_flat_colors) { 01174 text << "\t result = attr_color;\n"; 01175 } else { 01176 text << "\t result = float4(1,1,1,1);\n"; 01177 } 01178 } 01179 01180 // Loop first to see if something is using primary_color or last_saved_result. 01181 bool have_saved_result = false; 01182 bool have_primary_color = false; 01183 for (int i=0; i<_num_textures; i++) { 01184 TextureStage *stage = texture->get_on_stage(i); 01185 if (stage->get_mode() != TextureStage::M_combine) continue; 01186 if (stage->uses_primary_color() && !have_primary_color) { 01187 text << "\t float4 primary_color = result;\n"; 01188 have_primary_color = true; 01189 } 01190 if (stage->uses_last_saved_result() && !have_saved_result) { 01191 text << "\t float4 last_saved_result = result;\n"; 01192 have_saved_result = true; 01193 } 01194 } 01195 01196 // Now loop through the textures to compose our magic blending formulas. 01197 for (int i=0; i<_num_textures; i++) { 01198 TextureStage *stage = texture->get_on_stage(i); 01199 switch (stage->get_mode()) { 01200 case TextureStage::M_modulate: 01201 case TextureStage::M_modulate_glow: 01202 case TextureStage::M_modulate_gloss: 01203 text << "\t result *= tex" << i << ";\n"; 01204 break; 01205 case TextureStage::M_decal: 01206 text << "\t result.rgb = lerp(result, tex" << i << ", tex" << i << ".a).rgb;\n"; 01207 break; 01208 case TextureStage::M_blend: { 01209 LVecBase4f c = stage->get_color(); 01210 text << "\t result.rgb = lerp(result, tex" << i << " * float4(" 01211 << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << "), tex" << i << ".r).rgb;\n"; 01212 break; } 01213 case TextureStage::M_replace: 01214 text << "\t result = tex" << i << ";\n"; 01215 break; 01216 case TextureStage::M_add: 01217 text << "\t result.rgb += tex" << i << ".rgb;\n"; 01218 if (_calc_primary_alpha) { 01219 text << "\t result.a *= tex" << i << ".a;\n"; 01220 } 01221 break; 01222 case TextureStage::M_combine: 01223 text << "\t result.rgb = "; 01224 if (stage->get_combine_rgb_mode() != TextureStage::CM_undefined) { 01225 text << combine_mode_as_string(stage, stage->get_combine_rgb_mode(), false, i); 01226 } else { 01227 text << "tex" << i << ".rgb"; 01228 } 01229 if (stage->get_rgb_scale() != 1) { 01230 text << " * " << stage->get_rgb_scale(); 01231 } 01232 text << ";\n\t result.a = "; 01233 if (stage->get_combine_alpha_mode() != TextureStage::CM_undefined) { 01234 text << combine_mode_as_string(stage, stage->get_combine_alpha_mode(), true, i); 01235 } else { 01236 text << "tex" << i << ".a"; 01237 } 01238 if (stage->get_alpha_scale() != 1) { 01239 text << " * " << stage->get_alpha_scale(); 01240 } 01241 text << ";\n"; 01242 break; 01243 case TextureStage::M_blend_color_scale: 01244 text << "\t result.rgb = lerp(result, tex" << i << " * attr_colorscale, tex" << i << ".r).rgb;\n"; 01245 break; 01246 default: 01247 break; 01248 } 01249 if (stage->get_saved_result() && have_saved_result) { 01250 text << "\t last_saved_result = result;\n"; 01251 } 01252 } 01253 // Apply the color scale. 01254 text << "\t result *= attr_colorscale;\n"; 01255 01256 if (_subsume_alpha_test) { 01257 const AlphaTestAttrib *alpha_test = DCAST(AlphaTestAttrib, rs->get_attrib_def(AlphaTestAttrib::get_class_slot())); 01258 text << "\t // Shader includes alpha test:\n"; 01259 double ref = alpha_test->get_reference_alpha(); 01260 switch (alpha_test->get_mode()) { 01261 case RenderAttrib::M_never: text<<"\t discard;\n"; 01262 case RenderAttrib::M_less: text<<"\t if (result.a >= "<<ref<<") discard;\n"; 01263 case RenderAttrib::M_equal: text<<"\t if (result.a != "<<ref<<") discard;\n"; 01264 case RenderAttrib::M_less_equal: text<<"\t if (result.a > "<<ref<<") discard;\n"; 01265 case RenderAttrib::M_greater: text<<"\t if (result.a <= "<<ref<<") discard;\n"; 01266 case RenderAttrib::M_not_equal: text<<"\t if (result.a == "<<ref<<") discard;\n"; 01267 case RenderAttrib::M_greater_equal: text<<"\t if (result.a < "<<ref<<") discard;\n"; 01268 } 01269 } 01270 01271 if (_out_primary_glow) { 01272 if (_map_index_glow >= 0) { 01273 text << "\t result.a = tex" << _map_index_glow << ".a;\n"; 01274 } else { 01275 text << "\t result.a = 0.5;\n"; 01276 } 01277 } 01278 if (_out_aux_glow) { 01279 if (_map_index_glow >= 0) { 01280 text << "\t o_aux.a = tex" << _map_index_glow << ".a;\n"; 01281 } else { 01282 text << "\t o_aux.a = 0.5;\n"; 01283 } 01284 } 01285 01286 if (_lighting) { 01287 if (_have_specular) { 01288 if (_material->has_specular()) { 01289 text << "\t tot_specular *= attr_material[3];\n"; 01290 } 01291 if (_map_index_gloss >= 0) { 01292 text << "\t tot_specular *= tex" << _map_index_gloss << ".a;\n"; 01293 } 01294 text << "\t result.rgb = result.rgb + tot_specular.rgb;\n"; 01295 } 01296 } 01297 01298 const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); 01299 switch (light_ramp->get_mode()) { 01300 case LightRampAttrib::LRT_hdr0: 01301 text << "\t result.rgb = (result*result*result + result*result + result) / (result*result*result + result*result + result + 1);\n"; 01302 break; 01303 case LightRampAttrib::LRT_hdr1: 01304 text << "\t result.rgb = (result*result + result) / (result*result + result + 1);\n"; 01305 break; 01306 case LightRampAttrib::LRT_hdr2: 01307 text << "\t result.rgb = result / (result + 1);\n"; 01308 break; 01309 default: break; 01310 } 01311 01312 // The multiply is a workaround for a radeon driver bug. 01313 // It's annoying as heck, since it produces an extra instruction. 01314 text << "\t o_color = result * 1.000001;\n"; 01315 if (_subsume_alpha_test) { 01316 text << "\t // Shader subsumes normal alpha test.\n"; 01317 } 01318 if (_disable_alpha_write) { 01319 text << "\t // Shader disables alpha write.\n"; 01320 } 01321 text << "}\n"; 01322 01323 // Insert the shader into the shader attrib. 01324 CPT(RenderAttrib) shattr = create_shader_attrib(text.str()); 01325 if (_subsume_alpha_test) { 01326 shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_subsume_alpha_test, true); 01327 } 01328 if (_disable_alpha_write) { 01329 shattr=DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_disable_alpha_write, true); 01330 } 01331 clear_analysis(); 01332 reset_register_allocator(); 01333 return shattr; 01334 } 01335 01336 //////////////////////////////////////////////////////////////////// 01337 // Function: ShaderGenerator::combine_mode_as_string 01338 // Access: Protected, Static 01339 // Description: This 'synthesizes' a combine mode into a string. 01340 //////////////////////////////////////////////////////////////////// 01341 const string ShaderGenerator:: 01342 combine_mode_as_string(CPT(TextureStage) stage, TextureStage::CombineMode c_mode, bool alpha, short texindex) { 01343 ostringstream text; 01344 switch (c_mode) { 01345 case TextureStage::CM_modulate: 01346 text << combine_source_as_string(stage, 0, alpha, alpha, texindex); 01347 text << " * "; 01348 text << combine_source_as_string(stage, 1, alpha, alpha, texindex); 01349 break; 01350 case TextureStage::CM_add: 01351 text << combine_source_as_string(stage, 0, alpha, alpha, texindex); 01352 text << " + "; 01353 text << combine_source_as_string(stage, 1, alpha, alpha, texindex); 01354 break; 01355 case TextureStage::CM_add_signed: 01356 pgraph_cat.error() << "TextureStage::CombineMode ADD_SIGNED not yet supported in per-pixel mode.\n"; 01357 break; 01358 case TextureStage::CM_interpolate: 01359 text << "lerp("; 01360 text << combine_source_as_string(stage, 1, alpha, alpha, texindex); 01361 text << ", "; 01362 text << combine_source_as_string(stage, 0, alpha, alpha, texindex); 01363 text << ", "; 01364 text << combine_source_as_string(stage, 2, alpha, true, texindex); 01365 text << ")"; 01366 break; 01367 case TextureStage::CM_subtract: 01368 text << combine_source_as_string(stage, 0, alpha, alpha, texindex); 01369 text << " + "; 01370 text << combine_source_as_string(stage, 1, alpha, alpha, texindex); 01371 break; 01372 case TextureStage::CM_dot3_rgb: 01373 pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGB not yet supported in per-pixel mode.\n"; 01374 break; 01375 case TextureStage::CM_dot3_rgba: 01376 pgraph_cat.error() << "TextureStage::CombineMode DOT3_RGBA not yet supported in per-pixel mode.\n"; 01377 break; 01378 case TextureStage::CM_replace: 01379 default: // Not sure if this is correct as default value. 01380 text << combine_source_as_string(stage, 0, alpha, alpha, texindex); 01381 break; 01382 } 01383 return text.str(); 01384 } 01385 01386 //////////////////////////////////////////////////////////////////// 01387 // Function: ShaderGenerator::combine_source_as_string 01388 // Access: Protected, Static 01389 // Description: This 'synthesizes' a combine source into a string. 01390 //////////////////////////////////////////////////////////////////// 01391 const string ShaderGenerator:: 01392 combine_source_as_string(CPT(TextureStage) stage, short num, bool alpha, bool single_value, short texindex) { 01393 TextureStage::CombineSource c_src = TextureStage::CS_undefined; 01394 TextureStage::CombineOperand c_op = TextureStage::CO_undefined; 01395 if (alpha) { 01396 switch (num) { 01397 case 0: 01398 c_src = stage->get_combine_alpha_source0(); 01399 c_op = stage->get_combine_alpha_operand0(); 01400 break; 01401 case 1: 01402 c_src = stage->get_combine_alpha_source1(); 01403 c_op = stage->get_combine_alpha_operand1(); 01404 break; 01405 case 2: 01406 c_src = stage->get_combine_alpha_source2(); 01407 c_op = stage->get_combine_alpha_operand2(); 01408 break; 01409 } 01410 } else { 01411 switch (num) { 01412 case 0: 01413 c_src = stage->get_combine_rgb_source0(); 01414 c_op = stage->get_combine_rgb_operand0(); 01415 break; 01416 case 1: 01417 c_src = stage->get_combine_rgb_source1(); 01418 c_op = stage->get_combine_rgb_operand1(); 01419 break; 01420 case 2: 01421 c_src = stage->get_combine_rgb_source2(); 01422 c_op = stage->get_combine_rgb_operand2(); 01423 break; 01424 } 01425 } 01426 ostringstream csource; 01427 if (c_op == TextureStage::CO_one_minus_src_color || 01428 c_op == TextureStage::CO_one_minus_src_alpha) { 01429 csource << "1.0f - "; 01430 } 01431 switch (c_src) { 01432 case TextureStage::CS_texture: 01433 csource << "tex" << texindex; 01434 break; 01435 case TextureStage::CS_constant: { 01436 LVecBase4f c = stage->get_color(); 01437 csource << "float4(" << c[0] << ", " << c[1] << ", " << c[2] << ", " << c[3] << ")"; 01438 break; } 01439 case TextureStage::CS_primary_color: 01440 csource << "primary_color"; 01441 break; 01442 case TextureStage::CS_previous: 01443 csource << "result"; 01444 break; 01445 case TextureStage::CS_constant_color_scale: 01446 csource << "attr_colorscale"; 01447 break; 01448 case TextureStage::CS_last_saved_result: 01449 csource << "last_saved_result"; 01450 break; 01451 } 01452 if (c_op == TextureStage::CO_src_color || c_op == TextureStage::CO_one_minus_src_color) { 01453 if (single_value) { 01454 // Let's take the red channel. 01455 csource << ".r"; 01456 } else { 01457 csource << ".rgb"; 01458 } 01459 } else { 01460 csource << ".a"; 01461 if (!single_value) { 01462 // Dunno if it's legal in the FPP at all, but let's just allow it. 01463 return "float3(" + csource.str() + ")"; 01464 } 01465 } 01466 return csource.str(); 01467 } 01468 01469 //////////////////////////////////////////////////////////////////// 01470 // Function: ShaderGenerator::texture_type_as_string 01471 // Access: Protected, Static 01472 // Description: Returns 1D, 2D, 3D or CUBE, depending on the given 01473 // texture type. 01474 //////////////////////////////////////////////////////////////////// 01475 const string ShaderGenerator:: 01476 texture_type_as_string(Texture::TextureType ttype) { 01477 switch (ttype) { 01478 case Texture::TT_1d_texture: 01479 return "1D"; 01480 break; 01481 case Texture::TT_2d_texture: 01482 return "2D"; 01483 break; 01484 case Texture::TT_3d_texture: 01485 return "3D"; 01486 break; 01487 case Texture::TT_cube_map: 01488 return "CUBE"; 01489 break; 01490 default: 01491 pgraph_cat.error() << "Unsupported texture type!\n"; 01492 return "2D"; 01493 } 01494 } 01495