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 if ( state->isReflectPass( )) GFX->setStateBlock( pass.reflectionStateBlock ); 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->macroTexConst->isValid() ) GFX->setTexture( matInfo->macroTexConst->getSamplerRegister(), matInfo->macroTex ); 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; }
void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const SceneData &sgData, U32 pass ) { PROFILE_SCOPE( ProcessedShaderMaterial_SetTextureStages ); ShaderConstHandles *handles = _getShaderConstHandles(pass); // Set all of the textures we need to render the give pass. #ifdef TORQUE_DEBUG AssertFatal( pass<mPasses.size(), "Pass out of bounds" ); #endif RenderPassData *rpd = mPasses[pass]; GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); NamedTexTarget *texTarget; GFXTextureObject *texObject; for( U32 i=0; i<rpd->mNumTex; i++ ) { U32 currTexFlag = rpd->mTexType[i]; if (!LIGHTMGR || !LIGHTMGR->setTextureStage(sgData, currTexFlag, i, shaderConsts, handles)) { switch( currTexFlag ) { // If the flag is unset then assume its just // a regular texture to set... nothing special. case 0: default: GFX->setTexture(i, rpd->mTexSlot[i].texObject); break; case Material::NormalizeCube: GFX->setCubeTexture(i, Material::GetNormalizeCube()); break; case Material::Lightmap: GFX->setTexture( i, sgData.lightmap ); break; case Material::ToneMapTex: shaderConsts->setSafe(handles->mToneMapTexSC, (S32)i); GFX->setTexture(i, rpd->mTexSlot[i].texObject); break; case Material::Cube: GFX->setCubeTexture( i, rpd->mCubeMap ); break; case Material::SGCube: GFX->setCubeTexture( i, sgData.cubemap ); break; case Material::BackBuff: GFX->setTexture( i, sgData.backBuffTex ); break; case Material::TexTarget: { texTarget = rpd->mTexSlot[i].texTarget; if ( !texTarget ) { GFX->setTexture( i, NULL ); break; } texObject = texTarget->getTexture(); // If no texture is available then map the default 2x2 // black texture to it. This at least will ensure that // we get consistant behavior across GPUs and platforms. if ( !texObject ) texObject = GFXTexHandle::ZERO; if ( handles->mRTParamsSC[i]->isValid() && texObject ) { const Point3I &targetSz = texObject->getSize(); const RectI &targetVp = texTarget->getViewport(); Point4F rtParams; ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); shaderConsts->set(handles->mRTParamsSC[i], rtParams); } GFX->setTexture( i, texObject ); break; } } } } }
void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const SceneData &sgData, U32 pass ) { LightManager* lm = state ? LIGHTMGR : NULL; ShaderRenderPassData* rpd = _getRPD(pass); ShaderConstHandles* handles = _getShaderConstHandles(pass); GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); const NamedTexTarget *texTarget; GFXTextureObject *texObject; for( U32 i=0; i<mMaxTex; i++ ) { U32 currTexFlag = rpd->mTexType[i]; if ( !lm || !lm->setTextureStage(sgData, currTexFlag, i, shaderConsts, handles ) ) { GFXShaderConstHandle* handle = handles->mTexHandlesSC[i]; if ( !handle->isValid() ) continue; S32 samplerRegister = handle->getSamplerRegister(); switch( currTexFlag ) { case 0: default: break; case Material::Mask: case Material::Standard: case Material::Bump: case Material::Detail: { GFX->setTexture( samplerRegister, rpd->mTexSlot[i].texObject ); break; } case Material::Lightmap: { GFX->setTexture( samplerRegister, sgData.lightmap ); break; } case Material::Cube: { GFX->setCubeTexture( samplerRegister, rpd->mCubeMap ); break; } case Material::SGCube: { GFX->setCubeTexture( samplerRegister, sgData.cubemap ); break; } case Material::BackBuff: { GFX->setTexture( samplerRegister, sgData.backBuffTex ); //if ( sgData.reflectTex ) // GFX->setTexture( samplerRegister, sgData.reflectTex ); //else //{ // GFXTextureObject *refractTex = REFLECTMGR->getRefractTex( true ); // GFX->setTexture( samplerRegister, refractTex ); //} break; } case Material::ReflectBuff: { GFX->setTexture( samplerRegister, sgData.reflectTex ); break; } case Material::Misc: { GFX->setTexture( samplerRegister, sgData.miscTex ); break; } case Material::TexTarget: { texTarget = rpd->mTexSlot[i].texTarget; if ( !texTarget ) { GFX->setTexture( samplerRegister, NULL ); break; } texObject = texTarget->getTexture(); // If no texture is available then map the default 2x2 // black texture to it. This at least will ensure that // we get consistant behavior across GPUs and platforms. if ( !texObject ) texObject = GFXTexHandle::ZERO; if ( handles->mRTParamsSC[samplerRegister]->isValid() && texObject ) { const Point3I &targetSz = texObject->getSize(); const RectI &targetVp = texTarget->getViewport(); Point4F rtParams; ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); shaderConsts->set(handles->mRTParamsSC[samplerRegister], rtParams); } GFX->setTexture( samplerRegister, texObject ); break; } } } } }
void RenderImposterMgr::_innerRender( const SceneState *state, ShaderState &shaderState ) { PROFILE_SCOPE( RenderImposterMgr_InnerRender ); // Capture the GFX stats for this render. GFXDeviceStatistics stats; stats.start( GFX->getDeviceStatistics() ); GFXTransformSaver saver; // Init the shader. GFX->setShader( shaderState.mShader ); GFX->setShaderConstBuffer( shaderState.mConsts ); GFX->setStateBlock( shaderState.mSB ); // Set the projection and world transform info. MatrixF proj = GFX->getProjectionMatrix() * GFX->getWorldMatrix(); shaderState.mConsts->set( shaderState.mWorldViewProjectSC, proj ); if ( shaderState.mSunDirSC || shaderState.mLightColorSC || shaderState.mAmbientSC ) { // Pass the lighting consts. const LightInfo *sunlight = state->getLightManager()->getSpecialLight( LightManager::slSunLightType ); VectorF sunDir( sunlight->getDirection() ); sunDir.normalize(); shaderState.mConsts->set( shaderState.mSunDirSC, sunDir ); shaderState.mConsts->set( shaderState.mLightColorSC, sunlight->getColor() ); shaderState.mConsts->set( shaderState.mAmbientSC, sunlight->getAmbient() ); } // Get the data we need from the camera matrix. const MatrixF &camMat = state->getCameraTransform(); Point3F camPos; VectorF camRight, camUp, camDir; camMat.getColumn( 0, &camRight ); camMat.getColumn( 1, &camDir ); camMat.getColumn( 2, &camUp ); camMat.getColumn( 3, &camPos ); shaderState.mConsts->set( shaderState.mCamPosSC, camPos ); shaderState.mConsts->set( shaderState.mCamRightSC, camRight ); shaderState.mConsts->set( shaderState.mCamUpSC, camUp ); if ( shaderState.mLightTexRT && shaderState.mLightTarget ) { GFXTextureObject *texObject = shaderState.mLightTarget->getTargetTexture( 0 ); GFX->setTexture( 2, texObject ); // TODO: This normally shouldn't be NULL, but can be on the // first render... not sure why... we should investigate and // fix that rather than protect against it. if ( texObject ) { const Point3I &targetSz = texObject->getSize(); const RectI &targetVp = shaderState.mLightTarget->getTargetViewport(); Point4F rtParams; ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); shaderState.mConsts->set( shaderState.mLightTexRT, rtParams ); } } // Setup a fairly large dynamic vb to hold a bunch of imposters. if ( !mVB.isValid() ) { // Setup the vb to hold a bunch of imposters at once. mVB.set( GFX, mImposterBatchSize * 4, GFXBufferTypeDynamic ); // Setup a static index buffer for rendering. mIB.set( GFX, mImposterBatchSize * 6, 0, GFXBufferTypeStatic ); U16 *idxBuff; mIB.lock(&idxBuff, NULL, NULL, NULL); for ( U32 i=0; i < mImposterBatchSize; i++ ) { // // The vertex pattern in the VB for each // imposter is as follows... // // 0----1 // |\ | // | \ | // | \ | // | \| // 3----2 // // We setup the index order below to ensure // sequental, cache friendly, access. // U32 offset = i * 4; idxBuff[i*6+0] = 0 + offset; idxBuff[i*6+1] = 1 + offset; idxBuff[i*6+2] = 2 + offset; idxBuff[i*6+3] = 2 + offset; idxBuff[i*6+4] = 3 + offset; idxBuff[i*6+5] = 0 + offset; } mIB.unlock(); } // Set the buffers here once. GFX->setPrimitiveBuffer( mIB ); GFX->setVertexBuffer( mVB ); // Batch up the imposters into the buffer. These // are already sorted by texture, to minimize switches // so just batch them up and render as they come. ImposterVertex* vertPtr = NULL; U32 vertCount = 0; F32 halfSize, fade, scale; Point3F center; QuatF rotQuat; const U32 binSize = mElementList.size(); for( U32 i=0; i < binSize; ) { ImposterRenderInst *ri = static_cast<ImposterRenderInst*>( mElementList[i].inst ); TSLastDetail* detail = ri->detail; // Setup the textures. GFX->setTexture( 0, detail->getTextureMap() ); GFX->setTexture( 1, detail->getNormalMap() ); // Setup the constants for this batch. Point4F params( (detail->getNumPolarSteps() * 2) + 1, detail->getNumEquatorSteps(), detail->getPolarAngle(), detail->getIncludePoles() ); shaderState.mConsts->set( shaderState.mParamsSC, params ); U32 uvCount = getMin( detail->getTextureUVs().size(), 64 ); AlignedArray<Point4F> rectData( uvCount, sizeof( Point4F ), (U8*)detail->getTextureUVs().address(), false ); shaderState.mConsts->set( shaderState.mUVsSC, rectData ); vertPtr = mVB.lock(); vertCount = 0; for ( ; i < binSize; i++ ) { ri = static_cast<ImposterRenderInst*>( mElementList[i].inst ); // Stop the loop if the detail changed. if ( ri->detail != detail ) break; ++smRendered; // If we're out of vb space then draw what we got. if ( vertCount + 4 >= mVB->mNumVerts ) { mVB.unlock(); GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, vertCount, 0, vertCount / 2 ); vertPtr = mVB.lock(); vertCount = 0; } center = ri->center; halfSize = ri->halfSize; fade = ri->alpha; scale = ri->scale; rotQuat = ri->rotQuat; // Fill in the points for this instance. vertPtr->center = center; vertPtr->center.w = 0; vertPtr->miscParams.set( halfSize, fade, scale ); vertPtr->rotQuat.set( rotQuat.x, rotQuat.y, rotQuat.z, rotQuat.w ); vertPtr++; vertPtr->center = center; vertPtr->center.w = 1; vertPtr->miscParams.set( halfSize, fade, scale ); vertPtr->rotQuat.set( rotQuat.x, rotQuat.y, rotQuat.z, rotQuat.w ); vertPtr++; vertPtr->center = center; vertPtr->center.w = 2; vertPtr->miscParams.set( halfSize, fade, scale ); vertPtr->rotQuat.set( rotQuat.x, rotQuat.y, rotQuat.z, rotQuat.w ); vertPtr++; vertPtr->center = center; vertPtr->center.w = 3; vertPtr->miscParams.set( halfSize, fade, scale ); vertPtr->rotQuat.set( rotQuat.x, rotQuat.y, rotQuat.z, rotQuat.w ); vertPtr++; vertCount += 4; } // Any remainder to dump? if ( vertCount > 0 ) { smBatches++; mVB.unlock(); GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, vertCount, 0, vertCount / 2 ); } } // Capture the GFX stats for this render. stats.end( GFX->getDeviceStatistics() ); smDrawCalls += stats.mDrawCalls; smPolyCount += stats.mPolyCount; smRTChanges += stats.mRenderTargetChanges; }