00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <rve_render_server/ogre_material_generator.h>
00031 #include <rve_render_server/material.h>
00032 #include <rve_render_server/texture.h>
00033 #include <rve_render_server/render_target.h>
00034 #include <rve_render_server/render_texture.h>
00035 #include <rve_render_server/renderer.h>
00036 #include <rve_render_server/texture_resource.h>
00037 #include <rve_msgs/Material.h>
00038
00039 #include <rve_common/parse_resource_uri.h>
00040
00041 #include <resource_retriever/retriever.h>
00042 #include <boost/filesystem.hpp>
00043
00044 #include <sstream>
00045
00046 #include <OGRE/OgreMaterialManager.h>
00047 #include <OGRE/OgreTextureManager.h>
00048 #include <OGRE/OgreTexture.h>
00049 #include <OGRE/OgreGpuProgramManager.h>
00050 #include <OGRE/OgreHighLevelGpuProgramManager.h>
00051 #include <OGRE/OgreTechnique.h>
00052 #include <OGRE/OgrePass.h>
00053
00054 namespace fs = boost::filesystem;
00055
00056 namespace rve_render_server
00057 {
00058
00059 void loadTexture(const std::string& resource_path)
00060 {
00061 if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path))
00062 {
00063 resource_retriever::Retriever retriever;
00064 resource_retriever::MemoryResource res;
00065 try
00066 {
00067 res = retriever.get(resource_path);
00068 }
00069 catch (resource_retriever::Exception& e)
00070 {
00071 ROS_ERROR("%s", e.what());
00072 }
00073
00074 if (res.size != 0)
00075 {
00076 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00077 Ogre::Image image;
00078 std::string extension = fs::extension(fs::path(resource_path));
00079
00080 if (extension[0] == '.')
00081 {
00082 extension = extension.substr(1, extension.size() - 1);
00083 }
00084
00085 try
00086 {
00087 image.load(stream, extension);
00088 Ogre::TextureManager::getSingleton().loadImage(resource_path, ROS_PACKAGE_NAME, image);
00089 }
00090 catch (Ogre::Exception& e)
00091 {
00092 ROS_ERROR("Could not load texture [%s]: %s", resource_path.c_str(), e.what());
00093 }
00094 }
00095 }
00096 }
00097
00098 void applyUniforms(const Ogre::HighLevelGpuProgramPtr& program, const V_ShaderUniform& uniforms)
00099 {
00100 const Ogre::GpuProgramParametersSharedPtr& params = program->getDefaultParameters();
00101 V_ShaderUniform::const_iterator it = uniforms.begin();
00102 V_ShaderUniform::const_iterator end = uniforms.end();
00103 for (; it != end; ++it)
00104 {
00105 const ShaderUniform& uniform = *it;
00106 try
00107 {
00108 params->setNamedAutoConstant(uniform.name, (Ogre::GpuProgramParameters::AutoConstantType)uniform.auto_constant_type, uniform.extra);
00109 }
00110 catch (Ogre::Exception& e)
00111 {
00112 ROS_DEBUG("%s", e.what());
00113 }
00114 }
00115
00116 try
00117 {
00118 params->setNamedAutoConstant("worldviewproj", Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
00119 }
00120 catch (Ogre::Exception&)
00121 {}
00122
00123 try
00124 {
00125 params->setNamedAutoConstant("worldview", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX);
00126 }
00127 catch (Ogre::Exception&)
00128 {}
00129 }
00130
00131 static void emitInputs(std::stringstream& ss, const V_ShaderParameter& inputs, bool& first_parameter, bool geom_shader)
00132 {
00133 V_ShaderParameter::const_iterator it = inputs.begin();
00134 V_ShaderParameter::const_iterator end = inputs.end();
00135 for (; it != end; ++it)
00136 {
00137 const ShaderParameter& param = *it;
00138 if (!first_parameter)
00139 {
00140 ss << " ,";
00141 }
00142
00143 first_parameter = false;
00144 if (geom_shader)
00145 {
00146 ss << " AttribArray<" << param.type << "> in_" << param.name << " : " << param.semantic << std::endl;
00147 }
00148 else
00149 {
00150 ss << " " << param.type << " in_" << param.name << " : " << param.semantic << std::endl;
00151 }
00152 }
00153 }
00154
00155 static void emitOutputs(std::stringstream& ss, const V_ShaderParameter& outputs, bool& first_parameter)
00156 {
00157 V_ShaderParameter::const_iterator it = outputs.begin();
00158 V_ShaderParameter::const_iterator end = outputs.end();
00159 for (; it != end; ++it)
00160 {
00161 const ShaderParameter& param = *it;
00162
00163 if (!first_parameter)
00164 {
00165 ss << " ,";
00166 }
00167
00168 first_parameter = false;
00169
00170 ss << " out " << param.type << " out_" << param.name << " : " << param.semantic << std::endl;
00171 }
00172 }
00173
00174 static void emitUniforms(std::stringstream& ss, const V_ShaderUniform& uniforms, bool& first_parameter)
00175 {
00176 V_ShaderUniform::const_iterator it = uniforms.begin();
00177 V_ShaderUniform::const_iterator end = uniforms.end();
00178 for (; it != end; ++it)
00179 {
00180 const ShaderUniform& uniform = *it;
00181
00182 if (!first_parameter)
00183 {
00184 ss << " ,";
00185 }
00186
00187 first_parameter = false;
00188
00189 ss << " uniform " << uniform.type << " " << uniform.name << std::endl;
00190 }
00191 }
00192
00193 static void emitSamplers(std::stringstream& ss, const V_ShaderSampler& samplers, bool& first_parameter)
00194 {
00195 V_ShaderSampler::const_iterator it = samplers.begin();
00196 V_ShaderSampler::const_iterator end = samplers.end();
00197 for (; it != end; ++it)
00198 {
00199 const ShaderSampler& samp = *it;
00200
00201 if (!first_parameter)
00202 {
00203 ss << " ,";
00204 }
00205
00206 first_parameter = false;
00207
00208 ss << " uniform sampler sampler_" << samp.name << " : register(s" << samp.reg << ")" << std::endl;
00209 }
00210 }
00211
00212 static void emitIncludes(std::stringstream& ss, const V_string& includes)
00213 {
00214 V_string::const_iterator it = includes.begin();
00215 V_string::const_iterator end = includes.end();
00216 for (; it != end; ++it)
00217 {
00218 ss << "#include \"" << *it << "\"" << std::endl;
00219 }
00220 }
00221
00222 Ogre::GpuProgramPtr generateVertexShader(const ShaderDefinition& def, const std::string& base_name)
00223 {
00224 std::stringstream ss;
00225
00226 emitIncludes(ss, def.includes);
00227 ss << std::endl;
00228 ss << "void vp(" << std::endl;
00229 bool first_parameter = true;
00230 emitInputs(ss, def.inputs, first_parameter, false);
00231 emitOutputs(ss, def.outputs, first_parameter);
00232 emitUniforms(ss, def.uniforms, first_parameter);
00233 emitSamplers(ss, def.samplers, first_parameter);
00234
00235 ss << ")\n";
00236 ss << "{\n";
00237
00238 ss << def.body;
00239 ss << "\n";
00240
00241 ss << "}" << std::endl;
00242
00243 std::string program_source = ss.str();
00244 std::string program_name = base_name + "_VP";
00245
00246 ROS_DEBUG("%s", program_source.c_str());
00247
00248
00249 Ogre::HighLevelGpuProgramPtr program =
00250 Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(program_name, ROS_PACKAGE_NAME, "cg",
00251 Ogre::GPT_VERTEX_PROGRAM);
00252 program->setSource(program_source);
00253 program->setParameter("entry_point", "vp");
00254 program->setParameter("profiles", "vs_1_1 arbvp1");
00255
00256 applyUniforms(program, def.uniforms);
00257
00258 program->load();
00259
00260 return Ogre::GpuProgramPtr(program);
00261 }
00262
00263 Ogre::GpuProgramPtr generateFragmentShader(const ShaderDefinition& in_def, bool transparent, bool shaded, const std::string& base_name)
00264 {
00265 ShaderDefinition def = in_def;
00266 std::stringstream ss;
00267
00268 if (transparent)
00269 {
00270 def.include("camera_light.cg");
00271 }
00272
00273 def.output("float4", "color0", "COLOR0");
00274 def.output("float4", "color1", "COLOR1");
00275 def.uniform("float", "far_distance", Ogre::GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
00276
00277 emitIncludes(ss, def.includes);
00278 ss << std::endl;
00279 ss << "void fp(" << std::endl;
00280 bool first_parameter = true;
00281 emitInputs(ss, def.inputs, first_parameter, false);
00282 emitOutputs(ss, def.outputs, first_parameter);
00283 emitUniforms(ss, def.uniforms, first_parameter);
00284 emitSamplers(ss, def.samplers, first_parameter);
00285
00286 ss << " )\n";
00287 ss << "{\n";
00288
00289 ss << def.body;
00290 ss << "\n";
00291
00292 if (transparent)
00293 {
00294 if (shaded)
00295 {
00296 ss << "float3 gooch_color = camera_light(color.rgb, normal, float3(0.0, 0.0, 1.0));\n";
00297 ss << "out_color0 = float4(gooch_color * color.a, color.a);\n";
00298 }
00299 else
00300 {
00301 ss << "out_color0 = float4(color.rgb * color.a, color.a);";
00302 }
00303
00304 ss << "out_color1 = float4(1.0, 0.0, 0.0, 0.0);\n";
00305 }
00306 else
00307 {
00308 ss << " out_color0 = float4(color.rgb, 1.0);\n";
00309 if (!shaded)
00310 {
00311 ss << " out_color0.a = 0.0;";
00312 }
00313
00314
00315 ss << " out_color1.rgb = normal;\n";
00316 ss << " out_color1.a = length(in_view_pos) / far_distance;\n";
00317 }
00318
00319 ss << "}" << std::endl;
00320
00321 std::string program_source = ss.str();
00322 std::string program_name = base_name + "_FP";
00323
00324 ROS_DEBUG("%s", program_source.c_str());
00325
00326
00327 Ogre::HighLevelGpuProgramPtr program =
00328 Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(program_name, ROS_PACKAGE_NAME, "cg",
00329 Ogre::GPT_FRAGMENT_PROGRAM);
00330 program->setSource(program_source);
00331 program->setParameter("entry_point", "fp");
00332 program->setParameter("profiles", "ps_2_0 arbfp1");
00333
00334 applyUniforms(program, def.uniforms);
00335
00336 program->load();
00337
00338 return Ogre::GpuProgramPtr(program);
00339 }
00340
00341 Ogre::GpuProgramPtr generatePickingFragmentShader(const ShaderDefinition& in_def, const std::string& base_name)
00342 {
00343 ShaderDefinition def = in_def;
00344 std::stringstream ss;
00345
00346 def.output("float4", "object_id", "COLOR0");
00347 def.output("float4", "object_extra", "COLOR1");
00348
00349 emitIncludes(ss, def.includes);
00350 ss << std::endl;
00351 ss << "void fp(" << std::endl;
00352 bool first_parameter = true;
00353 emitInputs(ss, def.inputs, first_parameter, false);
00354 emitOutputs(ss, def.outputs, first_parameter);
00355 emitUniforms(ss, def.uniforms, first_parameter);
00356 emitSamplers(ss, def.samplers, first_parameter);
00357
00358 ss << " )\n";
00359 ss << "{\n";
00360
00361 if (!def.body.empty())
00362 {
00363 ss << def.body;
00364 ss << "\n";
00365 }
00366 else
00367 {
00368 ss << " float4 object_id = float4(0.0, 0.0, 0.0, 0.0);\n";
00369 ss << " float4 object_extra = float4(0.0, 0.0, 0.0, 0.0);\n";
00370 }
00371
00372 ss << " out_object_id = object_id;\n";
00373 ss << " out_object_extra = object_extra;\n";
00374
00375 ss << "}" << std::endl;
00376
00377 std::string program_source = ss.str();
00378 std::string program_name = base_name + "_FP_Pick";
00379
00380 ROS_DEBUG("%s", program_source.c_str());
00381
00382
00383 Ogre::HighLevelGpuProgramPtr program =
00384 Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(program_name, ROS_PACKAGE_NAME, "cg",
00385 Ogre::GPT_FRAGMENT_PROGRAM);
00386 program->setSource(program_source);
00387 program->setParameter("entry_point", "fp");
00388 program->setParameter("profiles", "ps_2_0 arbfp1");
00389
00390 applyUniforms(program, def.uniforms);
00391
00392 program->load();
00393
00394 return Ogre::GpuProgramPtr(program);
00395 }
00396
00397 Ogre::GpuProgramPtr generateGeometryShader(const ShaderDefinition& def, const std::string& base_name)
00398 {
00399 std::stringstream ss;
00400
00401 emitIncludes(ss, def.includes);
00402 ss << std::endl;
00403 ss << def.geom_input << " " << def.geom_output << " void gp(" << std::endl;
00404 bool first_parameter = true;
00405 emitInputs(ss, def.inputs, first_parameter, true);
00406 emitUniforms(ss, def.uniforms, first_parameter);
00407 emitSamplers(ss, def.samplers, first_parameter);
00408
00409 ss << ")\n";
00410 ss << "{\n";
00411
00412 ss << def.body;
00413 ss << "\n";
00414
00415 ss << "}" << std::endl;
00416
00417 std::string program_source = ss.str();
00418 std::string program_name = base_name + "_GP";
00419
00420 ROS_DEBUG("%s", program_source.c_str());
00421
00422
00423 Ogre::HighLevelGpuProgramPtr program =
00424 Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(program_name, ROS_PACKAGE_NAME, "cg",
00425 Ogre::GPT_GEOMETRY_PROGRAM);
00426 program->setSource(program_source);
00427 program->setParameter("entry_point", "gp");
00428 program->setParameter("profiles", "gpu_gp gp4_gp");
00429
00430 applyUniforms(program, def.uniforms);
00431
00432 program->load();
00433
00434 return Ogre::GpuProgramPtr(program);
00435 }
00436
00437 Ogre::MaterialPtr generateOgreMaterial(const MaterialDefinition& def)
00438 {
00439 if (Ogre::MaterialManager::getSingleton().resourceExists(def.name))
00440 {
00441 return Ogre::MaterialManager::getSingleton().getByName(def.name);
00442 }
00443
00444 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(def.name, ROS_PACKAGE_NAME);
00445
00446 if (def.transparent)
00447 {
00448 mat->getTechnique(0)->setSchemeName("WeightedAverageAlpha");
00449 mat->setSceneBlending(Ogre::SBT_ADD);
00450 mat->setDepthWriteEnabled(false);
00451 }
00452 else
00453 {
00454 mat->getTechnique(0)->setSchemeName("GBuffer");
00455 }
00456
00457 Ogre::Pass* pass = mat->getTechnique(0)->getPass(0);
00458 pass->setLightingEnabled(false);
00459
00460 V_string::const_iterator it = def.textures.begin();
00461 V_string::const_iterator end = def.textures.end();
00462 for (; it != end; ++it)
00463 {
00464 const std::string& tex_path = *it;
00465 Ogre::TextureUnitState* tu = pass->createTextureUnitState();
00466
00467 std::string tex_name = tex_path;
00468
00469 if (!lookupTextureResource(tex_path, tex_name))
00470 {
00471 loadTexture(tex_path);
00472 }
00473
00474 tu->setTextureName(tex_name);
00475 }
00476
00477 Ogre::GpuProgramPtr vertex_program = generateVertexShader(def.vertex_def, def.name);
00478 Ogre::GpuProgramPtr fragment_program = generateFragmentShader(def.fragment_def, def.transparent, !def.disable_shading, def.name);
00479 pass->setVertexProgram(vertex_program->getName());
00480 pass->setFragmentProgram(fragment_program->getName());
00481
00482 Ogre::GpuProgramPtr geometry_program;
00483 if (def.has_geometry_shader)
00484 {
00485 geometry_program = generateGeometryShader(def.geometry_def, def.name);
00486 pass->setGeometryProgram(geometry_program->getName());
00487 }
00488
00489 {
00490
00491 Ogre::GpuProgramPtr picking_fragment_program = generatePickingFragmentShader(def.picking_fragment_def, def.name);
00492 Ogre::Technique* tech = mat->createTechnique();
00493 tech->setSchemeName("Pick");
00494 Ogre::Pass* pass = tech->createPass();
00495 pass->setVertexProgram(vertex_program->getName());
00496 pass->setFragmentProgram(picking_fragment_program->getName());
00497
00498 if (!geometry_program.isNull())
00499 {
00500 pass->setGeometryProgram(geometry_program->getName());
00501 }
00502
00503 pass->setLightingEnabled(false);
00504 }
00505
00506 Ogre::CullingMode cull_mode;
00507 switch (def.cull_mode)
00508 {
00509 case rve_msgs::Material::CULL_COUNTERCLOCKWISE:
00510 cull_mode = Ogre::CULL_ANTICLOCKWISE;
00511 break;
00512 case rve_msgs::Material::CULL_CLOCKWISE:
00513 cull_mode = Ogre::CULL_CLOCKWISE;
00514 break;
00515 default:
00516 cull_mode = Ogre::CULL_NONE;
00517 }
00518 mat->setCullingMode(cull_mode);
00519
00520 return mat;
00521 }
00522
00527
00528
00529 std::string materialToStringID(const rve_msgs::Material& input_mat)
00530 {
00531 std::stringstream ss;
00532 ss << "Gen_";
00533
00534 if (input_mat.has_color)
00535 {
00536 ss << "Color";
00537 }
00538
00539 if (input_mat.has_texture)
00540 {
00541 ss << "Texture_" << input_mat.texture;
00542 }
00543
00544 if (input_mat.has_normal_map)
00545 {
00546 ss << "NormalMap_" << input_mat.normal_map;
00547 }
00548
00549 bool transparent = input_mat.opacity < 0.99;
00550 if (transparent)
00551 {
00552 ss << "Alpha";
00553 }
00554
00555 return ss.str();
00556 }
00557
00558 static std::string toString(uint32_t i)
00559 {
00560 std::stringstream ss;
00561 ss << i;
00562 return ss.str();
00563 }
00564
00565 void fillVertexShaderDefinition(const rve_msgs::Material& input_mat, ShaderDefinition& def)
00566 {
00567 def.input("float4", "position", "POSITION");
00568 def.input("float3", "normal", "NORMAL");
00569
00570 uint32_t num_tex_coords = input_mat.has_texture ? 1 : 0;
00571 uint32_t tex_coord_num = 2;
00572 for (uint32_t i = 0; i < num_tex_coords; i++)
00573 {
00574 def.input("float2", "uv" + toString(i), "TEXCOORD" + toString(i));
00575 def.output("float2", "uv" + toString(i), "TEXCOORD" + toString(tex_coord_num));
00576 ++tex_coord_num;
00577 }
00578
00579 if (input_mat.has_normal_map)
00580 {
00581 def.input("float3", "tangent", "TANGENT0");
00582 }
00583
00584 def.output("float4", "position", "POSITION");
00585 def.output("float3", "view_pos", "TEXCOORD0");
00586 def.output("float3", "normal", "TEXCOORD1");
00587
00588 if (input_mat.has_normal_map)
00589 {
00590 def.output("float3", "tangent", "TEXCOORD" + toString(tex_coord_num++));
00591 def.output("float3", "binormal", "TEXCOORD" + toString(tex_coord_num++));
00592 }
00593
00594 def.uniform("float4x4", "worldviewproj", Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX, 0);
00595 def.uniform("float4x4", "worldview", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX, 0);
00596
00597 std::stringstream ss;
00598 ss << " out_position = mul(worldviewproj, in_position);" << std::endl;
00599 ss << " out_normal = mul(worldview, float4(in_normal,0)).xyz;" << std::endl;
00600
00601 ss << " out_view_pos = mul(worldview, in_position).xyz;" << std::endl;
00602
00603 if (input_mat.has_normal_map)
00604 {
00605 ss << " out_tangent = mul(worldview, float4(in_tangent, 0)).xyz;" << std::endl;
00606 ss << " out_binormal = cross(out_normal, out_tangent);" << std::endl;
00607 }
00608
00609 for (uint32_t i = 0; i < num_tex_coords; i++)
00610 {
00611 ss << " out_uv" << i << " = in_uv" << i << ';' << std::endl;
00612 }
00613
00614 def.body = ss.str();
00615 }
00616
00617 void fillFragmentShaderDefinition(const rve_msgs::Material& input_mat, ShaderDefinition& def)
00618 {
00619 if (input_mat.has_normal_map)
00620 {
00621 def.include("normal_mapping.cg");
00622 }
00623
00624 def.input("float3", "view_pos", "TEXCOORD0");
00625 def.input("float3", "normal", "TEXCOORD1");
00626
00627 uint32_t num_tex_coords = input_mat.has_texture ? 1 : 0;
00628 uint32_t tex_coord_num = 2;
00629 for (uint32_t i = 0; i < num_tex_coords; i++)
00630 {
00631 def.input("float2", "uv" + toString(i), "TEXCOORD" + toString(tex_coord_num));
00632 ++tex_coord_num;
00633 }
00634
00635 if (input_mat.has_normal_map)
00636 {
00637 def.input("float3", "tangent", "TEXCOORD" + toString(tex_coord_num++));
00638 def.input("float3", "binormal", "TEXCOORD" + toString(tex_coord_num++));
00639 }
00640
00641 uint32_t sampler_num = 0;
00642 if (input_mat.has_texture)
00643 {
00644 def.sampler("tex", sampler_num++);
00645 }
00646
00647 if (input_mat.has_normal_map)
00648 {
00649 def.sampler("normal_map", sampler_num++);
00650 }
00651
00652 def.uniform("float4", "color", Ogre::GpuProgramParameters::ACT_CUSTOM, Material::CustomParam_Color);
00653 def.uniform("float4x4", "worldview", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX, 0);
00654
00655 std::stringstream ss;
00656 if (input_mat.has_texture)
00657 {
00658 #if 0
00659 if (input_mat.has_color)
00660 {
00661 ss << " color = color * tex2D(sampler_tex, in_uv0);\n";
00662 }
00663 else
00664 #endif
00665 {
00666 ss << " float4 tmp = tex2D(sampler_tex, in_uv0);\n";
00667 ss << " color = float4(tmp.rgb, tmp.a * color.a);\n";
00668 }
00669 }
00670
00671 if (input_mat.has_normal_map)
00672 {
00673 ss << " float3 normal = extractNormalFromMap(sampler_normal_map, in_uv0, in_normal, in_tangent, in_binormal);" << std::endl;
00674 }
00675 else
00676 {
00677 ss << " float3 normal = normalize(in_normal);" << std::endl;
00678 }
00679
00680 def.body = ss.str();
00681 }
00682
00683 void fillPickingFragmentShaderDefinition(const rve_msgs::Material& input_mat, ShaderDefinition& def)
00684 {
00685 def.uniform("float4", "object_id", Ogre::GpuProgramParameters::ACT_CUSTOM, Material::CustomParam_ObjectID);
00686
00687 std::stringstream ss;
00688
00689 ss << " float4 object_extra = float4(0.0, 0.0, 0.0, 0.0);\n";
00690 def.body = ss.str();
00691 }
00692
00693 Ogre::MaterialPtr generateOgreMaterial(const rve_msgs::Material& input_mat)
00694 {
00695 MaterialDefinition def;
00696 def.name = materialToStringID(input_mat);
00697 def.transparent = input_mat.opacity < 0.99;
00698 def.disable_shading = input_mat.disable_shading;
00699
00700 def.cull_mode = input_mat.cull_mode;
00701
00702 if (input_mat.has_texture)
00703 {
00704 def.textures.push_back(input_mat.texture);
00705 }
00706
00707 if (input_mat.has_normal_map)
00708 {
00709 def.textures.push_back(input_mat.normal_map);
00710 }
00711
00712 fillVertexShaderDefinition(input_mat, def.vertex_def);
00713 fillFragmentShaderDefinition(input_mat, def.fragment_def);
00714 fillPickingFragmentShaderDefinition(input_mat, def.picking_fragment_def);
00715 return generateOgreMaterial(def);
00716 }
00717
00718 }