mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-09 15:30:41 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
780
Engine/source/terrain/terrCellMaterial.cpp
Normal file
780
Engine/source/terrain/terrCellMaterial.cpp
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "terrain/terrCellMaterial.h"
|
||||
|
||||
#include "terrain/terrData.h"
|
||||
#include "terrain/terrCell.h"
|
||||
#include "materials/materialFeatureTypes.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "terrain/terrFeatureTypes.h"
|
||||
#include "terrain/terrMaterial.h"
|
||||
#include "renderInstance/renderPrePassMgr.h"
|
||||
#include "shaderGen/shaderGen.h"
|
||||
#include "shaderGen/featureMgr.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "gfx/util/screenspace.h"
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( MaterialManager )
|
||||
{
|
||||
Con::NotifyDelegate callabck( &TerrainCellMaterial::_updateDefaultAnisotropy );
|
||||
Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck );
|
||||
}
|
||||
|
||||
Vector<TerrainCellMaterial*> TerrainCellMaterial::smAllMaterials;
|
||||
|
||||
TerrainCellMaterial::TerrainCellMaterial()
|
||||
: mCurrPass( 0 ),
|
||||
mTerrain( NULL ),
|
||||
mPrePassMat( NULL ),
|
||||
mReflectMat( NULL )
|
||||
{
|
||||
smAllMaterials.push_back( this );
|
||||
}
|
||||
|
||||
TerrainCellMaterial::~TerrainCellMaterial()
|
||||
{
|
||||
SAFE_DELETE( mPrePassMat );
|
||||
SAFE_DELETE( mReflectMat );
|
||||
smAllMaterials.remove( this );
|
||||
}
|
||||
|
||||
void TerrainCellMaterial::_updateDefaultAnisotropy()
|
||||
{
|
||||
// TODO: We need to split the stateblock initialization
|
||||
// from the shader constant lookup and pass setup in a
|
||||
// future version of terrain materials.
|
||||
//
|
||||
// For now use some custom code in a horrible loop to
|
||||
// change the anisotropy directly and fast.
|
||||
//
|
||||
|
||||
const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy();
|
||||
|
||||
Vector<TerrainCellMaterial*>::iterator iter = smAllMaterials.begin();
|
||||
for ( ; iter != smAllMaterials.end(); iter++ )
|
||||
{
|
||||
for ( U32 p=0; p < (*iter)->mPasses.size(); p++ )
|
||||
{
|
||||
Pass &pass = (*iter)->mPasses[p];
|
||||
|
||||
// Start from the existing state block.
|
||||
GFXStateBlockDesc desc = pass.stateBlock->getDesc();
|
||||
|
||||
for ( U32 m=0; m < pass.materials.size(); m++ )
|
||||
{
|
||||
const MaterialInfo *matInfo = pass.materials[m];
|
||||
|
||||
if ( matInfo->detailTexConst->isValid() )
|
||||
{
|
||||
const S32 sampler = matInfo->detailTexConst->getSamplerRegister();
|
||||
|
||||
if ( maxAnisotropy > 1 )
|
||||
{
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
|
||||
desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
else
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
|
||||
}
|
||||
|
||||
if ( matInfo->normalTexConst->isValid() )
|
||||
{
|
||||
const S32 sampler = matInfo->normalTexConst->getSamplerRegister();
|
||||
|
||||
if ( maxAnisotropy > 1 )
|
||||
{
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
|
||||
desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
else
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
|
||||
}
|
||||
|
||||
} // for ( U32 m=0; m < pass.materials.size(); m++ )
|
||||
|
||||
// Set the updated stateblock.
|
||||
pass.stateBlock = GFX->createStateBlock( desc );
|
||||
|
||||
// Create the wireframe state blocks.
|
||||
GFXStateBlockDesc wireframe( desc );
|
||||
wireframe.fillMode = GFXFillWireframe;
|
||||
pass.wireframeStateBlock = GFX->createStateBlock( wireframe );
|
||||
|
||||
} // for ( U32 p=0; i < (*iter)->mPasses.size(); p++ )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TerrainCellMaterial::setTransformAndEye( const MatrixF &modelXfm,
|
||||
const MatrixF &viewXfm,
|
||||
const MatrixF &projectXfm,
|
||||
F32 farPlane )
|
||||
{
|
||||
PROFILE_SCOPE( TerrainCellMaterial_SetTransformAndEye );
|
||||
|
||||
MatrixF modelViewProj = projectXfm * viewXfm * modelXfm;
|
||||
|
||||
MatrixF invViewXfm( viewXfm );
|
||||
invViewXfm.inverse();
|
||||
Point3F eyePos = invViewXfm.getPosition();
|
||||
|
||||
MatrixF invModelXfm( modelXfm );
|
||||
invModelXfm.inverse();
|
||||
|
||||
Point3F objEyePos = eyePos;
|
||||
invModelXfm.mulP( objEyePos );
|
||||
|
||||
VectorF vEye = invViewXfm.getForwardVector();
|
||||
vEye.normalize( 1.0f / farPlane );
|
||||
|
||||
for ( U32 i=0; i < mPasses.size(); i++ )
|
||||
{
|
||||
Pass &pass = mPasses[i];
|
||||
|
||||
pass.consts->setSafe( pass.modelViewProjConst, modelViewProj );
|
||||
|
||||
if( pass.viewToObj->isValid() || pass.worldViewOnly->isValid() )
|
||||
{
|
||||
MatrixF worldViewOnly = viewXfm * modelXfm;
|
||||
|
||||
pass.consts->setSafe( pass.worldViewOnly, worldViewOnly );
|
||||
|
||||
if( pass.viewToObj->isValid() )
|
||||
{
|
||||
worldViewOnly.affineInverse();
|
||||
pass.consts->set( pass.viewToObj, worldViewOnly);
|
||||
}
|
||||
}
|
||||
|
||||
pass.consts->setSafe( pass.eyePosWorldConst, eyePos );
|
||||
pass.consts->setSafe( pass.eyePosConst, objEyePos );
|
||||
pass.consts->setSafe( pass.objTransConst, modelXfm );
|
||||
pass.consts->setSafe( pass.worldToObjConst, invModelXfm );
|
||||
pass.consts->setSafe( pass.vEyeConst, vEye );
|
||||
}
|
||||
}
|
||||
|
||||
TerrainCellMaterial* TerrainCellMaterial::getPrePassMat()
|
||||
{
|
||||
if ( !mPrePassMat )
|
||||
{
|
||||
mPrePassMat = new TerrainCellMaterial();
|
||||
mPrePassMat->init( mTerrain, mMaterials, true, false, mMaterials == 0 );
|
||||
}
|
||||
|
||||
return mPrePassMat;
|
||||
}
|
||||
|
||||
TerrainCellMaterial* TerrainCellMaterial::getReflectMat()
|
||||
{
|
||||
if ( !mReflectMat )
|
||||
{
|
||||
mReflectMat = new TerrainCellMaterial();
|
||||
mReflectMat->init( mTerrain, mMaterials, false, true, true );
|
||||
}
|
||||
|
||||
return mReflectMat;
|
||||
}
|
||||
|
||||
void TerrainCellMaterial::init( TerrainBlock *block,
|
||||
U64 activeMaterials,
|
||||
bool prePassMat,
|
||||
bool reflectMat,
|
||||
bool baseOnly )
|
||||
{
|
||||
// This isn't allowed for now.
|
||||
AssertFatal( !( prePassMat && reflectMat ), "TerrainCellMaterial::init - We shouldn't get prepass and reflection in the same material!" );
|
||||
|
||||
mTerrain = block;
|
||||
mMaterials = activeMaterials;
|
||||
|
||||
Vector<MaterialInfo*> materials;
|
||||
|
||||
for ( U32 i = 0; i < 64; i++ )
|
||||
{
|
||||
if ( !( mMaterials & ((U64)1 << i ) ) )
|
||||
continue;
|
||||
|
||||
TerrainMaterial *mat = block->getMaterial( i );
|
||||
|
||||
MaterialInfo *info = new MaterialInfo();
|
||||
info->layerId = i;
|
||||
info->mat = mat;
|
||||
materials.push_back( info );
|
||||
}
|
||||
|
||||
mCurrPass = 0;
|
||||
mPasses.clear();
|
||||
|
||||
// Ok... loop till we successfully generate all
|
||||
// the shader passes for the materials.
|
||||
while ( materials.size() > 0 || baseOnly )
|
||||
{
|
||||
mPasses.increment();
|
||||
|
||||
if ( !_createPass( &materials,
|
||||
&mPasses.last(),
|
||||
mPasses.size() == 1,
|
||||
prePassMat,
|
||||
reflectMat,
|
||||
baseOnly ) )
|
||||
{
|
||||
Con::errorf( "TerrainCellMaterial::init - Failed to create pass!" );
|
||||
|
||||
// The pass failed to be generated... give up.
|
||||
mPasses.last().materials.clear();
|
||||
mPasses.clear();
|
||||
for_each( materials.begin(), materials.end(), delete_pointer() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( baseOnly )
|
||||
break;
|
||||
}
|
||||
|
||||
// Cleanup any remaining matinfo.
|
||||
for_each( materials.begin(), materials.end(), delete_pointer() );
|
||||
|
||||
// If we have attached mats then update them too.
|
||||
if ( mPrePassMat )
|
||||
mPrePassMat->init( mTerrain, mMaterials, true, false, baseOnly );
|
||||
if ( mReflectMat )
|
||||
mReflectMat->init( mTerrain, mMaterials, false, true, baseOnly );
|
||||
}
|
||||
|
||||
bool TerrainCellMaterial::_createPass( Vector<MaterialInfo*> *materials,
|
||||
Pass *pass,
|
||||
bool firstPass,
|
||||
bool prePassMat,
|
||||
bool reflectMat,
|
||||
bool baseOnly )
|
||||
{
|
||||
if ( GFX->getPixelShaderVersion() < 3.0f )
|
||||
baseOnly = true;
|
||||
|
||||
// NOTE: At maximum we only try to combine 3 materials
|
||||
// into a single pass. This is sub-optimal for the simplest
|
||||
// cases, but the most common case results in much fewer
|
||||
// shader generation failures and permutations leading to
|
||||
// faster load time and less hiccups during gameplay.
|
||||
U32 matCount = getMin( 3, materials->size() );
|
||||
|
||||
Vector<GFXTexHandle> normalMaps;
|
||||
|
||||
// See if we're currently running under the
|
||||
// basic lighting manager.
|
||||
//
|
||||
// TODO: This seems ugly... we should trigger
|
||||
// features like this differently in the future.
|
||||
//
|
||||
bool useBLM = dStrcmp( LIGHTMGR->getId(), "BLM" ) == 0;
|
||||
|
||||
// Do we need to disable normal mapping?
|
||||
const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature( MFT_NormalMap ) || useBLM;
|
||||
|
||||
// How about parallax?
|
||||
const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f ||
|
||||
MATMGR->getExclusionFeatures().hasFeature( MFT_Parallax );
|
||||
|
||||
// Has advanced lightmap support been enabled for prepass.
|
||||
bool advancedLightmapSupport = false;
|
||||
if ( prePassMat )
|
||||
{
|
||||
// This sucks... but it works.
|
||||
AdvancedLightBinManager *lightBin;
|
||||
if ( Sim::findObject( "AL_LightBinMgr", lightBin ) )
|
||||
advancedLightmapSupport = lightBin->MRTLightmapsDuringPrePass();
|
||||
}
|
||||
|
||||
// Loop till we create a valid shader!
|
||||
while( true )
|
||||
{
|
||||
FeatureSet features;
|
||||
features.addFeature( MFT_VertTransform );
|
||||
features.addFeature( MFT_TerrainBaseMap );
|
||||
|
||||
if ( prePassMat )
|
||||
{
|
||||
features.addFeature( MFT_EyeSpaceDepthOut );
|
||||
features.addFeature( MFT_PrePassConditioner );
|
||||
|
||||
if ( advancedLightmapSupport )
|
||||
features.addFeature( MFT_RenderTarget1_Zero );
|
||||
}
|
||||
else
|
||||
{
|
||||
features.addFeature( MFT_RTLighting );
|
||||
|
||||
// The HDR feature is always added... it will compile out
|
||||
// if HDR is not enabled in the engine.
|
||||
features.addFeature( MFT_HDROut );
|
||||
}
|
||||
|
||||
// Enable lightmaps and fogging if we're in BL.
|
||||
if ( reflectMat || useBLM )
|
||||
{
|
||||
features.addFeature( MFT_Fog );
|
||||
features.addFeature( MFT_ForwardShading );
|
||||
}
|
||||
if ( useBLM )
|
||||
features.addFeature( MFT_TerrainLightMap );
|
||||
|
||||
// The additional passes need to be lerp blended into the
|
||||
// target to maintain the results of the previous passes.
|
||||
if ( !firstPass )
|
||||
features.addFeature( MFT_TerrainAdditive );
|
||||
|
||||
normalMaps.clear();
|
||||
pass->materials.clear();
|
||||
|
||||
// Now add all the material layer features.
|
||||
|
||||
for ( U32 i=0; i < matCount && !baseOnly; i++ )
|
||||
{
|
||||
TerrainMaterial *mat = (*materials)[i]->mat;
|
||||
|
||||
if ( mat == NULL )
|
||||
continue;
|
||||
|
||||
// We only include materials that
|
||||
// have more than a base texture.
|
||||
if ( mat->getDetailSize() <= 0 ||
|
||||
mat->getDetailDistance() <= 0 ||
|
||||
mat->getDetailMap().isEmpty() )
|
||||
continue;
|
||||
|
||||
S32 featureIndex = pass->materials.size();
|
||||
|
||||
features.addFeature( MFT_TerrainDetailMap, featureIndex );
|
||||
|
||||
pass->materials.push_back( (*materials)[i] );
|
||||
normalMaps.increment();
|
||||
|
||||
// Skip normal maps if we need to.
|
||||
if ( !disableNormalMaps && mat->getNormalMap().isNotEmpty() )
|
||||
{
|
||||
features.addFeature( MFT_TerrainNormalMap, featureIndex );
|
||||
|
||||
normalMaps.last().set( mat->getNormalMap(),
|
||||
&GFXDefaultStaticNormalMapProfile, "TerrainCellMaterial::_createPass() - NormalMap" );
|
||||
|
||||
if ( normalMaps.last().getFormat() == GFXFormatDXT5 )
|
||||
features.addFeature( MFT_IsDXTnm, featureIndex );
|
||||
|
||||
// Do we need and can we do parallax mapping?
|
||||
if ( !disableParallaxMaps &&
|
||||
mat->getParallaxScale() > 0.0f &&
|
||||
!mat->useSideProjection() )
|
||||
features.addFeature( MFT_TerrainParallaxMap, featureIndex );
|
||||
}
|
||||
|
||||
// Is this layer got side projection?
|
||||
if ( mat->useSideProjection() )
|
||||
features.addFeature( MFT_TerrainSideProject, featureIndex );
|
||||
}
|
||||
|
||||
MaterialFeatureData featureData;
|
||||
featureData.features = features;
|
||||
featureData.materialFeatures = features;
|
||||
|
||||
// Check to see how many vertex shader output
|
||||
// registers we're gonna need.
|
||||
U32 numTex = 0;
|
||||
U32 numTexReg = 0;
|
||||
for ( U32 i=0; i < features.getCount(); i++ )
|
||||
{
|
||||
S32 index;
|
||||
const FeatureType &type = features.getAt( i, &index );
|
||||
ShaderFeature* sf = FEATUREMGR->getByType( type );
|
||||
if ( !sf )
|
||||
continue;
|
||||
|
||||
sf->setProcessIndex( index );
|
||||
ShaderFeature::Resources res = sf->getResources( featureData );
|
||||
|
||||
numTex += res.numTex;
|
||||
numTexReg += res.numTexReg;
|
||||
}
|
||||
|
||||
// Can we build the shader?
|
||||
//
|
||||
// NOTE: The 10 is sort of an abitrary SM 3.0
|
||||
// limit. Its really supposed to be 11, but that
|
||||
// always fails to compile so far.
|
||||
//
|
||||
if ( numTex < GFX->getNumSamplers() &&
|
||||
numTexReg <= 10 )
|
||||
{
|
||||
// NOTE: We really shouldn't be getting errors building the shaders,
|
||||
// but we can generate more instructions than the ps_2_x will allow.
|
||||
//
|
||||
// There is no way to deal with this case that i know of other than
|
||||
// letting the compile fail then recovering by trying to build it
|
||||
// with fewer materials.
|
||||
//
|
||||
// We normally disable the shader error logging so that the user
|
||||
// isn't fooled into thinking there is a real bug. That is until
|
||||
// we get down to a single material. If a single material case
|
||||
// fails it means it cannot generate any passes at all!
|
||||
const bool logErrors = matCount == 1;
|
||||
GFXShader::setLogging( logErrors, true );
|
||||
|
||||
pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat<TerrVertex>(), NULL );
|
||||
}
|
||||
|
||||
// If we got a shader then we can continue.
|
||||
if ( pass->shader )
|
||||
break;
|
||||
|
||||
// If the material count is already 1 then this
|
||||
// is a real shader error... give up!
|
||||
if ( matCount <= 1 )
|
||||
return false;
|
||||
|
||||
// If we failed we next try half the input materials
|
||||
// so that we can more quickly arrive at a valid shader.
|
||||
matCount -= matCount / 2;
|
||||
}
|
||||
|
||||
// Setup the constant buffer.
|
||||
pass->consts = pass->shader->allocConstBuffer();
|
||||
|
||||
// Prepare the basic constants.
|
||||
pass->modelViewProjConst = pass->shader->getShaderConstHandle( "$modelview" );
|
||||
pass->worldViewOnly = pass->shader->getShaderConstHandle( "$worldViewOnly" );
|
||||
pass->viewToObj = pass->shader->getShaderConstHandle( "$viewToObj" );
|
||||
pass->eyePosWorldConst = pass->shader->getShaderConstHandle( "$eyePosWorld" );
|
||||
pass->eyePosConst = pass->shader->getShaderConstHandle( "$eyePos" );
|
||||
pass->vEyeConst = pass->shader->getShaderConstHandle( "$vEye" );
|
||||
pass->layerSizeConst = pass->shader->getShaderConstHandle( "$layerSize" );
|
||||
pass->objTransConst = pass->shader->getShaderConstHandle( "$objTrans" );
|
||||
pass->worldToObjConst = pass->shader->getShaderConstHandle( "$worldToObj" );
|
||||
pass->lightInfoBufferConst = pass->shader->getShaderConstHandle( "$lightInfoBuffer" );
|
||||
pass->baseTexMapConst = pass->shader->getShaderConstHandle( "$baseTexMap" );
|
||||
pass->layerTexConst = pass->shader->getShaderConstHandle( "$layerTex" );
|
||||
pass->fogDataConst = pass->shader->getShaderConstHandle( "$fogData" );
|
||||
pass->fogColorConst = pass->shader->getShaderConstHandle( "$fogColor" );
|
||||
pass->lightMapTexConst = pass->shader->getShaderConstHandle( "$lightMapTex" );
|
||||
pass->oneOverTerrainSize = pass->shader->getShaderConstHandle( "$oneOverTerrainSize" );
|
||||
pass->squareSize = pass->shader->getShaderConstHandle( "$squareSize" );
|
||||
|
||||
// NOTE: We're assuming rtParams0 here as we know its the only
|
||||
// render target we currently get in a terrain material and the
|
||||
// DeferredRTLightingFeatHLSL will always use 0.
|
||||
//
|
||||
// This could change in the future and we would need to fix
|
||||
// the ShaderFeature API to allow us to do this right.
|
||||
//
|
||||
pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParams0" );
|
||||
|
||||
// Now prepare the basic stateblock.
|
||||
GFXStateBlockDesc desc;
|
||||
if ( !firstPass )
|
||||
{
|
||||
desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha );
|
||||
|
||||
// If this is the prepass then we don't want to
|
||||
// write to the last two color channels (where
|
||||
// depth is usually encoded).
|
||||
//
|
||||
// This trick works in combination with the
|
||||
// MFT_TerrainAdditive feature to lerp the
|
||||
// output normal with the previous pass.
|
||||
//
|
||||
if ( prePassMat )
|
||||
desc.setColorWrites( true, true, false, false );
|
||||
}
|
||||
|
||||
// We write to the zbuffer if this is a prepass
|
||||
// material or if the prepass is disabled.
|
||||
// We also write the zbuffer if we're using OpenGL, because in OpenGL the prepass
|
||||
// cannot share the same zbuffer as the backbuffer.
|
||||
desc.setZReadWrite( true, !MATMGR->getPrePassEnabled() ||
|
||||
GFX->getAdapterType() == OpenGL ||
|
||||
prePassMat ||
|
||||
reflectMat );
|
||||
|
||||
desc.samplersDefined = true;
|
||||
if ( pass->baseTexMapConst->isValid() )
|
||||
desc.samplers[pass->baseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear();
|
||||
|
||||
if ( pass->layerTexConst->isValid() )
|
||||
desc.samplers[pass->layerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint();
|
||||
|
||||
if ( pass->lightInfoBufferConst->isValid() )
|
||||
desc.samplers[pass->lightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint();
|
||||
|
||||
if ( pass->lightMapTexConst->isValid() )
|
||||
desc.samplers[pass->lightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear();
|
||||
|
||||
const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy();
|
||||
|
||||
// Finally setup the material specific shader
|
||||
// constants and stateblock state.
|
||||
//
|
||||
// NOTE: If this changes be sure to check TerrainCellMaterial::_updateDefaultAnisotropy
|
||||
// to see if it needs the same changes.
|
||||
//
|
||||
for ( U32 i=0; i < pass->materials.size(); i++ )
|
||||
{
|
||||
MaterialInfo *matInfo = pass->materials[i];
|
||||
|
||||
matInfo->detailInfoVConst = pass->shader->getShaderConstHandle( avar( "$detailScaleAndFade%d", i ) );
|
||||
matInfo->detailInfoPConst = pass->shader->getShaderConstHandle( avar( "$detailIdStrengthParallax%d", i ) );
|
||||
|
||||
matInfo->detailTexConst = pass->shader->getShaderConstHandle( avar( "$detailMap%d", i ) );
|
||||
if ( matInfo->detailTexConst->isValid() )
|
||||
{
|
||||
const S32 sampler = matInfo->detailTexConst->getSamplerRegister();
|
||||
|
||||
desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
|
||||
desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
|
||||
desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
|
||||
|
||||
if ( maxAnisotropy > 1 )
|
||||
{
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
|
||||
desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
else
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
|
||||
|
||||
matInfo->detailTex.set( matInfo->mat->getDetailMap(),
|
||||
&GFXDefaultStaticDiffuseProfile, "TerrainCellMaterial::_createPass() - DetailMap" );
|
||||
}
|
||||
|
||||
matInfo->normalTexConst = pass->shader->getShaderConstHandle( avar( "$normalMap%d", i ) );
|
||||
if ( matInfo->normalTexConst->isValid() )
|
||||
{
|
||||
const S32 sampler = matInfo->normalTexConst->getSamplerRegister();
|
||||
|
||||
desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
|
||||
desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
|
||||
desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
|
||||
|
||||
if ( maxAnisotropy > 1 )
|
||||
{
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
|
||||
desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
else
|
||||
desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
|
||||
|
||||
matInfo->normalTex = normalMaps[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the materials we processed and leave the
|
||||
// ones that remain for the next pass.
|
||||
for ( U32 i=0; i < matCount; i++ )
|
||||
{
|
||||
MaterialInfo *matInfo = materials->first();
|
||||
if ( baseOnly || pass->materials.find_next( matInfo ) == -1 )
|
||||
delete matInfo;
|
||||
materials->pop_front();
|
||||
}
|
||||
|
||||
// If we're doing prepass it requires some
|
||||
// special stencil settings for it to work.
|
||||
if ( prePassMat )
|
||||
desc.addDesc( RenderPrePassMgr::getOpaqueStenciWriteDesc( false ) );
|
||||
|
||||
// Flip the cull for reflection materials.
|
||||
if ( reflectMat )
|
||||
desc.setCullMode( GFXCullCW );
|
||||
|
||||
pass->stateBlock = GFX->createStateBlock( desc );
|
||||
|
||||
// Create the wireframe state blocks.
|
||||
GFXStateBlockDesc wireframe( desc );
|
||||
wireframe.fillMode = GFXFillWireframe;
|
||||
pass->wireframeStateBlock = GFX->createStateBlock( wireframe );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerrainCellMaterial::_updateMaterialConsts( Pass *pass )
|
||||
{
|
||||
PROFILE_SCOPE( TerrainCellMaterial_UpdateMaterialConsts );
|
||||
|
||||
for ( U32 j=0; j < pass->materials.size(); j++ )
|
||||
{
|
||||
MaterialInfo *matInfo = pass->materials[j];
|
||||
|
||||
F32 detailSize = matInfo->mat->getDetailSize();
|
||||
F32 detailScale = 1.0f;
|
||||
if ( !mIsZero( detailSize ) )
|
||||
detailScale = mTerrain->getWorldBlockSize() / detailSize;
|
||||
|
||||
// Scale the distance by the global scalar.
|
||||
const F32 distance = mTerrain->smDetailScale * matInfo->mat->getDetailDistance();
|
||||
|
||||
// NOTE: The negation of the y scale is to make up for
|
||||
// my mistake early in development and passing the wrong
|
||||
// y texture coord into the system.
|
||||
//
|
||||
// This negation fixes detail, normal, and parallax mapping
|
||||
// without harming the layer id blending code.
|
||||
//
|
||||
// Eventually we should rework this to correct this little
|
||||
// mistake, but there isn't really a hurry to.
|
||||
//
|
||||
Point4F detailScaleAndFade( detailScale,
|
||||
-detailScale,
|
||||
distance,
|
||||
0 );
|
||||
|
||||
if ( !mIsZero( distance ) )
|
||||
detailScaleAndFade.w = 1.0f / distance;
|
||||
|
||||
Point3F detailIdStrengthParallax( matInfo->layerId,
|
||||
matInfo->mat->getDetailStrength(),
|
||||
matInfo->mat->getParallaxScale() );
|
||||
|
||||
pass->consts->setSafe( matInfo->detailInfoVConst, detailScaleAndFade );
|
||||
pass->consts->setSafe( matInfo->detailInfoPConst, detailIdStrengthParallax );
|
||||
}
|
||||
}
|
||||
|
||||
bool TerrainCellMaterial::setupPass( const SceneRenderState *state,
|
||||
const SceneData &sceneData )
|
||||
{
|
||||
PROFILE_SCOPE( TerrainCellMaterial_SetupPass );
|
||||
|
||||
if ( mCurrPass >= mPasses.size() )
|
||||
{
|
||||
mCurrPass = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
Pass &pass = mPasses[mCurrPass];
|
||||
|
||||
_updateMaterialConsts( &pass );
|
||||
|
||||
if ( pass.baseTexMapConst->isValid() )
|
||||
GFX->setTexture( pass.baseTexMapConst->getSamplerRegister(), mTerrain->mBaseTex.getPointer() );
|
||||
|
||||
if ( pass.layerTexConst->isValid() )
|
||||
GFX->setTexture( pass.layerTexConst->getSamplerRegister(), mTerrain->mLayerTex.getPointer() );
|
||||
|
||||
if ( pass.lightMapTexConst->isValid() )
|
||||
GFX->setTexture( pass.lightMapTexConst->getSamplerRegister(), mTerrain->getLightMapTex() );
|
||||
|
||||
if ( sceneData.wireframe )
|
||||
GFX->setStateBlock( pass.wireframeStateBlock );
|
||||
else
|
||||
GFX->setStateBlock( pass.stateBlock );
|
||||
|
||||
GFX->setShader( pass.shader );
|
||||
GFX->setShaderConstBuffer( pass.consts );
|
||||
|
||||
// Let the light manager prepare any light stuff it needs.
|
||||
LIGHTMGR->setLightInfo( NULL,
|
||||
NULL,
|
||||
sceneData,
|
||||
state,
|
||||
mCurrPass,
|
||||
pass.consts );
|
||||
|
||||
for ( U32 i=0; i < pass.materials.size(); i++ )
|
||||
{
|
||||
MaterialInfo *matInfo = pass.materials[i];
|
||||
|
||||
if ( matInfo->detailTexConst->isValid() )
|
||||
GFX->setTexture( matInfo->detailTexConst->getSamplerRegister(), matInfo->detailTex );
|
||||
if ( matInfo->normalTexConst->isValid() )
|
||||
GFX->setTexture( matInfo->normalTexConst->getSamplerRegister(), matInfo->normalTex );
|
||||
}
|
||||
|
||||
pass.consts->setSafe( pass.layerSizeConst, (F32)mTerrain->mLayerTex.getWidth() );
|
||||
|
||||
if ( pass.oneOverTerrainSize->isValid() )
|
||||
{
|
||||
F32 oneOverTerrainSize = 1.0f / mTerrain->getWorldBlockSize();
|
||||
pass.consts->set( pass.oneOverTerrainSize, oneOverTerrainSize );
|
||||
}
|
||||
|
||||
pass.consts->setSafe( pass.squareSize, mTerrain->getSquareSize() );
|
||||
|
||||
if ( pass.fogDataConst->isValid() )
|
||||
{
|
||||
Point3F fogData;
|
||||
fogData.x = sceneData.fogDensity;
|
||||
fogData.y = sceneData.fogDensityOffset;
|
||||
fogData.z = sceneData.fogHeightFalloff;
|
||||
pass.consts->set( pass.fogDataConst, fogData );
|
||||
}
|
||||
|
||||
pass.consts->setSafe( pass.fogColorConst, sceneData.fogColor );
|
||||
|
||||
if ( pass.lightInfoBufferConst->isValid() &&
|
||||
pass.lightParamsConst->isValid() )
|
||||
{
|
||||
if ( !mLightInfoTarget )
|
||||
mLightInfoTarget = NamedTexTarget::find( "lightinfo" );
|
||||
|
||||
GFXTextureObject *texObject = mLightInfoTarget->getTexture();
|
||||
|
||||
// TODO: Sometimes during reset of the light manager we get a
|
||||
// NULL texture here. This is corrected on the next frame, but
|
||||
// we should still investigate why that happens.
|
||||
|
||||
if ( texObject )
|
||||
{
|
||||
GFX->setTexture( pass.lightInfoBufferConst->getSamplerRegister(), texObject );
|
||||
|
||||
const Point3I &targetSz = texObject->getSize();
|
||||
const RectI &targetVp = mLightInfoTarget->getViewport();
|
||||
Point4F rtParams;
|
||||
ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
|
||||
pass.consts->setSafe( pass.lightParamsConst, rtParams );
|
||||
}
|
||||
}
|
||||
|
||||
++mCurrPass;
|
||||
return true;
|
||||
}
|
||||
|
||||
BaseMatInstance* TerrainCellMaterial::getShadowMat()
|
||||
{
|
||||
// Find our material which has some settings
|
||||
// defined on it in script.
|
||||
Material *mat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" );
|
||||
|
||||
// Create the material instance adding the feature which
|
||||
// handles rendering terrain cut outs.
|
||||
FeatureSet features = MATMGR->getDefaultFeatures();
|
||||
BaseMatInstance *matInst = mat->createMatInstance();
|
||||
if ( !matInst->init( features, getGFXVertexFormat<TerrVertex>() ) )
|
||||
{
|
||||
delete matInst;
|
||||
matInst = NULL;
|
||||
}
|
||||
|
||||
return matInst;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue