History: Multiple Light Terrain
Source of version: 5 (current)
Copy to clipboard
!Multiple Light Terrain
[http://www.ogre3d.org/forums/viewtopic.php?f=2&t=70004|Forum post]
This is a Terrain Material Generator that supports multiple point lights.
!!!-.h File
{CODE(wrap="1", colors="c++")}
#ifndef __Ogre_TerrainMaterialGeneratorB_H__
#define __Ogre_TerrainMaterialGeneratorB_H__
#include <Terrain\OgreTerrainMaterialGenerator.h>
#include <Terrain\OgreTerrainPrerequisites.h>
#include <OgreGpuProgramParams.h>
namespace Ogre
{
class PSSMShadowCameraSetup;
/** \addtogroup Optional Components
* @{
*/
/** \addtogroup Terrain
* Some details on the terrain component
* @{
*/
/** A TerrainMaterialGenerator which can cope with normal mapped, specular mapped
terrain.
Supports 8 point lights and 1 directional light.
@note Requires the Cg plugin to render correctly
@note shader model 2
*/
class TerrainMaterialGeneratorB : public TerrainMaterialGenerator
{
public:
TerrainMaterialGeneratorB();
~TerrainMaterialGeneratorB();
/** Shader model 2 profile target.
*/
class SM2Profile : public TerrainMaterialGenerator::Profile
{
public:
SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc);
~SM2Profile();
bool isVertexCompressionSupported() const {return false;}
MaterialPtr generate(const Terrain* terrain);
MaterialPtr generateForCompositeMap(const Terrain* terrain);
uint8 getMaxLayers(const Terrain* terrain) const;
void updateParams(const MaterialPtr& mat, const Terrain* terrain);
void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain);
void requestOptions(Terrain* terrain);
void setShadowFar(float far);
void setShadowFadeStart(float fadestart);
/** Whether to support normal mapping per layer in the shader (default true).
*/
bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; }
/** Whether to support normal mapping per layer in the shader (default true).
*/
void setLayerNormalMappingEnabled(bool enabled);
/** Whether to support parallax mapping per layer in the shader (default true).
*/
bool isLayerParallaxMappingEnabled() const { return mLayerParallaxMappingEnabled; }
/** Whether to support parallax mapping per layer in the shader (default true).
*/
void setLayerParallaxMappingEnabled(bool enabled);
/** Whether to support specular mapping per layer in the shader (default true).
*/
bool isLayerSpecularMappingEnabled() const { return mLayerSpecularMappingEnabled; }
/** Whether to support specular mapping per layer in the shader (default true).
*/
void setLayerSpecularMappingEnabled(bool enabled);
/** Whether to support a global colour map over the terrain in the shader,
if it's present (default true).
*/
bool isGlobalColourMapEnabled() const { return mGlobalColourMapEnabled; }
/** Whether to support a global colour map over the terrain in the shader,
if it's present (default true).
*/
void setGlobalColourMapEnabled(bool enabled);
/** Whether to support a light map over the terrain in the shader,
if it's present (default true).
*/
bool isLightmapEnabled() const { return mLightmapEnabled; }
/** Whether to support a light map over the terrain in the shader,
if it's present (default true).
*/
void setLightmapEnabled(bool enabled);
/** Whether to use the composite map to provide a lower LOD technique
in the distance (default true).
*/
bool isCompositeMapEnabled() const { return mCompositeMapEnabled; }
/** Whether to use the composite map to provide a lower LOD technique
in the distance (default true).
*/
void setCompositeMapEnabled(bool enabled);
/** Whether to support dynamic texture shadows received from other
objects, on the terrain (default true).
*/
bool getReceiveDynamicShadowsEnabled() const { return mReceiveDynamicShadows; }
/** Whether to support dynamic texture shadows received from other
objects, on the terrain (default true).
*/
void setReceiveDynamicShadowsEnabled(bool enabled);
/** Whether to use PSSM support dynamic texture shadows, and if so the
settings to use (default 0).
*/
void setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings);
/** Whether to use PSSM support dynamic texture shadows, and if so the
settings to use (default 0).
*/
PSSMShadowCameraSetup* getReceiveDynamicShadowsPSSM() const { return mPSSM; }
/** Whether to use depth shadows (default false).
*/
void setReceiveDynamicShadowsDepth(bool enabled);
/** Whether to use depth shadows (default false).
*/
bool getReceiveDynamicShadowsDepth() const { return mDepthShadows; }
/** Whether to use shadows on low LOD material rendering (when using composite map) (default false).
*/
void setReceiveDynamicShadowsLowLod(bool enabled);
/** Whether to use shadows on low LOD material rendering (when using composite map) (default false).
*/
bool getReceiveDynamicShadowsLowLod() const { return mLowLodShadows; }
int getNumberOfLightsSupported() const;
/// Internal
bool _isSM3Available() const { return mSM3Available; }
protected:
enum TechniqueType
{
HIGH_LOD,
LOW_LOD,
RENDER_COMPOSITE_MAP
};
void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt);
/// Interface definition for helper class to generate shaders
class ShaderHelper : public TerrainAlloc
{
public:
ShaderHelper() : mShadowSamplerStartHi(0), mShadowSamplerStartLo(0) {}
virtual ~ShaderHelper() {}
virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
virtual void updateParams(const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap);
protected:
virtual String getVertexProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
virtual String getFragmentProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
virtual HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0;
virtual HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0;
virtual void generateVertexProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
virtual void generateFragmentProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
virtual void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
virtual void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
virtual void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0;
virtual void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0;
virtual void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
virtual void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0;
virtual void defaultVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog);
virtual void defaultFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog);
virtual void updateVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params);
virtual void updateFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params);
static String getChannel(uint idx);
size_t mShadowSamplerStartHi;
size_t mShadowSamplerStartLo;
};
/// Utility class to help with generating shaders for Cg / HLSL.
class ShaderHelperCg : public ShaderHelper
{
protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream);
void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream);
void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
uint generateVpDynamicShadowsParams(uint texCoordStart, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateVpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateFpDynamicShadowsHelpers(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateFpDynamicShadowsParams(uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
void generateFpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream);
};
class ShaderHelperHLSL : public ShaderHelperCg
{
protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
};
/// Utility class to help with generating shaders for GLSL.
class ShaderHelperGLSL : public ShaderHelper
{
protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {}
void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {}
void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {}
};
ShaderHelper* mShaderGen;
bool mLayerNormalMappingEnabled;
bool mLayerParallaxMappingEnabled;
bool mLayerSpecularMappingEnabled;
bool mGlobalColourMapEnabled;
bool mLightmapEnabled;
bool mCompositeMapEnabled;
bool mReceiveDynamicShadows;
PSSMShadowCameraSetup* mPSSM;
bool mDepthShadows;
bool mLowLodShadows;
bool mSM3Available;
float mShadowFar;
float mShadowFadeStart;
bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const;
};
};
/** @} */
/** @} */
}
#endif
{CODE}
!!!
!!!-.cpp File
{CODE(wrap="1", colors="c++")}
#include "TerrainMaterialGeneratorB.h"
#include <Terrain\OgreTerrain.h>
#include <OgreMaterialManager.h>
#include <OgreTechnique.h>
#include <OgrePass.h>
#include <OgreTextureUnitState.h>
#include <OgreGpuProgramManager.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreShadowCameraSetupPSSM.h>
namespace Ogre
{
//---------------------------------------------------------------------
TerrainMaterialGeneratorB::TerrainMaterialGeneratorB()
{
// define the layers
// We expect terrain textures to have no alpha, so we use the alpha channel
// in the albedo texture to store specular reflection
// similarly we double-up the normal and height (for parallax)
mLayerDecl.samplers.push_back(TerrainLayerSampler("albedo_specular", PF_BYTE_RGBA));
mLayerDecl.samplers.push_back(TerrainLayerSampler("normal_height", PF_BYTE_RGBA));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(0, TLSS_ALBEDO, 0, 3));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(0, TLSS_SPECULAR, 3, 1));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(1, TLSS_NORMAL, 0, 3));
mLayerDecl.elements.push_back(
TerrainLayerSamplerElement(1, TLSS_HEIGHT, 3, 1));
mProfiles.push_back(OGRE_NEW SM2Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards"));
//! @todo - check hardware capabilities & use fallbacks if required (more profiles needed)
setActiveProfile("SM2");
}
//---------------------------------------------------------------------
TerrainMaterialGeneratorB::~TerrainMaterialGeneratorB()
{
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
TerrainMaterialGeneratorB::SM2Profile::SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc)
: Profile(parent, name, desc)
, mShaderGen(0)
, mLayerNormalMappingEnabled(true)
, mLayerParallaxMappingEnabled(true)
, mLayerSpecularMappingEnabled(true)
, mGlobalColourMapEnabled(true)
, mLightmapEnabled(true)
, mCompositeMapEnabled(true)
, mReceiveDynamicShadows(true)
, mPSSM(0)
, mDepthShadows(false)
, mLowLodShadows(false)
{
}
//---------------------------------------------------------------------
TerrainMaterialGeneratorB::SM2Profile::~SM2Profile()
{
OGRE_DELETE mShaderGen;
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::requestOptions(Terrain* terrain)
{
terrain->_setMorphRequired(true);
terrain->_setNormalMapRequired(true);
terrain->_setLightMapRequired(mLightmapEnabled, true);
terrain->_setCompositeMapRequired(mCompositeMapEnabled);
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled)
{
if (enabled != mLayerNormalMappingEnabled)
{
mLayerNormalMappingEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setLayerParallaxMappingEnabled(bool enabled)
{
if (enabled != mLayerParallaxMappingEnabled)
{
mLayerParallaxMappingEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setLayerSpecularMappingEnabled(bool enabled)
{
if (enabled != mLayerSpecularMappingEnabled)
{
mLayerSpecularMappingEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setGlobalColourMapEnabled(bool enabled)
{
if (enabled != mGlobalColourMapEnabled)
{
mGlobalColourMapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setLightmapEnabled(bool enabled)
{
if (enabled != mLightmapEnabled)
{
mLightmapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setCompositeMapEnabled(bool enabled)
{
if (enabled != mCompositeMapEnabled)
{
mCompositeMapEnabled = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsEnabled(bool enabled)
{
if (enabled != mReceiveDynamicShadows)
{
mReceiveDynamicShadows = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings)
{
if (pssmSettings != mPSSM)
{
mPSSM = pssmSettings;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsDepth(bool enabled)
{
if (enabled != mDepthShadows)
{
mDepthShadows = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsLowLod(bool enabled)
{
if (enabled != mLowLodShadows)
{
mLowLodShadows = enabled;
mParent->_markChanged();
}
}
//---------------------------------------------------------------------
uint8 TerrainMaterialGeneratorB::SM2Profile::getMaxLayers(const Terrain* terrain) const
{
// count the texture units free
uint8 freeTextureUnits = 16;
// lightmap
--freeTextureUnits;
// normalmap
--freeTextureUnits;
// colourmap
if (terrain->getGlobalColourMapEnabled())
--freeTextureUnits;
if (isShadowingEnabled(HIGH_LOD, terrain))
{
uint numShadowTextures = 1;
if (getReceiveDynamicShadowsPSSM())
{
numShadowTextures = getReceiveDynamicShadowsPSSM()->getSplitCount();
}
freeTextureUnits -= numShadowTextures;
}
// each layer needs 2.25 units (1xdiffusespec, 1xnormalheight, 0.25xblend)
return static_cast<uint8>(freeTextureUnits / 2.25f);
}
//---------------------------------------------------------------------
//added to return 9 light total; 1 directional, 8 point
int TerrainMaterialGeneratorB::SM2Profile::getNumberOfLightsSupported() const
{
return 9;
}
//---------------------------------------------------------------------
MaterialPtr TerrainMaterialGeneratorB::SM2Profile::generate(const Terrain* terrain)
{
// re-use old material if exists
MaterialPtr mat = terrain->_getMaterial();
if (mat.isNull())
{
MaterialManager& matMgr = MaterialManager::getSingleton();
// it's important that the names are deterministic for a given terrain, so
// use the terrain pointer as an ID
const String& matName = terrain->getMaterialName();
mat = matMgr.getByName(matName);
if (mat.isNull())
{
mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}
}
// clear everything
mat->removeAllTechniques();
// Automatically disable normal & parallax mapping if card cannot handle it
// We do this rather than having a specific technique for it since it's simpler
GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
if (!gmgr.isSyntaxSupported("ps_3_0") && !gmgr.isSyntaxSupported("ps_2_x")
&& !gmgr.isSyntaxSupported("fp40") && !gmgr.isSyntaxSupported("arbfp1"))
{
setLayerNormalMappingEnabled(false);
setLayerParallaxMappingEnabled(false);
}
addTechnique(mat, terrain, HIGH_LOD);
// LOD
if(mCompositeMapEnabled)
{
addTechnique(mat, terrain, LOW_LOD);
Material::LodValueList lodValues;
lodValues.push_back(TerrainGlobalOptions::getSingleton().getCompositeMapDistance());
mat->setLodLevels(lodValues);
Technique* lowLodTechnique = mat->getTechnique(1);
lowLodTechnique->setLodIndex(1);
}
updateParams(mat, terrain);
return mat;
}
//---------------------------------------------------------------------
MaterialPtr TerrainMaterialGeneratorB::SM2Profile::generateForCompositeMap(const Terrain* terrain)
{
// re-use old material if exists
MaterialPtr mat = terrain->_getCompositeMapMaterial();
if (mat.isNull())
{
MaterialManager& matMgr = MaterialManager::getSingleton();
// it's important that the names are deterministic for a given terrain, so
// use the terrain pointer as an ID
const String& matName = terrain->getMaterialName() + "/comp";
mat = matMgr.getByName(matName);
if (mat.isNull())
{
mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}
}
// clear everything
mat->removeAllTechniques();
addTechnique(mat, terrain, RENDER_COMPOSITE_MAP);
updateParamsForCompositeMap(mat, terrain);
return mat;
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::addTechnique(
const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)
{
Technique* tech = mat->createTechnique();
// Only supporting one pass
Pass* pass = tech->createPass();
GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
if (!mShaderGen)
{
bool check2x = mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled;
if (hmgr.isLanguageSupported("cg"))
mShaderGen = OGRE_NEW ShaderHelperCg();
else if (hmgr.isLanguageSupported("hlsl") &&
((check2x && gmgr.isSyntaxSupported("ps_2_x")) ||
(!check2x && gmgr.isSyntaxSupported("ps_2_0"))))
mShaderGen = OGRE_NEW ShaderHelperHLSL();
else if (hmgr.isLanguageSupported("glsl"))
mShaderGen = OGRE_NEW ShaderHelperGLSL();
else
{
// todo
}
// check SM3 features
mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0");
}
HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt);
HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt);
pass->setVertexProgram(vprog->getName());
pass->setFragmentProgram(fprog->getName());
if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP)
{
// global normal map
TextureUnitState* tu = pass->createTextureUnitState();
tu->setTextureName(terrain->getTerrainNormalMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
// global colour map
if (terrain->getGlobalColourMapEnabled() && isGlobalColourMapEnabled())
{
tu = pass->createTextureUnitState(terrain->getGlobalColourMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// light map
if (isLightmapEnabled())
{
tu = pass->createTextureUnitState(terrain->getLightmap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// blend maps
uint maxLayers = getMaxLayers(terrain);
uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numBlendTextures; ++i)
{
tu = pass->createTextureUnitState(terrain->getBlendTextureName(i));
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
}
// layer textures
for (uint i = 0; i < numLayers; ++i)
{
// diffuse / specular
tu = pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
// normal / height
tu = pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
}
}
else
{
// LOW_LOD textures
// composite map
TextureUnitState* tu = pass->createTextureUnitState();
tu->setTextureName(terrain->getCompositeMap()->getName());
tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
// That's it!
}
// Add shadow textures (always at the end)
if (isShadowingEnabled(tt, terrain))
{
uint numTextures = 1;
if (getReceiveDynamicShadowsPSSM())
{
numTextures = getReceiveDynamicShadowsPSSM()->getSplitCount();
}
for (uint i = 0; i < numTextures; ++i)
{
TextureUnitState* tu = pass->createTextureUnitState();
tu->setContentType(TextureUnitState::CONTENT_SHADOW);
tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
tu->setTextureBorderColour(ColourValue::White);
}
}
//! @todo caustics still don't work
//! @todo maybe add optin to set here
if(true)
{
TextureUnitState* tu = pass->createTextureUnitState();
tu->setAnimatedTextureName("Caustic.bmp",16,1.5);
tu->setColourOperationEx(LayerBlendOperationEx::LBX_MODULATE,LayerBlendSource::LBS_CURRENT,LayerBlendSource::LBS_TEXTURE);
tu->setTextureScale(0.1,0.1);
}
}
//---------------------------------------------------------------------
bool TerrainMaterialGeneratorB::SM2Profile::isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const
{
return getReceiveDynamicShadowsEnabled() && tt != RENDER_COMPOSITE_MAP &&
(tt != LOW_LOD || mLowLodShadows) &&
terrain->getSceneManager()->isShadowTechniqueTextureBased();
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::updateParams(const MaterialPtr& mat, const Terrain* terrain)
{
mShaderGen->updateParams(this, mat, terrain, false);
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain)
{
mShaderGen->updateParams(this, mat, terrain, true);
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramPtr ret = createVertexProgram(prof, terrain, tt);
StringUtil::StrStreamType sourceStr;
generateVertexProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str());
ret->load();
defaultVpParams(prof, terrain, tt, ret);
#if OGRE_DEBUG_MODE
LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Vertex Program: "
<< ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
#endif
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramPtr ret = createFragmentProgram(prof, terrain, tt);
StringUtil::StrStreamType sourceStr;
generateFragmentProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str());
ret->load();
defaultFpParams(prof, terrain, tt, ret);
#if OGRE_DEBUG_MODE
LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Fragment Program: "
<< ret->getName() << " ***\n" << ret->getSource() << "\n*** ***";
#endif
return ret;
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateVertexProgramSource(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
generateVpHeader(prof, terrain, tt, outStream);
if (tt != LOW_LOD)
{
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numLayers; ++i)
generateVpLayer(prof, terrain, tt, i, outStream);
}
generateVpFooter(prof, terrain, tt, outStream);
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateFragmentProgramSource(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
generateFpHeader(prof, terrain, tt, outStream);
if (tt != LOW_LOD)
{
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
for (uint i = 0; i < numLayers; ++i)
generateFpLayer(prof, terrain, tt, i, outStream);
}
generateFpFooter(prof, terrain, tt, outStream);
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::defaultVpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
{
GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
params->setIgnoreMissingParams(true);
params->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX);
params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM,
Terrain::LOD_MORPH_CUSTOM_PARAM);
params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (prof->isShadowingEnabled(tt, terrain))
{
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
}
for (uint i = 0; i < numTextures; ++i)
{
params->setNamedAutoConstant("texViewProjMatrix" + StringConverter::toString(i),
GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
if (prof->getReceiveDynamicShadowsDepth())
{
params->setNamedAutoConstant("depthRange" + StringConverter::toString(i),
GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i);
}
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::defaultFpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog)
{
GpuProgramParametersSharedPtr params = prog->getDefaultParameters();
params->setIgnoreMissingParams(true);
params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
// openMW MULTILIGHT
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
params->setNamedAutoConstant("lightPosObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i);
params->setNamedAutoConstant("lightDiffuseColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i);
if (i > 0)
params->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i);
if(i == 0)
params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, i);
}
//params->setNamedAutoConstant("lightPosObjSpace", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, 0);
//params->setNamedAutoConstant("lightDiffuseColour", GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 0);
//params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 0);
params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
if (prof->isShadowingEnabled(tt, terrain))
{
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
PSSMShadowCameraSetup* pssm = prof->getReceiveDynamicShadowsPSSM();
numTextures = pssm->getSplitCount();
Vector4 splitPoints;
const PSSMShadowCameraSetup::SplitPointList& splitPointList = pssm->getSplitPoints();
// Populate from split point 1, not 0, since split 0 isn't useful (usually 0)
for (uint i = 1; i < numTextures; ++i)
{
splitPoints[i-1] = splitPointList[i];
}
params->setNamedConstant("pssmSplitPoints", splitPoints);
}
if (prof->getReceiveDynamicShadowsDepth())
{
size_t samplerOffset = (tt == HIGH_LOD) ? mShadowSamplerStartHi : mShadowSamplerStartLo;
for (uint i = 0; i < numTextures; ++i)
{
params->setNamedAutoConstant("inverseShadowmapSize" + StringConverter::toString(i),
GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i + samplerOffset);
}
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateParams(
const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap)
{
Pass* p = mat->getTechnique(0)->getPass(0);
if (compositeMap)
{
updateVpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getVertexProgramParameters());
updateFpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getFragmentProgramParameters());
}
else
{
// high lod
updateVpParams(prof, terrain, HIGH_LOD, p->getVertexProgramParameters());
updateFpParams(prof, terrain, HIGH_LOD, p->getFragmentProgramParameters());
if(prof->isCompositeMapEnabled())
{
// low lod
p = mat->getTechnique(1)->getPass(0);
updateVpParams(prof, terrain, LOW_LOD, p->getVertexProgramParameters());
updateFpParams(prof, terrain, LOW_LOD, p->getFragmentProgramParameters());
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateVpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
{
params->setIgnoreMissingParams(true);
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVMul = numLayers / 4;
if (numLayers % 4)
++numUVMul;
for (uint i = 0; i < numUVMul; ++i)
{
Vector4 uvMul(
terrain->getLayerUVMultiplier(i * 4),
terrain->getLayerUVMultiplier(i * 4 + 1),
terrain->getLayerUVMultiplier(i * 4 + 2),
terrain->getLayerUVMultiplier(i * 4 + 3)
);
params->setNamedConstant("uvMul" + StringConverter::toString(i), uvMul);
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateFpParams(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params)
{
params->setIgnoreMissingParams(true);
// TODO - parameterise this?
Vector4 scaleBiasSpecular(0.03, -0.04, 32, 0.5);
params->setNamedConstant("scaleBiasSpecular", scaleBiasSpecular);
}
//---------------------------------------------------------------------
String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getChannel(uint idx)
{
uint rem = idx % 4;
switch(rem)
{
case 0:
default:
return "r";
case 1:
return "g";
case 2:
return "b";
case 3:
return "a";
};
}
//---------------------------------------------------------------------
String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getVertexProgramName(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
String progName = terrain->getMaterialName() + "/sm2/vp";
switch(tt)
{
case HIGH_LOD:
progName += "/hlod";
break;
case LOW_LOD:
progName += "/llod";
break;
case RENDER_COMPOSITE_MAP:
progName += "/comp";
break;
}
return progName;
}
//---------------------------------------------------------------------
String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getFragmentProgramName(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
String progName = terrain->getMaterialName() + "/sm2/fp";
switch(tt)
{
case HIGH_LOD:
progName += "/hlod";
break;
case LOW_LOD:
progName += "/llod";
break;
case RENDER_COMPOSITE_MAP:
progName += "/comp";
break;
}
return progName;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::createVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getVertexProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_VERTEX_PROGRAM);
}
else
{
ret->unload();
}
ret->setParameter("profiles", "vs_3_0 vs_2_0 arbvp1");
ret->setParameter("entry_point", "main_vp");
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::createFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getFragmentProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
}
else
{
ret->unload();
}
if(prof->isLayerNormalMappingEnabled() || prof->isLayerParallaxMappingEnabled())
ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1");
else
ret->setParameter("profiles", "ps_3_0 ps_2_0 fp30 arbfp1");
ret->setParameter("entry_point", "main_fp");
return ret;
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpHeader(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
outStream <<
"void main_vp(\n"
"float4 pos : POSITION,\n"
"float2 uv : TEXCOORD0,\n";
if (tt != RENDER_COMPOSITE_MAP)
outStream << "float2 delta : TEXCOORD1,\n"; // lodDelta, lodThreshold
outStream <<
"uniform float4x4 worldMatrix,\n"
"uniform float4x4 viewProjMatrix,\n"
"uniform float2 lodMorph,\n"; // morph amount, morph LOD target
// uv multipliers
uint maxLayers = prof->getMaxLayers(terrain);
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVMultipliers = (numLayers / 4);
if (numLayers % 4)
++numUVMultipliers;
for (uint i = 0; i < numUVMultipliers; ++i)
outStream << "uniform float4 uvMul" << i << ", \n";
outStream <<
"out float4 oPos : POSITION,\n"
"out float4 oPosObj : TEXCOORD0 \n";
uint texCoordSet = 1;
outStream <<
", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n";
// layer UV's premultiplied, packed as xy/zw
uint numUVSets = numLayers / 2;
if (numLayers % 2)
++numUVSets;
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
outStream <<
", out float4 oUV" << i << " : TEXCOORD" << texCoordSet++ << "\n";
}
}
if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
{
outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n";
}
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream <<
", uniform float4 fogParams\n"
", out float fogVal : COLOR\n";
}
if (prof->isShadowingEnabled(tt, terrain))
{
texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream);
}
// check we haven't exceeded texture coordinates
if (texCoordSet > 8)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"Requested options require too many texture coordinate sets! Try reducing the number of layers.",
__FUNCTION__);
}
outStream <<
")\n"
"{\n"
" float4 worldPos = mul(worldMatrix, pos);\n"
" oPosObj = pos;\n";
if (tt != RENDER_COMPOSITE_MAP)
{
// determine whether to apply the LOD morph to this vertex
// we store the deltas against all vertices so we only want to apply
// the morph to the ones which would disappear. The target LOD which is
// being morphed to is stored in lodMorph.y, and the LOD at which
// the vertex should be morphed is stored in uv.w. If we subtract
// the former from the latter, and arrange to only morph if the
// result is negative (it will only be -1 in fact, since after that
// the vertex will never be indexed), we will achieve our aim.
// sign(vertexLOD - targetLOD) == -1 is to morph
outStream <<
" float toMorph = -min(0, sign(delta.y - lodMorph.y));\n";
// this will either be 1 (morph) or 0 (don't morph)
if (prof->getParent()->getDebugLevel())
{
// x == LOD level (-1 since value is target level, we want to display actual)
outStream << "lodInfo.x = (lodMorph.y - 1) / " << terrain->getNumLodLevels() << ";\n";
// y == LOD morph
outStream << "lodInfo.y = toMorph * lodMorph.x;\n";
}
// morph
switch (terrain->getAlignment())
{
case Terrain::ALIGN_X_Y:
outStream << " worldPos.z += delta.x * toMorph * lodMorph.x;\n";
break;
case Terrain::ALIGN_X_Z:
outStream << " worldPos.y += delta.x * toMorph * lodMorph.x;\n";
break;
case Terrain::ALIGN_Y_Z:
outStream << " worldPos.x += delta.x * toMorph * lodMorph.x;\n";
break;
};
}
// generate UVs
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
uint layer = i * 2;
uint uvMulIdx = layer / 4;
outStream <<
" oUV" << i << ".xy = " << " uv.xy * uvMul" << uvMulIdx << "." << getChannel(layer) << ";\n";
outStream <<
" oUV" << i << ".zw = " << " uv.xy * uvMul" << uvMulIdx << "." << getChannel(layer+1) << ";\n";
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpHeader(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
// Main header
outStream <<
// helpers
"float4 expand(float4 v)\n"
"{ \n"
" return v * 2 - 1;\n"
"}\n\n\n";
if (prof->isShadowingEnabled(tt, terrain))
generateFpDynamicShadowsHelpers(prof, terrain, tt, outStream);
outStream <<
"float4 main_fp(\n"
"float4 position : TEXCOORD0,\n";
uint texCoordSet = 1;
outStream <<
"float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n";
// UV's premultiplied, packed as xy/zw
uint maxLayers = prof->getMaxLayers(terrain);
uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
uint numUVSets = numLayers / 2;
if (numLayers % 2)
++numUVSets;
if (tt != LOW_LOD)
{
for (uint i = 0; i < numUVSets; ++i)
{
outStream <<
"float4 layerUV" << i << " : TEXCOORD" << texCoordSet++ << ", \n";
}
}
if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP)
{
outStream << "float2 lodInfo : TEXCOORD" << texCoordSet++ << ", \n";
}
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream <<
"uniform float3 fogColour, \n"
"float fogVal : COLOR,\n";
}
uint currentSamplerIdx = 0;
outStream <<
// Only 1 light supported in this version
// deferred shading profile / generator later, ok? :)
"uniform float3 ambient,\n";
//MULTILIGHT for loop num lights here
//"uniform float4 lightPosObjSpace,\n"
//"uniform float3 lightDiffuseColour,\n"
//"uniform float3 lightSpecularColour,\n"
//openmw adds attenuation for num light - 9 lights here; probly one directional light all more pont lights
//en here
//openmw multi
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
outStream <<
"uniform float4 lightPosObjSpace"<<i<<",\n"
"uniform float3 lightDiffuseColour"<<i<<",\n"
//"uniform float3 lightSpecularColour"<<i<<",\n"
;
if(i == 0)
outStream << "uniform float3 lightSpecularColour,\n";
if (i > 0)
outStream <<
"uniform float4 lightAttenuation"<<i<<",\n";
}
outStream <<
"uniform float3 eyePosObjSpace,\n"
// pack scale, bias and specular
"uniform float4 scaleBiasSpecular,\n";
if (tt == LOW_LOD)
{
// single composite map covers all the others below
outStream <<
"uniform sampler2D compositeMap : register(s" << currentSamplerIdx++ << ")\n";
}
else
{
outStream <<
"uniform sampler2D globalNormal : register(s" << currentSamplerIdx++ << ")\n";
if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
{
outStream << ", uniform sampler2D globalColourMap : register(s"
<< currentSamplerIdx++ << ")\n";
}
if (prof->isLightmapEnabled())
{
outStream << ", uniform sampler2D lightMap : register(s"
<< currentSamplerIdx++ << ")\n";
}
// Blend textures - sampler definitions
for (uint i = 0; i < numBlendTextures; ++i)
{
outStream << ", uniform sampler2D blendTex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
}
// Layer textures - sampler definitions & UV multipliers
for (uint i = 0; i < numLayers; ++i)
{
outStream << ", uniform sampler2D difftex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
outStream << ", uniform sampler2D normtex" << i
<< " : register(s" << currentSamplerIdx++ << ")\n";
}
}
if (prof->isShadowingEnabled(tt, terrain))
{
generateFpDynamicShadowsParams(&texCoordSet, ¤tSamplerIdx, prof, terrain, tt, outStream);
}
// check we haven't exceeded samplers
if (currentSamplerIdx > 16)
{
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
"Requested options require too many texture samplers! Try reducing the number of layers.",
__FUNCTION__);
}
outStream <<
") : COLOR\n"
"{\n"
" float4 outputCol;\n"
" float shadow = 1.0;\n"
" float2 uv = uvMisc.xy;\n"
// base colour
" outputCol = float4(0,0,0,1);\n";
if (tt != LOW_LOD)
{
outStream <<
// global normal
" float3 normal = expand(tex2D(globalNormal, uv)).rgb;\n";
}
// openMW MULTILIAGHT
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream <<
" float3 lightDir"<<i<<" = \n"
" lightPosObjSpace"<<i<<".xyz - (position.xyz * lightPosObjSpace"<<i<<".w);\n";
//outStream <<
// " float3 lightDir = \n"
// " lightPosObjSpace.xyz - (position.xyz * lightPosObjSpace.w);\n";
outStream <<
" float3 eyeDir = eyePosObjSpace - position.xyz;\n"
// set up accumulation areas
" float3 diffuse = float3(0,0,0);\n"
" float specular = 0;\n";
if (tt == LOW_LOD)
{
// we just do a single calculation from composite map
outStream <<
" float4 composite = tex2D(compositeMap, uv);\n"
" diffuse = composite.rgb;\n";
// TODO - specular; we'll need normals for this!
}
else
{
// set up the blend values
for (uint i = 0; i < numBlendTextures; ++i)
{
outStream << " float4 blendTexVal" << i << " = tex2D(blendTex" << i << ", uv);\n";
}
if (prof->isLayerNormalMappingEnabled())
{
// derive the tangent space basis
// we do this in the pixel shader because we don't have per-vertex normals
// because of the LOD, we use a normal map
// tangent is always +x or -z in object space depending on alignment
switch(terrain->getAlignment())
{
case Terrain::ALIGN_X_Y:
case Terrain::ALIGN_X_Z:
outStream << " float3 tangent = float3(1, 0, 0);\n";
break;
case Terrain::ALIGN_Y_Z:
outStream << " float3 tangent = float3(0, 0, -1);\n";
break;
};
outStream << " float3 binormal = normalize(cross(tangent, normal));\n";
// note, now we need to re-cross to derive tangent again because it wasn't orthonormal
outStream << " tangent = normalize(cross(normal, binormal));\n";
// derive final matrix
outStream << " float3x3 TBN = float3x3(tangent, binormal, normal);\n";
// set up lighting result placeholders for interpolation
outStream << " float4 litRes, litResLayer;\n";
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " float4 litResLayer"<<i<<";\n";
//outStream << " float3 TSlightDir;\n";
//outStream << " float3 TShalfAngle;\n";
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " float3 TShalfAngle"<<i<<";\n";
outStream << " float3 TSeyeDir, TSnormal;\n";
if (prof->isLayerParallaxMappingEnabled())
outStream << " float displacement;\n";
// move
//outStream << " TSlightDir = normalize(mul(TBN, lightDir));\n";
outStream << " TSeyeDir = normalize(mul(TBN, eyeDir));\n";
//init litRes<i> vars
if (prof->getNumberOfLightsSupported() > 1)
outStream << "float d; \n"
"float attn; \n";
outStream <<
" eyeDir = normalize(eyeDir); \n";
// simple per-pixel lighting with no normal mapping
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
outStream <<
" float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), dot(normalize(lightDir"<<i<<"+eyeDir),normalize(normal)), scaleBiasSpecular.z);\n";
outStream <<
" float3 TSlightDir"<<i<<" = normalize(mul(TBN, lightDir"<<i<<"));\n";
if (i > 0)
outStream <<
// pre-multiply light color with attenuation factor
"d = length( lightDir"<<i<<" ); \n"
"attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
"lightDiffuseColour"<<i<<" *= attn; \n";
}
//init litRes<i> vars END
}
else
{
// openMW MULTILIGHT
if (prof->getNumberOfLightsSupported() > 1)
outStream << "float d; \n"
"float attn; \n";
outStream <<
" eyeDir = normalize(eyeDir); \n";
// simple per-pixel lighting with no normal mapping
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
outStream <<
//" float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), 0, scaleBiasSpecular.z);\n";
" float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), dot(normalize(lightDir"<<i<<"+eyeDir),normalize(normal)), scaleBiasSpecular.z);\n";
if (i > 0)
outStream <<
// pre-multiply light color with attenuation factor
"d = length( lightDir"<<i<<" ); \n"
"attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
"lightDiffuseColour"<<i<<" *= attn; \n";
}
// simple per-pixel lighting with no normal mapping
//outStream << " lightDir = normalize(lightDir);\n";
//outStream << " eyeDir = normalize(eyeDir);\n";
//outStream << " float3 halfAngle = normalize(lightDir + eyeDir);\n";
//outStream << " float4 litRes = lit(dot(lightDir, normal), dot(halfAngle, normal), scaleBiasSpecular.z);\n";
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpLayer(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream)
{
// nothing to do
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpLayer(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream)
{
uint uvIdx = layer / 2;
String uvChannels = layer % 2 ? ".zw" : ".xy";
uint blendIdx = (layer-1) / 4;
String blendChannel = getChannel(layer-1);
String blendWeightStr = String("blendTexVal") + StringConverter::toString(blendIdx) +
"." + blendChannel;
// generate early-out conditional
/* Disable - causing some issues even when trying to force the use of texldd
if (layer && prof->_isSM3Available())
outStream << " if (" << blendWeightStr << " > 0.0003)\n { \n";
*/
// generate UV
outStream << " float2 uv" << layer << " = layerUV" << uvIdx << uvChannels << ";\n";
// calculate lighting here if normal mapping
if (prof->isLayerNormalMappingEnabled())
{
if (prof->isLayerParallaxMappingEnabled() && tt != RENDER_COMPOSITE_MAP)
{
// modify UV - note we have to sample an extra time
outStream << " displacement = tex2D(normtex" << layer << ", uv" << layer << ").a\n"
" * scaleBiasSpecular.x + scaleBiasSpecular.y;\n";
outStream << " uv" << layer << " += TSeyeDir.xy * displacement;\n";
}
// access TS normal map
outStream << " TSnormal = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n";
//outStream << " TShalfAngle = normalize(TSlightDir + TSeyeDir);\n";
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " TShalfAngle"<<i<<"= normalize(TSlightDir"<<i<<" + TSeyeDir);\n";
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " litResLayer"<<i<<" = lit(dot(TSlightDir"<<i<<", TSnormal), dot(TShalfAngle"<<i<<", TSnormal), scaleBiasSpecular.z);\n";
if (!layer)
{
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " litRes"<<i<<" = litResLayer"<<i<<";\n";
}
else
{
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
outStream << " litRes"<<i<<" = lerp(litRes"<<i<<", litResLayer"<<i<<", " << blendWeightStr << ");\n";
}
}
// sample diffuse texture
outStream << " float4 diffuseSpecTex" << layer
<< " = tex2D(difftex" << layer << ", uv" << layer << ");\n";
// apply to common
if (!layer)
{
outStream << " diffuse = diffuseSpecTex0.rgb;\n";
if (prof->isLayerSpecularMappingEnabled())
outStream << " specular = diffuseSpecTex0.a;\n";
}
else
{
outStream << " diffuse = lerp(diffuse, diffuseSpecTex" << layer
<< ".rgb, " << blendWeightStr << ");\n";
if (prof->isLayerSpecularMappingEnabled())
outStream << " specular = lerp(specular, diffuseSpecTex" << layer
<< ".a, " << blendWeightStr << ");\n";
}
// End early-out
/* Disable - causing some issues even when trying to force the use of texldd
if (layer && prof->_isSM3Available())
outStream << " } // early-out blend value\n";
*/
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpFooter(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
outStream <<
" oPos = mul(viewProjMatrix, worldPos);\n"
" oUVMisc.xy = uv.xy;\n";
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
{
outStream <<
" fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
}
else
{
outStream <<
" fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n";
}
}
if (prof->isShadowingEnabled(tt, terrain))
generateVpDynamicShadows(prof, terrain, tt, outStream);
outStream <<
"}\n";
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpFooter(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
if (tt == LOW_LOD)
{
if (prof->isShadowingEnabled(tt, terrain))
{
generateFpDynamicShadows(prof, terrain, tt, outStream);
outStream <<
" outputCol.rgb = diffuse * rtshadow;\n";
}
else
{
outStream <<
" outputCol.rgb = diffuse;\n";
}
}
else
{
if (terrain->getGlobalColourMapEnabled() && prof->isGlobalColourMapEnabled())
{
// sample colour map and apply to diffuse
outStream << " diffuse *= tex2D(globalColourMap, uv).rgb;\n";
}
if (prof->isLightmapEnabled())
{
// sample lightmap
outStream << " shadow = tex2D(lightMap, uv).r;\n";
}
if (prof->isShadowingEnabled(tt, terrain))
{
generateFpDynamicShadows(prof, terrain, tt, outStream);
}
// diffuse lighting
//outStream << " outputCol.rgb += ambient * diffuse + litRes.y * lightDiffuseColour * diffuse * shadow;\n";
//openMW MULTILIGHT
outStream << " outputCol.rgb += ambient * diffuse; \n";
// diffuse lighting
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
// shadows only for first light (directional)
if (i==0)
outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse * shadow;\n";
else
outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse;\n";
}
// specular default
if (!prof->isLayerSpecularMappingEnabled())
outStream << " specular = 1.0;\n";
if (tt == RENDER_COMPOSITE_MAP)
{
// Lighting embedded in alpha
outStream <<
" outputCol.a = shadow;\n";
}
else
{
// Apply specular
outStream << " outputCol.rgb += litRes0.z * lightSpecularColour * specular * shadow;\n";
if (prof->getParent()->getDebugLevel())
{
outStream << " outputCol.rg += lodInfo.xy;\n";
}
}
}
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
outStream << " outputCol.rgb = lerp(outputCol.rgb, fogColour, fogVal);\n";
}
// Final return
outStream << " return outputCol;\n"
<< "}\n";
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsHelpers(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
// TODO make filtering configurable
outStream <<
"// Simple PCF \n"
"// Number of samples in one dimension (square for total samples) \n"
"#define NUM_SHADOW_SAMPLES_1D 2.0 \n"
"#define SHADOW_FILTER_SCALE 1 \n"
"#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n"
"float4 offsetSample(float4 uv, float2 offset, float invMapSize) \n"
"{ \n"
" return float4(uv.xy + offset * invMapSize * uv.w, uv.z, uv.w); \n"
"} \n";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
"float calcDepthShadow(sampler2D shadowMap, float4 uv, float invShadowMapSize) \n"
"{ \n"
" // 4-sample PCF \n"
" float shadow = 0.0; \n"
" float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n"
" for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n"
" for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n"
" { \n"
" float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n"
" // manually project and assign derivatives \n"
" // to avoid gradient issues inside loops \n"
" newUV = newUV / newUV.w; \n"
" float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n"
" if (depth >= 1 || depth >= uv.z)\n"
" shadow += 1.0;\n"
" } \n"
" shadow /= SHADOW_SAMPLES; \n"
" return shadow; \n"
"} \n";
}
else
{
outStream <<
"float calcSimpleShadow(sampler2D shadowMap, float4 shadowMapPos) \n"
"{ \n"
" return tex2Dproj(shadowMap, shadowMapPos).x; \n"
"} \n";
}
if (prof->getReceiveDynamicShadowsPSSM())
{
uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
"float calcPSSMDepthShadow(";
}
else
{
outStream <<
"float calcPSSMSimpleShadow(";
}
outStream << "\n ";
for (uint i = 0; i < numTextures; ++i)
outStream << "sampler2D shadowMap" << i << ", ";
outStream << "\n ";
for (uint i = 0; i < numTextures; ++i)
outStream << "float4 lsPos" << i << ", ";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream << "\n ";
for (uint i = 0; i < numTextures; ++i)
outStream << "float invShadowmapSize" << i << ", ";
}
outStream << "\n"
" float4 pssmSplitPoints, float camDepth) \n"
"{ \n"
" float shadow; \n"
" // calculate shadow \n";
for (uint i = 0; i < numTextures; ++i)
{
if (!i)
outStream << " if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n";
else if (i < numTextures - 1)
outStream << " else if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n";
else
outStream << " else \n";
outStream <<
" { \n";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
" shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n";
}
else
{
outStream <<
" shadow = calcSimpleShadow(shadowMap" << i << ", lsPos" << i << "); \n";
}
outStream <<
" } \n";
}
outStream <<
" return shadow; \n"
"} \n\n\n";
}
}
//---------------------------------------------------------------------
uint TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpDynamicShadowsParams(
uint texCoord, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
// out semantics & params
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
}
for (uint i = 0; i < numTextures; ++i)
{
outStream <<
", out float4 oLightSpacePos" << i << " : TEXCOORD" << texCoord++ << " \n" <<
", uniform float4x4 texViewProjMatrix" << i << " \n";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
", uniform float4 depthRange" << i << " // x = min, y = max, z = range, w = 1/range \n";
}
}
return texCoord;
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpDynamicShadows(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
}
// Calculate the position of vertex in light space
for (uint i = 0; i < numTextures; ++i)
{
outStream <<
" oLightSpacePos" << i << " = mul(texViewProjMatrix" << i << ", worldPos); \n";
if (prof->getReceiveDynamicShadowsDepth())
{
// make linear
outStream <<
"oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n";
}
}
if (prof->getReceiveDynamicShadowsPSSM())
{
outStream <<
" // pass cam depth\n"
" oUVMisc.z = oPos.z;\n";
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsParams(
uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
if (tt == HIGH_LOD)
mShadowSamplerStartHi = *sampler;
else if (tt == LOW_LOD)
mShadowSamplerStartLo = *sampler;
// in semantics & params
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
outStream <<
", uniform float4 pssmSplitPoints \n";
}
for (uint i = 0; i < numTextures; ++i)
{
outStream <<
", float4 lightSpacePos" << i << " : TEXCOORD" << *texCoord << " \n" <<
", uniform sampler2D shadowMap" << i << " : register(s" << *sampler << ") \n";
*sampler = *sampler + 1;
*texCoord = *texCoord + 1;
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
", uniform float inverseShadowmapSize" << i << " \n";
}
}
}
//---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadows(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream)
{
if (prof->getReceiveDynamicShadowsPSSM())
{
uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
outStream <<
" float camDepth = uvMisc.z;\n";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
" float rtshadow = calcPSSMDepthShadow(";
}
else
{
outStream <<
" float rtshadow = calcPSSMSimpleShadow(";
}
for (uint i = 0; i < numTextures; ++i)
outStream << "shadowMap" << i << ", ";
outStream << "\n ";
for (uint i = 0; i < numTextures; ++i)
outStream << "lightSpacePos" << i << ", ";
if (prof->getReceiveDynamicShadowsDepth())
{
outStream << "\n ";
for (uint i = 0; i < numTextures; ++i)
outStream << "inverseShadowmapSize" << i << ", ";
}
outStream << "\n" <<
" pssmSplitPoints, camDepth);\n";
}
else
{
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
" float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);";
}
else
{
outStream <<
" float rtshadow = calcSimpleShadow(shadowMap0, lightSpacePos0);";
}
}
outStream <<
" shadow = min(shadow, rtshadow);\n";
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperHLSL::createVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getVertexProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"hlsl", GPT_VERTEX_PROGRAM);
}
else
{
ret->unload();
}
if (prof->_isSM3Available())
ret->setParameter("target", "vs_3_0");
else
ret->setParameter("target", "vs_2_0");
ret->setParameter("entry_point", "main_vp");
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperHLSL::createFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getFragmentProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"hlsl", GPT_FRAGMENT_PROGRAM);
}
else
{
ret->unload();
}
if (prof->_isSM3Available())
ret->setParameter("target", "ps_3_0");
else
ret->setParameter("target", "ps_2_x");
ret->setParameter("entry_point", "main_fp");
return ret;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperGLSL::createVertexProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getVertexProgramName(prof, terrain, tt);
switch(tt)
{
case HIGH_LOD:
progName += "/hlod";
break;
case LOW_LOD:
progName += "/llod";
break;
case RENDER_COMPOSITE_MAP:
progName += "/comp";
break;
}
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"glsl", GPT_VERTEX_PROGRAM);
}
else
{
ret->unload();
}
return ret;
}
//---------------------------------------------------------------------
HighLevelGpuProgramPtr
TerrainMaterialGeneratorB::SM2Profile::ShaderHelperGLSL::createFragmentProgram(
const SM2Profile* prof, const Terrain* terrain, TechniqueType tt)
{
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
String progName = getFragmentProgramName(prof, terrain, tt);
HighLevelGpuProgramPtr ret = mgr.getByName(progName);
if (ret.isNull())
{
ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"glsl", GPT_FRAGMENT_PROGRAM);
}
else
{
ret->unload();
}
return ret;
}
}
{CODE}
!!!
!!Use
To enable it do this when you make your terrain:
{CODE(wrap="1", colors="c++")}
Ogre::TerrainMaterialGeneratorPtr matGen;
Ogre::TerrainMaterialGeneratorB* matGenP = new Ogre::TerrainMaterialGeneratorB();
matGen.bind(matGenP);
m_pTerrainGlobals->setDefaultMaterialGenerator(matGen);
{CODE}