//----------------------------------------------------------------------------- /// void BatchPage::build() { m_pBatchGeom->build(); BatchedGeometry::TSubBatchIterator it = m_pBatchGeom->getSubBatchIterator(); while (it.hasMoreElements()) { BatchedGeometry::SubBatch *subBatch = it.getNext(); const MaterialPtr &ptrMat = subBatch->getMaterial(); //Disable specular unless a custom shader is being used. //This is done because the default shader applied by BatchPage //doesn't support specular, and fixed-function needs to look //the same as the shader (for computers with no shader support) for (unsigned short t = 0, tCnt = ptrMat->getNumTechniques(); t < tCnt; ++t) { Technique *tech = ptrMat->getTechnique(t); for (unsigned short p = 0, pCnt = tech->getNumPasses(); p < pCnt; ++p) { Pass *pass = tech->getPass(p); //if (pass->getVertexProgramName() == "") // pass->setSpecular(0, 0, 0, 1); if (!pass->hasVertexProgram()) pass->setSpecular(0.f, 0.f, 0.f, 1.f); } } //Store the original materials m_vecUnfadedMaterials.push_back(subBatch->getMaterial()); } _updateShaders(); }
void BatchPage::build() { batch->build(); BatchedGeometry::SubBatchIterator it = batch->getSubBatchIterator(); while (it.hasMoreElements()){ BatchedGeometry::SubBatch *subBatch = it.getNext(); MaterialPtr mat = subBatch->getMaterial(); //Disable specular unless a custom shader is being used. //This is done because the default shader applied by BatchPage //doesn't support specular, and fixed-function needs to look //the same as the shader (for computers with no shader support) for (int t = 0; t < mat->getNumTechniques(); ++t){ Technique *tech = mat->getTechnique(t); for (int p = 0; p < tech->getNumPasses(); ++p){ Pass *pass = tech->getPass(p); if (pass->getVertexProgramName() == "") pass->setSpecular(0, 0, 0, 1); } } //Store the original materials unfadedMaterials.push_back(subBatch->getMaterial()); } _updateShaders(); }
int GameScript::getSafeTextureUnitState(TextureUnitState **tu, const String materialName, int techniqueNum, int passNum, int textureUnitNum) { try { MaterialPtr m = MaterialManager::getSingleton().getByName(materialName); if (m.isNull()) return 1; // verify technique if (techniqueNum < 0 || techniqueNum > m->getNumTechniques()) return 2; Technique *t = m->getTechnique(techniqueNum); if (!t) return 2; //verify pass if (passNum < 0 || passNum > t->getNumPasses()) return 3; Pass *p = t->getPass(passNum); if (!p) return 3; //verify texture unit if (textureUnitNum < 0 || textureUnitNum > p->getNumTextureUnitStates()) return 4; TextureUnitState *tut = p->getTextureUnitState(textureUnitNum); if (!tut) return 4; *tu = tut; return 0; } catch(Exception e) { SLOG("Exception in getSafeTextureUnitState(): " + e.getFullDescription()); } return 1; }
void LightInstanceBatchHW::injectRender() { if( (mRenderOperation.numberOfInstances = updateVertexBuffer( mCurrentCamera )) ) { Technique* tech = mMaterial->getBestTechnique(); for (size_t i=0; i<tech->getNumPasses(); ++i) { mManager->_injectRenderWithPass(tech->getPass(i), this, false); } } }
//! [schemenotfound] Technique* GBufferSchemeHandler::handleSchemeNotFound(unsigned short schemeIndex, const String& schemeName, Material* originalMaterial, unsigned short lodIndex, const Renderable* rend) { Ogre::MaterialManager& matMgr = Ogre::MaterialManager::getSingleton(); String curSchemeName = matMgr.getActiveScheme(); matMgr.setActiveScheme(MaterialManager::DEFAULT_SCHEME_NAME); Technique* originalTechnique = originalMaterial->getBestTechnique(lodIndex, rend); matMgr.setActiveScheme(curSchemeName); Technique* gBufferTech = originalMaterial->createTechnique(); gBufferTech->removeAllPasses(); gBufferTech->setSchemeName(schemeName); #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM RTShader::ShaderGenerator& rtShaderGen = RTShader::ShaderGenerator::getSingleton(); rtShaderGen.createShaderBasedTechnique(originalTechnique, "NoGBuffer"); #else Technique* noGBufferTech = originalMaterial->createTechnique(); noGBufferTech->removeAllPasses(); noGBufferTech->setSchemeName("NoGBuffer"); #endif for (unsigned short i=0; i<originalTechnique->getNumPasses(); i++) { Pass* originalPass = originalTechnique->getPass(i); PassProperties props = inspectPass(originalPass, lodIndex, rend); if (!props.isDeferred) { #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM rtShaderGen.validateMaterial("NoGBuffer", originalMaterial->getName(), originalMaterial->getGroup()); #else //Just copy the technique so it gets rendered regularly Pass* clonePass = noGBufferTech->createPass(); *clonePass = *originalPass; #endif continue; } Pass* newPass = gBufferTech->createPass(); MaterialGenerator::Perm perm = getPermutation(props); const Ogre::MaterialPtr& templateMat = mMaterialGenerator.getMaterial(perm); //We assume that the GBuffer technique contains only one pass. But its true. *newPass = *(templateMat->getTechnique(0)->getPass(0)); fillPass(newPass, originalPass, props); } return gBufferTech; }
// 把地形的障碍区域显示Pass移除 void TerrainEditorPlugin::removeTerrainBlockerPass(ETTerrain *terrain) { MaterialPtr mat = terrain->getTerrainImpl()->getMaterial(); Technique *tech = mat->getTechnique(0); // 看有没有这个Blocker的Pass,如果有就删除之 for(size_t i = 0 ; i < tech->getNumPasses() ; i ++) { if(tech->getPass(i)->getName() == "Blocker") { tech->removePass(i); return; } } }
//----------------------------------------------------------------------------- void SGMaterialSerializerListener::createSGPassList(Material* mat, SGPassList& passList) { for (unsigned short techniqueIndex = 0; techniqueIndex < mat->getNumTechniques(); ++techniqueIndex) { Technique* curTechnique = mat->getTechnique(techniqueIndex); for (unsigned short passIndex = 0; passIndex < curTechnique->getNumPasses(); ++passIndex) { Pass* curPass = curTechnique->getPass(passIndex); const Any& passUserData = curPass->getUserObjectBindings().getUserAny(ShaderGenerator::SGPass::UserKey); // Case this pass created by the shader generator. if (passUserData.isEmpty() == false) { ShaderGenerator::SGPass* passEntry = any_cast<ShaderGenerator::SGPass*>(passUserData); passList.push_back(passEntry); } } } }
// 为地形添加一个障碍区域的显示Pass void TerrainEditorPlugin::addTerrainBlockerPass(ETTerrain *terrain) { MaterialPtr mat = terrain->getTerrainImpl()->getMaterial(); Technique *tech = mat->getTechnique(0); // 看有没有这个Blocker的Pass,如果有就不用添加了 for(size_t i = 0 ; i < tech->getNumPasses() ; i ++) { if(tech->getPass(i)->getName() == "Blocker") return; } Pass *blockerPass = mat->getTechnique(0)->createPass(); blockerPass->setName("Blocker"); // 使用透明渲染 blockerPass->setSceneBlending(SBT_TRANSPARENT_ALPHA); blockerPass->setVertexProgram("ET/Programs/VSLodMorph2"); //blockerPass->setPolygonMode(PM_WIREFRAME); //blockerPass->setLightingEnabled(false); blockerPass->setCullingMode(CULL_ANTICLOCKWISE); //blockerPass->setDepthCheckEnabled(false); // 创建个贴图 TextureUnitState *state = blockerPass->createTextureUnitState(terrain->getBlockerTexture()->getName()); state->setTextureFiltering(TFO_NONE); }
//----------------------------------------------------------------------------- ShadowCaster::ShadowRenderableListIterator ManualObject::getShadowVolumeRenderableIterator( ShadowTechnique shadowTechnique, const Light* light, HardwareIndexBufferSharedPtr* indexBuffer, bool extrude, Real extrusionDistance, unsigned long flags) { assert(indexBuffer && "Only external index buffers are supported right now"); EdgeData* edgeList = getEdgeList(); if (!edgeList) { return ShadowRenderableListIterator( mShadowRenderables.begin(), mShadowRenderables.end()); } // Calculate the object space light details Vector4 lightPos = light->getAs4DVector(); Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine(); lightPos = world2Obj.transformAffine(lightPos); // Init shadow renderable list if required (only allow indexed) bool init = mShadowRenderables.empty() && mAnyIndexed; EdgeData::EdgeGroupList::iterator egi; ShadowRenderableList::iterator si, siend; ManualObjectSectionShadowRenderable* esr = 0; SectionList::iterator seci; if (init) mShadowRenderables.resize(edgeList->edgeGroups.size()); siend = mShadowRenderables.end(); egi = edgeList->edgeGroups.begin(); seci = mSectionList.begin(); for (si = mShadowRenderables.begin(); si != siend; ++seci) { // Skip non-indexed geometry if (!(*seci)->getRenderOperation()->useIndexes) { continue; } if (init) { // Create a new renderable, create a separate light cap if // we're using a vertex program (either for this model, or // for extruding the shadow volume) since otherwise we can // get depth-fighting on the light cap MaterialPtr mat = (*seci)->getMaterial(); mat->load(); bool vertexProgram = false; Technique* t = mat->getBestTechnique(0, *seci); for (unsigned short p = 0; p < t->getNumPasses(); ++p) { Pass* pass = t->getPass(p); if (pass->hasVertexProgram()) { vertexProgram = true; break; } } *si = OGRE_NEW ManualObjectSectionShadowRenderable(this, indexBuffer, egi->vertexData, vertexProgram || !extrude); } // Get shadow renderable esr = static_cast<ManualObjectSectionShadowRenderable*>(*si); HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer(); // Extrude vertices in software if required if (extrude) { extrudeVertices(esrPositionBuffer, egi->vertexData->vertexCount, lightPos, extrusionDistance); } ++si; ++egi; } // Calc triangle light facing updateEdgeListLightFacing(edgeList, lightPos); // Generate indexes and update renderables generateShadowVolume(edgeList, *indexBuffer, light, mShadowRenderables, flags); return ShadowRenderableListIterator( mShadowRenderables.begin(), mShadowRenderables.end()); }
//----------------------------------------------------------------------------- /// void WindBatchPage::_updateShaders() { if (!m_bShadersSupported) return; unsigned int i = 0; BatchedGeometry::TSubBatchIterator it = m_pBatchGeom->getSubBatchIterator(); while (it.hasMoreElements()) { BatchedGeometry::SubBatch *subBatch = it.getNext(); const MaterialPtr &ptrMat = m_vecUnfadedMaterials[i++]; //Check if lighting should be enabled bool lightingEnabled = false; for (unsigned short t = 0, techCnt = ptrMat->getNumTechniques(); t < techCnt; ++t) { Technique *tech = ptrMat->getTechnique(t); for (unsigned short p = 0, passCnt = tech->getNumPasses(); p < passCnt; ++p) { if (tech->getPass(p)->getLightingEnabled()) { lightingEnabled = true; break; } } if (lightingEnabled) break; } //Compile the shader script based on various material / fade options StringUtil::StrStreamType tmpName; tmpName << "BatchPage_"; if (m_bFadeEnabled) tmpName << "fade_"; if (lightingEnabled) tmpName << "lit_"; if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) tmpName << "clr_"; for (unsigned short i = 0; i < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { String uvType; switch (el->getType()) { case VET_FLOAT1: uvType = "1"; break; case VET_FLOAT2: uvType = "2"; break; case VET_FLOAT3: uvType = "3"; break; case VET_FLOAT4: uvType = "4"; break; } tmpName << uvType << '_'; } } tmpName << "vp"; const String vertexProgName = tmpName.str(); String shaderLanguage; if (Root::getSingleton().getRenderSystem()->getName() == "Direct3D9 Rendering Subsystem") shaderLanguage = "hlsl"; else if(Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem") shaderLanguage = "glsl"; else shaderLanguage = "cg"; //If the shader hasn't been created yet, create it if (HighLevelGpuProgramManager::getSingleton().getByName(vertexProgName).isNull()) { Pass *pass = ptrMat->getTechnique(0)->getPass(0); String vertexProgSource; if(!shaderLanguage.compare("hlsl") || !shaderLanguage.compare("cg")) { vertexProgSource = "void main( \n" " float4 iPosition : POSITION, \n" " float3 normal : NORMAL, \n" " out float4 oPosition : POSITION, \n"; if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " float4 iColor : COLOR, \n"; } int texNum = 0; unsigned short texCoordCount = 0; for (unsigned short j = 0; j < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++j) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(j); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { ++ texCoordCount; } } for (unsigned short i = 0; i < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { if (el->getIndex() == texCoordCount - 2) { vertexProgSource += " float4 params : TEXCOORD" + StringConverter::toString(texCoordCount-2) + ", \n"; } else { if (el->getIndex() == texCoordCount - 1) { vertexProgSource += " float4 originPos : TEXCOORD" + StringConverter::toString(texCoordCount-1) + ", \n"; } else { String uvType = ""; switch (el->getType()) { case VET_FLOAT1: uvType = "float"; break; case VET_FLOAT2: uvType = "float2"; break; case VET_FLOAT3: uvType = "float3"; break; case VET_FLOAT4: uvType = "float4"; break; } vertexProgSource += " " + uvType + " iUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n" " out " + uvType + " oUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n"; } ++texNum; } } } vertexProgSource += " out float oFog : FOG, \n" " out float4 oColor : COLOR, \n"; if (lightingEnabled) { vertexProgSource += " uniform float4 objSpaceLight, \n" " uniform float4 lightDiffuse, \n" " uniform float4 lightAmbient, \n"; } if (m_bFadeEnabled) { vertexProgSource += " uniform float3 camPos, \n" " uniform float fadeGap, \n" " uniform float invisibleDist, \n"; } vertexProgSource += " uniform float4x4 worldViewProj,\n" " uniform float time) \n " "{ \n"; if (lightingEnabled) { //Perform lighting calculations (no specular) vertexProgSource += " float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n" " float diffuseFactor = max(dot(normal, light), 0); \n"; if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n"; } else { vertexProgSource += " oColor = (lightAmbient + diffuseFactor * lightDiffuse); \n"; } } else { if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " oColor = iColor; \n"; } else { vertexProgSource += " oColor = float4(1, 1, 1, 1); \n"; } } if (m_bFadeEnabled) { //Fade out in the distance vertexProgSource += " float dist = distance(camPos.xz, iPosition.xz); \n" " oColor.a *= (invisibleDist - dist) / fadeGap; \n"; } for (unsigned short i = 0; i < texCoordCount - 2; ++i) { vertexProgSource += " oUV" + StringConverter::toString(i) + " = iUV" + StringConverter::toString(i) + "; \n"; } vertexProgSource += " float radiusCoeff = params.x; \n" " float heightCoeff = params.y; \n" " float factorX = params.z; \n" " float factorY = params.w; \n" " float4 tmpPos = iPosition; \n" /* 2 different methods are used to for the sin calculation : - the first one gives a better effect but at the cost of a few fps because of the 2 sines - the second one uses less ressources but is a bit less realistic a sin approximation could be use to optimize performances */ #if 0 " tmpPos.y += sin(time + originPos.z + tmpPos.y + tmpPos.x) * radiusCoeff * radiusCoeff * factorY; \n" " tmpPos.x += sin(time + originPos.z ) * heightCoeff * heightCoeff * factorX ; \n" #else " float sinval = sin(time + originPos.z ); \n" " tmpPos.y += sinval * radiusCoeff * radiusCoeff * factorY; \n" " tmpPos.x += sinval * heightCoeff * heightCoeff * factorX ; \n" #endif " oPosition = mul(worldViewProj, tmpPos); \n" " oFog = oPosition.z; \n" "}"; } if(!shaderLanguage.compare("glsl")) { unsigned short texCoordCount = 0; for (unsigned short j = 0; j < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++j) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(j); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { ++ texCoordCount; } } if (lightingEnabled) { vertexProgSource += "uniform vec4 objSpaceLight; \n" "uniform vec4 lightDiffuse; \n" "uniform vec4 lightAmbient; \n"; } if (m_bFadeEnabled) { vertexProgSource += "uniform vec3 camPos; \n" "uniform float fadeGap; \n" "uniform float invisibleDist; \n"; } vertexProgSource += "uniform float time; \n" "void main() \n" "{ \n"; int texNum = 0; for (unsigned short i = 0; i < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { if (el->getIndex() == texCoordCount - 2) { vertexProgSource += " vec4 params = gl_MultiTexCoord" + StringConverter::toString(texCoordCount-2) + "; \n"; } else { if (el->getIndex() == texCoordCount - 1) { vertexProgSource += " vec4 originPos = gl_MultiTexCoord" + StringConverter::toString(texCoordCount-1) + "; \n"; } else { vertexProgSource += " gl_TexCoord[" + StringConverter::toString(texNum) + "] = gl_MultiTexCoord" + StringConverter::toString(texNum) + "; \n"; } ++texNum; } } } if (lightingEnabled) { //Perform lighting calculations (no specular) vertexProgSource += " vec3 light = normalize(objSpaceLight.xyz - (gl_Vertex.xyz * objSpaceLight.w)); \n" " float diffuseFactor = max(dot(gl_Normal.xyz, light), 0.0); \n"; if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse) * gl_Color; \n"; } else { vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse); \n"; } } else { if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " gl_FrontColor = gl_Color; \n"; } else { vertexProgSource += " gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); \n"; } } if (m_bFadeEnabled) { //Fade out in the distance vertexProgSource += " float dist = distance(camPos.xz, gl_Vertex.xz); \n" " gl_FrontColor.a *= (invisibleDist - dist) / fadeGap; \n"; } vertexProgSource += " float radiusCoeff = params.x; \n" " float heightCoeff = params.y; \n" " float factorX = params.z; \n" " float factorY = params.w; \n" " vec4 tmpPos = gl_Vertex; \n" /* 2 different methods are used to for the sin calculation : - the first one gives a better effect but at the cost of a few fps because of the 2 sines - the second one uses less ressources but is a bit less realistic a sin approximation could be use to optimize performances */ #if 1 " tmpPos.y += sin(time + originPos.z + tmpPos.y + tmpPos.x) * radiusCoeff * radiusCoeff * factorY; \n" " tmpPos.x += sin(time + originPos.z ) * heightCoeff * heightCoeff * factorX; \n" #else " float sinval = sin(time + originPos.z ); \n" " tmpPos.y += sinval * radiusCoeff * radiusCoeff * factorY; \n" " tmpPos.x += sinval * heightCoeff * heightCoeff * factorX; \n" #endif " gl_Position = gl_ModelViewProjectionMatrix * tmpPos; \n" " gl_FogFragCoord = gl_Position.z; \n" "}"; } // test for shader source //std::ofstream shaderOutput; //shaderOutput.open((vertexProgName+std::string(".cg")).c_str()); //shaderOutput << vertexProgSource; //shaderOutput.close(); // end test for shader source HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram( vertexProgName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, shaderLanguage, GPT_VERTEX_PROGRAM); vertexShader->setSource(vertexProgSource); if (shaderLanguage == "hlsl") { vertexShader->setParameter("target", "vs_1_1"); vertexShader->setParameter("entry_point", "main"); } else if(shaderLanguage == "cg") { vertexShader->setParameter("profiles", "vs_1_1 arbvp1"); vertexShader->setParameter("entry_point", "main"); } // GLSL can only have one entry point "main". vertexShader->load(); } //Now that the shader is ready to be applied, apply it StringUtil::StrStreamType materialSignature; materialSignature << "BatchMat|"; materialSignature << ptrMat->getName() << "|"; if (m_bFadeEnabled) { materialSignature << m_fVisibleDist << "|"; materialSignature << m_fInvisibleDist << "|"; } //Search for the desired material MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str()); if (generatedMaterial.isNull()) { //Clone the material generatedMaterial = ptrMat->clone(materialSignature.str()); //And apply the fade shader for (unsigned short t = 0; t < generatedMaterial->getNumTechniques(); ++t){ Technique *tech = generatedMaterial->getTechnique(t); for (unsigned short p = 0; p < tech->getNumPasses(); ++p){ Pass *pass = tech->getPass(p); //Setup vertex program if (pass->getVertexProgramName() == "") pass->setVertexProgram(vertexProgName); try{ GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters(); if (lightingEnabled) { params->setNamedAutoConstant("objSpaceLight", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); params->setNamedAutoConstant("lightDiffuse", GpuProgramParameters::ACT_DERIVED_LIGHT_DIFFUSE_COLOUR); params->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_DERIVED_AMBIENT_LIGHT_COLOUR); //params->setNamedAutoConstant("matAmbient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); } params->setNamedConstantFromTime("time", 1); if(shaderLanguage.compare("glsl")) { //glsl can use the built in gl_ModelViewProjectionMatrix params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); } if (m_bFadeEnabled) { params->setNamedAutoConstant("camPos", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); //Set fade ranges params->setNamedAutoConstant("invisibleDist", GpuProgramParameters::ACT_CUSTOM); params->setNamedConstant("invisibleDist", m_fInvisibleDist); params->setNamedAutoConstant("fadeGap", GpuProgramParameters::ACT_CUSTOM); params->setNamedConstant("fadeGap", m_fInvisibleDist - m_fVisibleDist); if (pass->getAlphaRejectFunction() == CMPF_ALWAYS_PASS) pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); } } catch (const Ogre::Exception &e) { // test for shader source std::ofstream shaderOutput; shaderOutput.open("exception.log"); shaderOutput << e.getDescription(); shaderOutput.close(); } catch (...) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error configuring batched geometry transitions. If you're using materials with custom\ vertex shaders, they will need to implement fade transitions to be compatible with BatchPage.", "BatchPage::_updateShaders()"); } } } } //Apply the material subBatch->setMaterial(generatedMaterial); }
void BatchPage::_updateShaders() { if (!shadersSupported) return; uint32 i = 0; BatchedGeometry::SubBatchIterator it = batch->getSubBatchIterator(); while (it.hasMoreElements()){ BatchedGeometry::SubBatch *subBatch = it.getNext(); MaterialPtr mat = unfadedMaterials[i++]; //Check if lighting should be enabled bool lightingEnabled = false; for (unsigned short t = 0; t < mat->getNumTechniques(); ++t){ Technique *tech = mat->getTechnique(t); for (unsigned short p = 0; p < tech->getNumPasses(); ++p){ Pass *pass = tech->getPass(p); if (pass->getLightingEnabled()) { lightingEnabled = true; break; } } if (lightingEnabled) break; } //Compile the CG shader script based on various material / fade options StringUtil::StrStreamType tmpName; tmpName << "BatchPage_"; if (fadeEnabled) tmpName << "fade_"; if (lightingEnabled) tmpName << "lit_"; if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) tmpName << "clr_"; for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { String uvType = ""; switch (el->getType()) { case VET_FLOAT1: uvType = "1"; break; case VET_FLOAT2: uvType = "2"; break; case VET_FLOAT3: uvType = "3"; break; case VET_FLOAT4: uvType = "4"; break; } tmpName << uvType << '_'; } } tmpName << "vp"; const String vertexProgName = tmpName.str(); String shaderLanguage; if (Root::getSingleton().getRenderSystem()->getName() == "Direct3D9 Rendering Subsystem") shaderLanguage = "hlsl"; else if(Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem") shaderLanguage = "glsl"; else shaderLanguage = "cg"; //If the shader hasn't been created yet, create it if (HighLevelGpuProgramManager::getSingleton().getByName(vertexProgName).isNull()) { Pass *pass = mat->getTechnique(0)->getPass(0); String vertexProgSource; if(!shaderLanguage.compare("hlsl") || !shaderLanguage.compare("cg")) { vertexProgSource = "void main( \n" " float4 iPosition : POSITION, \n" " float3 normal : NORMAL, \n" " out float4 oPosition : POSITION, \n"; if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource += " float4 iColor : COLOR, \n"; unsigned texNum = 0; for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { String uvType = ""; switch (el->getType()) { case VET_FLOAT1: uvType = "float"; break; case VET_FLOAT2: uvType = "float2"; break; case VET_FLOAT3: uvType = "float3"; break; case VET_FLOAT4: uvType = "float4"; break; } vertexProgSource += " " + uvType + " iUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n" " out " + uvType + " oUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n"; ++texNum; } } vertexProgSource += " out float oFog : FOG, \n" " out float4 oColor : COLOR, \n"; if (lightingEnabled) vertexProgSource += " uniform float4 objSpaceLight, \n" " uniform float4 lightDiffuse, \n" " uniform float4 lightAmbient, \n"; if (fadeEnabled) vertexProgSource += " uniform float3 camPos, \n"; vertexProgSource += " uniform float4x4 worldViewProj, \n" " uniform float fadeGap, \n" " uniform float invisibleDist )\n" "{ \n"; if (lightingEnabled) { //Perform lighting calculations (no specular) vertexProgSource += " float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n" " float diffuseFactor = max(dot(normal, light), 0); \n"; if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n"; else vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse); \n"; } else { if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource += "oColor = iColor; \n"; else vertexProgSource += "oColor = float4(1, 1, 1, 1); \n"; } if (fadeEnabled) vertexProgSource += //Fade out in the distance " float dist = distance(camPos.xz, iPosition.xz); \n" " oColor.a *= (invisibleDist - dist) / fadeGap; \n"; texNum = 0; for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { vertexProgSource += " oUV" + StringConverter::toString(texNum) + " = iUV" + StringConverter::toString(texNum) + "; \n"; ++texNum; } } vertexProgSource += " oPosition = mul(worldViewProj, iPosition); \n" " oFog = oPosition.z; \n" "}"; } if(!shaderLanguage.compare("glsl")) { vertexProgSource = "uniform float fadeGap; \n" "uniform float invisibleDist; \n"; if (lightingEnabled) vertexProgSource += "uniform vec4 objSpaceLight; \n" "uniform vec4 lightDiffuse; \n" "uniform vec4 lightAmbient; \n"; if (fadeEnabled) vertexProgSource += "uniform vec3 camPos; \n"; vertexProgSource += "void main() \n" "{ \n"; if (lightingEnabled) { //Perform lighting calculations (no specular) vertexProgSource += " vec3 light = normalize(objSpaceLight.xyz - (gl_Vertex.xyz * objSpaceLight.w)); \n" " float diffuseFactor = max(dot(gl_Normal, light), 0.0); \n"; if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse) * gl_Color; \n"; } else { vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse); \n"; } } else { if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) { vertexProgSource += " gl_FrontColor = gl_Color; \n"; } else { vertexProgSource += " gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); \n"; } } if (fadeEnabled) { vertexProgSource += //Fade out in the distance " float dist = distance(camPos.xz, gl_Vertex.xz); \n" " gl_FrontColor.a *= (invisibleDist - dist) / fadeGap; \n"; } unsigned texNum = 0; for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { vertexProgSource += " gl_TexCoord[" + StringConverter::toString(texNum) + "] = gl_MultiTexCoord" + StringConverter::toString(texNum) + "; \n"; ++texNum; } } vertexProgSource += " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" " gl_FogFragCoord = gl_Position.z; \n" "}"; } HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram( vertexProgName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, shaderLanguage, GPT_VERTEX_PROGRAM); vertexShader->setSource(vertexProgSource); if (shaderLanguage == "hlsl") { vertexShader->setParameter("target", "vs_1_1"); vertexShader->setParameter("entry_point", "main"); } else if(shaderLanguage == "cg") { vertexShader->setParameter("profiles", "vs_1_1 arbvp1"); vertexShader->setParameter("entry_point", "main"); } // GLSL can only have one entry point "main". vertexShader->load(); } //Now that the shader is ready to be applied, apply it StringUtil::StrStreamType materialSignature; materialSignature << "BatchMat|"; materialSignature << mat->getName() << "|"; if (fadeEnabled){ materialSignature << visibleDist << "|"; materialSignature << invisibleDist << "|"; } //Search for the desired material MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str()); if (generatedMaterial.isNull()){ //Clone the material generatedMaterial = mat->clone(materialSignature.str()); //And apply the fade shader for (unsigned short t = 0; t < generatedMaterial->getNumTechniques(); ++t){ Technique *tech = generatedMaterial->getTechnique(t); for (unsigned short p = 0; p < tech->getNumPasses(); ++p){ Pass *pass = tech->getPass(p); //Setup vertex program if (pass->getVertexProgramName() == "") pass->setVertexProgram(vertexProgName); try{ GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters(); if (lightingEnabled) { params->setNamedAutoConstant("objSpaceLight", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE); params->setNamedAutoConstant("lightDiffuse", GpuProgramParameters::ACT_DERIVED_LIGHT_DIFFUSE_COLOUR); params->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_DERIVED_AMBIENT_LIGHT_COLOUR); //params->setNamedAutoConstant("matAmbient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); } if(shaderLanguage.compare("glsl")) { //glsl can use the built in gl_ModelViewProjectionMatrix params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); } if (fadeEnabled) { params->setNamedAutoConstant("camPos", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); //Set fade ranges params->setNamedAutoConstant("invisibleDist", GpuProgramParameters::ACT_CUSTOM); params->setNamedConstant("invisibleDist", invisibleDist); params->setNamedAutoConstant("fadeGap", GpuProgramParameters::ACT_CUSTOM); params->setNamedConstant("fadeGap", invisibleDist - visibleDist); if (pass->getAlphaRejectFunction() == CMPF_ALWAYS_PASS) pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); } } catch (...) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error configuring batched geometry transitions. If you're using materials with custom vertex shaders, they will need to implement fade transitions to be compatible with BatchPage.", "BatchPage::_updateShaders()"); } } } } //Apply the material subBatch->setMaterial(generatedMaterial); } }
void MeshObject::loadMesh() { try { Ogre::String resourceGroup = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME; mesh = static_cast<Ogre::MeshPtr>(Ogre::MeshManager::getSingleton().create(meshName, resourceGroup)); if(backgroundLoading) { mesh->setBackgroundLoaded(true); mesh->addListener(this); ticket = Ogre::ResourceBackgroundQueue::getSingleton().load( Ogre::MeshManager::getSingletonPtr()->getResourceType(), mesh->getName(), resourceGroup, false, 0, 0, 0); // try to load its textures in the background for(int i=0; i<mesh->getNumSubMeshes(); i++) { SubMesh *sm = mesh->getSubMesh(i); String materialName = sm->getMaterialName(); Ogre::MaterialPtr mat = static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName(materialName)); //, resourceGroup)); if(mat.isNull()) continue; for(int tn=0; tn<mat->getNumTechniques(); tn++) { Technique *t = mat->getTechnique(tn); for(int pn=0; pn<t->getNumPasses(); pn++) { Pass *p = t->getPass(pn); for(int tun=0; tun<p->getNumTextureUnitStates(); tun++) { TextureUnitState *tu = p->getTextureUnitState(tun); String textureName = tu->getTextureName(); // now add this texture to the background loading queue Ogre::TexturePtr tex = static_cast<Ogre::TexturePtr>(Ogre::TextureManager::getSingleton().create(textureName, resourceGroup)); tex->setBackgroundLoaded(true); tex->addListener(this); ticket = Ogre::ResourceBackgroundQueue::getSingleton().load( Ogre::TextureManager::getSingletonPtr()->getResourceType(), tex->getName(), resourceGroup, false, 0, 0, 0); } } } } } if(!backgroundLoading) postProcess(); } catch (Ogre::Exception* e) { LOG("exception while loading mesh: " + e->getFullDescription()); } }
//----------------------------------------------------------------------------- /// MaterialPtr StaticBillboardSet::getFadeMaterial(const Ogre::MaterialPtr &protoMaterial, Real visibleDist_, Real invisibleDist_) { assert(!protoMaterial.isNull()); StringUtil::StrStreamType materialSignature; materialSignature << mEntityName << "|"; materialSignature << visibleDist_ << "|"; materialSignature << invisibleDist_ << "|"; materialSignature << protoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureUScroll() << "|"; materialSignature << protoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureVScroll() << "|"; FadedMaterialMap::iterator it = s_mapFadedMaterial.find(materialSignature.str()); if (it != s_mapFadedMaterial.end()) return it->second; //Use the existing fade material else { MaterialPtr fadeMaterial = protoMaterial->clone(getUniqueID("ImpostorFade")); bool isglsl = Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem" ? true : false; //And apply the fade shader for (unsigned short t = 0; t < fadeMaterial->getNumTechniques(); ++t) { Technique *tech = fadeMaterial->getTechnique(t); for (unsigned short p = 0; p < tech->getNumPasses(); ++p) { Pass *pass = tech->getPass(p); //Setup vertex program pass->setVertexProgram("SpriteFade_vp"); GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters(); //glsl can use the built in gl_ModelViewProjectionMatrix if (!isglsl) params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); static const Ogre::String uScroll = "uScroll", vScroll = "vScroll", preRotatedQuad0 = "preRotatedQuad[0]", preRotatedQuad1 = "preRotatedQuad[1]", preRotatedQuad2 = "preRotatedQuad[2]", preRotatedQuad3 = "preRotatedQuad[3]", camPos = "camPos", fadeGap = "fadeGap", invisibleDist = "invisibleDist"; params->setNamedAutoConstant(uScroll, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(vScroll, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(preRotatedQuad0, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(preRotatedQuad1, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(preRotatedQuad2, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(preRotatedQuad3, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(camPos, GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); params->setNamedAutoConstant(fadeGap, GpuProgramParameters::ACT_CUSTOM); params->setNamedAutoConstant(invisibleDist, GpuProgramParameters::ACT_CUSTOM); //Set fade ranges params->setNamedConstant(invisibleDist, invisibleDist_); params->setNamedConstant(fadeGap, invisibleDist_ - visibleDist_); pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); //pass->setAlphaRejectFunction(CMPF_ALWAYS_PASS); //pass->setDepthWriteEnabled(false); } // for Pass } // for Technique //Add it to the list so it can be reused later s_mapFadedMaterial.insert(std::pair<String, MaterialPtr>(materialSignature.str(), fadeMaterial)); return fadeMaterial; } }
//----------------------------------------------------------------------------- /// void WindBatchPage::_updateShaders() { if (!m_bShadersSupported) return; unsigned int i = 0; BatchedGeometry::TSubBatchIterator it = m_pBatchGeom->getSubBatchIterator(); while (it.hasMoreElements()) { BatchedGeometry::SubBatch *subBatch = it.getNext(); const MaterialPtr &ptrMat = m_vecUnfadedMaterials[i++]; //Check if lighting should be enabled bool lightingEnabled = false; for (unsigned short t = 0, techCnt = ptrMat->getNumTechniques(); t < techCnt; ++t) { Technique *tech = ptrMat->getTechnique(t); for (unsigned short p = 0, passCnt = tech->getNumPasses(); p < passCnt; ++p) { if (tech->getPass(p)->getLightingEnabled()) { lightingEnabled = true; break; } } if (lightingEnabled) break; } //Compile the shader script based on various material / fade options StringUtil::StrStreamType tmpName; tmpName << "BatchPage_"; if (m_bFadeEnabled) tmpName << "fade_"; if (lightingEnabled) tmpName << "lit_"; if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) tmpName << "clr_"; for (unsigned short i = 0; i < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++i) { const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i); if (el->getSemantic() == VES_TEXTURE_COORDINATES) { String uvType; switch (el->getType()) { case VET_FLOAT1: uvType = "1"; break; case VET_FLOAT2: uvType = "2"; break; case VET_FLOAT3: uvType = "3"; break; case VET_FLOAT4: uvType = "4"; break; } tmpName << uvType << '_'; } } tmpName << "vp"; const String vertexProgName = tmpName.str(); String shaderLanguage; if (Root::getSingleton().getRenderSystem()->getName() == "Direct3D9 Rendering Subsystem") shaderLanguage = "hlsl"; else if(Root::getSingleton().getRenderSystem()->getName() == "OpenGL Rendering Subsystem") shaderLanguage = "glsl"; else shaderLanguage = "cg"; ///T removed code for shader creation (we have our own shader) //Now that the shader is ready to be applied, apply it StringUtil::StrStreamType materialSignature; materialSignature << "BatchMat|"; materialSignature << ptrMat->getName() << "|"; if (m_bFadeEnabled) { materialSignature << m_fVisibleDist << "|"; materialSignature << m_fInvisibleDist << "|"; } //Search for the desired material /* MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str()); if (generatedMaterial.isNull()) { //Clone the material std::cout << ptrMat->getName() << std::endl; sh::MaterialInstance* m = sh::Factory::getInstance ().createMaterialInstance (materialSignature.str(), ptrMat->getName()); //generatedMaterial = ptrMat->clone(materialSignature.str()); //And apply the fade shader } */ //Apply the material Ogre::MaterialPtr m = ptrMat; subBatch->setMaterial(m); } }
//------------------------------------------------------------------------- void TerrainSceneManager::setupTerrainMaterial(void) { if (mCustomMaterialName == "") { // define our own material mOptions.terrainMaterial = MaterialManager::getSingleton().getByName(TERRAIN_MATERIAL_NAME); // Make unique terrain material name StringUtil::StrStreamType s; s << mName << "/Terrain"; mOptions.terrainMaterial = MaterialManager::getSingleton().getByName(s.str()); if (mOptions.terrainMaterial.isNull()) { mOptions.terrainMaterial = MaterialManager::getSingleton().create( s.str(), ResourceGroupManager::getSingleton().getWorldResourceGroupName()); } else { mOptions.terrainMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); } Pass* pass = mOptions.terrainMaterial->getTechnique(0)->getPass(0); if ( mWorldTextureName != "" ) { pass->createTextureUnitState( mWorldTextureName, 0 ); } if ( mDetailTextureName != "" ) { pass->createTextureUnitState( mDetailTextureName, 1 ); } mOptions.terrainMaterial -> setLightingEnabled( mOptions.lit ); if (mOptions.lodMorph && mDestRenderSystem->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM) && GpuProgramManager::getSingleton().getByName("Terrain/VertexMorph").isNull()) { // Create & assign LOD morphing vertex program String syntax; if (GpuProgramManager::getSingleton().isSyntaxSupported("arbvp1")) { syntax = "arbvp1"; } else { syntax = "vs_1_1"; } // Get source, and take into account current fog mode FogMode fm = getFogMode(); const String& source = TerrainVertexProgram::getProgramSource( fm, syntax); GpuProgramPtr prog = GpuProgramManager::getSingleton().createProgramFromString( "Terrain/VertexMorph", ResourceGroupManager::getSingleton().getWorldResourceGroupName(), source, GPT_VERTEX_PROGRAM, syntax); // Attach pass->setVertexProgram("Terrain/VertexMorph"); // Get params GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters(); // worldviewproj params->setAutoConstant(0, GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); // morph factor params->setAutoConstant(4, GpuProgramParameters::ACT_CUSTOM, MORPH_CUSTOM_PARAM_ID); // fog exp density(if relevant) if (fm == FOG_EXP || fm == FOG_EXP2) { params->setConstant(5, Vector3(getFogDensity(), 0, 0)); // Override scene fog since otherwise it's applied twice // Set to linear and we derive [0,1] fog value in the shader pass->setFog(true, FOG_LINEAR, getFogColour(), 0, 1, 0); } // Also set shadow receiver program const String& source2 = TerrainVertexProgram::getProgramSource( fm, syntax, true); prog = GpuProgramManager::getSingleton().createProgramFromString( "Terrain/VertexMorphShadowReceive", ResourceGroupManager::getSingleton().getWorldResourceGroupName(), source2, GPT_VERTEX_PROGRAM, syntax); pass->setShadowReceiverVertexProgram("Terrain/VertexMorphShadowReceive"); params = pass->getShadowReceiverVertexProgramParameters(); // worldviewproj params->setAutoConstant(0, GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); // world params->setAutoConstant(4, GpuProgramParameters::ACT_WORLD_MATRIX); // texture view / proj params->setAutoConstant(8, GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX); // morph factor params->setAutoConstant(12, GpuProgramParameters::ACT_CUSTOM, MORPH_CUSTOM_PARAM_ID); if (mDetailTextureName != "") { pass->getTextureUnitState(1)->setTextureCoordSet(1); } // Set param index mLodMorphParamName = ""; mLodMorphParamIndex = 4; } mOptions.terrainMaterial->load(); } else { // Custom material mOptions.terrainMaterial = MaterialManager::getSingleton().getByName(mCustomMaterialName); if (mOptions.terrainMaterial.isNull()){ OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Material " + mCustomMaterialName + " not found.", "TerrainSceneManager::setupTerrainMaterial"); } mOptions.terrainMaterial->load(); } // now set up the linkage between vertex program and LOD morph param if (mOptions.lodMorph) { Technique* t = mOptions.terrainMaterial->getBestTechnique(); for (ushort i = 0; i < t->getNumPasses(); ++i) { Pass* p = t->getPass(i); if (p->hasVertexProgram()) { // we have to assume vertex program includes LOD morph capability GpuProgramParametersSharedPtr params = p->getVertexProgramParameters(); // Check to see if custom param is already there GpuProgramParameters::AutoConstantIterator aci = params->getAutoConstantIterator(); bool found = false; while (aci.hasMoreElements()) { const GpuProgramParameters::AutoConstantEntry& ace = aci.getNext(); if (ace.paramType == GpuProgramParameters::ACT_CUSTOM && ace.data == MORPH_CUSTOM_PARAM_ID) { found = true; } } if (!found) { if(mLodMorphParamName != "") { params->setNamedAutoConstant(mLodMorphParamName, GpuProgramParameters::ACT_CUSTOM, MORPH_CUSTOM_PARAM_ID); } else { params->setAutoConstant(mLodMorphParamIndex, GpuProgramParameters::ACT_CUSTOM, MORPH_CUSTOM_PARAM_ID); } } } } } }