#include "StdAfx.h" #ifndef CODE_INGAME #include "AOPerVertexShadowGenerator.h" #include "Terrain.h" //#include "NiSpeedTreeComponent.h" #include "NiDefaultErrorHandler.h" #include #include "Utility.h" #include "TerrainModifier.h" using namespace SceneCore; //-------------------------------------------------------------------------------- CAOPerVertexShadowGenerator::CAOPerVertexShadowGenerator(CTerrain* pkTerrain) : m_pkTerrain(pkTerrain), m_kDiskGenerator(pkTerrain) { int iNumChunks = m_kDiskGenerator.m_iNumChunkX*m_kDiskGenerator.m_iNumChunkY; m_aEntityList = new list[iNumChunks]; } //-------------------------------------------------------------------------------- CAOPerVertexShadowGenerator::~CAOPerVertexShadowGenerator(void) { } //-------------------------------------------------------------------------------- /// 添加投射阴影的物件,利用该物件产生 AODisk //void CAOPerVertexShadowGenerator::AddShadowEmitter(NiAVObject* pkAVObj) //{ // //if (pkAVObj != NULL) // //{ // // pkAVObj->Update(0.0f); // // m_kDiskGenerator.RecursiveFindGenerateDisk(pkAVObj); // //} // // //int iChunkIdx = m_pkTerrain->GetChunkIndex(pkAVObj->GetWorldBound().GetCenter()); // //if (iChunkIdx>-1 && iChunkIdxGetPropertyData("Scene Root Pointer", pkObj, 0); if (pkObj==NULL || !NiIsKindOf(NiAVObject, pkObj)) { return; } NiAVObject* pkAVObj = NiDynamicCast(NiAVObject, pkObj); int iChunkIdx = m_pkTerrain->GetChunkIndex(pkAVObj->GetWorldBound().GetCenter()); if (iChunkIdx>-1 && iChunkIdxLinkEndChild(pElmMapRoot); int iNumChunksX = m_pkTerrain->GetChunkNumX(); int iNumChunksY = m_pkTerrain->GetChunkNumY(); pElmMapRoot->SetAttribute("NumChunkX", iNumChunksX); pElmMapRoot->SetAttribute("NumChunkY", iNumChunksY); TiXmlElement* pElmTerrainDiskRoot = new TiXmlElement("TerrainDiskRoot"); TiXmlElement* pElmSceneDiskRoot = new TiXmlElement("SceneDiskRoot"); pElmMapRoot->LinkEndChild(pElmTerrainDiskRoot); pElmMapRoot->LinkEndChild(pElmSceneDiskRoot); for (int i=0; iSetAttribute("ChunkID", i); pElmTerrainDiskRoot->LinkEndChild(pElmTerrainDiskChunk); // 遍历所有 i chunk 的 terrain disk list &diskList = m_kDiskGenerator.m_aTerrainDiskList[i]; list::iterator iter = diskList.begin(); while (iter != diskList.end()) { tAODisk& disk = (*iter); TiXmlElement* pElmDisk = new TiXmlElement("Disk"); pElmDisk->SetDoubleAttribute("X", disk.kPosition.x); pElmDisk->SetDoubleAttribute("Y", disk.kPosition.y); pElmDisk->SetDoubleAttribute("Z", disk.kPosition.z); pElmDisk->SetDoubleAttribute("DirX", disk.kNormal.x); pElmDisk->SetDoubleAttribute("DirY", disk.kNormal.y); pElmDisk->SetDoubleAttribute("DirZ", disk.kNormal.z); pElmDisk->SetDoubleAttribute("Area", disk.fArea); pElmTerrainDiskChunk->LinkEndChild(pElmDisk); iter++; } TiXmlElement* pElmSceneDiskChunk = new TiXmlElement("Chunk"); pElmSceneDiskChunk->SetAttribute("ChunkID", i); pElmTerrainDiskRoot->LinkEndChild(pElmSceneDiskChunk); // 遍历所有 i chunk 的 scene disk diskList = m_kDiskGenerator.m_aSceneDiskList[i]; iter = diskList.begin(); while (iter != diskList.end()) { tAODisk& disk = (*iter); TiXmlElement* pElmDisk = new TiXmlElement("Disk"); pElmDisk->SetDoubleAttribute("X", disk.kPosition.x); pElmDisk->SetDoubleAttribute("Y", disk.kPosition.y); pElmDisk->SetDoubleAttribute("Z", disk.kPosition.z); pElmDisk->SetDoubleAttribute("DirX", disk.kNormal.x); pElmDisk->SetDoubleAttribute("DirY", disk.kNormal.y); pElmDisk->SetDoubleAttribute("DirZ", disk.kNormal.z); pElmDisk->SetDoubleAttribute("Area", disk.fArea); pElmSceneDiskChunk->LinkEndChild(pElmDisk); iter++; } } pDoc->SaveFile(); pDoc->Clear(); delete pDoc; return true; } //-------------------------------------------------------------------------------- // 保存地形 disk info bool CAOPerVertexShadowGenerator::LoadSceneDiskInfo(const char* pszFileName) { return true; } //-------------------------------------------------------------------------------- void CAOPerVertexShadowGenerator::GenerateTerrainShadow(int iChunkID, float fTerrainAffectFactor, float fSceneAffectFactor, float fMaxShadowValue) { if (m_pkTerrain == NULL) { return; } int iNumChunks = m_kDiskGenerator.m_iNumChunkX*m_kDiskGenerator.m_iNumChunkY; if (iChunkID<0 || iChunkID>=iNumChunks) { // 非法的 chunk id return; } // 先不计算 bent nromal, 只计算 shadow // 每个 terrain 顶点对应的 shadow int iNumVertex = m_kDiskGenerator.m_aTerrainDiskList[iChunkID].size(); float* pShadowValues = new float[iNumVertex]; ZeroMemory(pShadowValues, sizeof(float)*iNumVertex); int iDiskIndex = 0; //const float SHADOW_AFFECT_FACTOR_TERRAIN = 25.0f; //const float SHADOW_AFFECT_FACTOR_OBJECT = 12.0f; // receive disk: 遍历所有iChunkID chunk AODisk // emitter disk: 遍历 iChunkID 周围9块(包括自己) 的 chunk AODisk std::vector elementChunksID; // 目标 chunk 的 chunk 坐标 int iRX = iChunkID%m_kDiskGenerator.m_iNumChunkX; int iRY = iChunkID/m_kDiskGenerator.m_iNumChunkX; // 搜集目标 chunk 周围 9 个 chunk ID for (int iOffsetX=-1; iOffsetX<=1; iOffsetX++) { for (int iOffsetY=-1; iOffsetY<=1; iOffsetY++) { int iX = iRX+iOffsetX; int iY = iRY+iOffsetY; if (iX<0 || iX>=m_kDiskGenerator.m_iNumChunkX || iY<0 || iY>=m_kDiskGenerator.m_iNumChunkY) { continue; } elementChunksID.push_back(iY*m_kDiskGenerator.m_iNumChunkX+iX); } } list::iterator rIter = m_kDiskGenerator.m_aTerrainDiskList[iChunkID].begin(); while (rIter != m_kDiskGenerator.m_aTerrainDiskList[iChunkID].end()) { tAODisk& rAODisk = (*rIter); // receive disk float fBound = 0.01f; if (rAODisk.fArea > fBound) {for (UINT i=0; i::iterator eIter = m_kDiskGenerator.m_aTerrainDiskList[iEChunkID].begin(); while (eIter != m_kDiskGenerator.m_aTerrainDiskList[iEChunkID].end()) { //if (eIter == rIter) //{ // eIter++; // continue; // 不接受本 disk 投射 //} tAODisk& eAODisk = (*eIter); if (eAODisk.fArea > fBound) { NiPoint3 v = rAODisk.kPosition - eAODisk.kPosition; float r = v.Length(); v /= r; if (rAODisk.kNormal!=eAODisk.kNormal && eAODisk.fArea*fTerrainAffectFactor>r) { float fVal = ElementShadow(v, r, rAODisk.kNormal, eAODisk.kNormal, eAODisk.fArea); pShadowValues[iDiskIndex] += fVal; } } eIter++; } // 2.计算地表物件在地形上的阴影 不再用物件影响地形 ao //eIter = m_kDiskGenerator.m_aSceneDiskList[iEChunkID].begin(); //while (eIter != m_kDiskGenerator.m_aSceneDiskList[iEChunkID].end()) //{ // tAODisk& eAODisk = (*eIter); // NiPoint3 v = rAODisk.kPosition - eAODisk.kPosition; // float r = v.Length(); // v /= r; // if (rAODisk.kNormal!=eAODisk.kNormal && eAODisk.fArea*fSceneAffectFactor>r) // { // float fVal = ElementShadow(v, r, rAODisk.kNormal, eAODisk.kNormal, eAODisk.fArea); // pShadowValues[iDiskIndex] += fVal*0.5f; // } // eIter++; //} } if (pShadowValues[iDiskIndex]<-fMaxShadowValue) { pShadowValues[iDiskIndex]=-fMaxShadowValue; } } rIter++; iDiskIndex++; } // shadow value 计算完成.将每个顶点的 shadow value 写到 blend texture alpha 通道 // 该 chunk 第一个顶点的行列 //int iFirstVertX = iRX * GRIDINCHUNK; //int iFirstVertY = iRY * GRIDINCHUNK; //int iNumVertInRow = m_kDiskGenerator.m_iNumChunkX*GRIDINCHUNK+1; int iNumVertInRow = GRIDINCHUNK+1; CTerrain::stChunk* pChunks = m_pkTerrain->GetChunks(); NiSourceTexturePtr pkBlendTexture = pChunks[iChunkID].pChunkMtl->GetBlendTexture(); NiPixelData* pkPixelData = pkBlendTexture->GetSourcePixelData(); // 遍历一个 chunk 的所有 grid, 找出4个顶点,插值计算对应的 16 个像素,写入 blend texture alpha 通道 for (int m=0; mMarkAsChanged(); delete[] pShadowValues; } void CAOPerVertexShadowGenerator::GenerateSceneObjectShadow(float fMaxShadowValue, float fBlur, float fBlurTexSize) { // 创建整个地形的物件阴影 /* * 1. 验证资源 */ std::vector elementChunksID; // 地形尺寸 int iNumChunkX = m_kDiskGenerator.m_iNumChunkX; int iNumChunkY = m_kDiskGenerator.m_iNumChunkY; // Chunk 尺寸小于 8 assert(iNumChunkX>0 && iNumChunkX<=8); assert(iNumChunkY>0 && iNumChunkY<=8); //-------------------------------------------------------------------------------------------------------- /* * 2. 创建 RTG */ NiRendererPtr pkRenderer = NiRenderer::GetRenderer(); NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiRenderedTexturePtr pkRTTexture = NiRenderedTexture::Create(BLENDTEX_SIZE*iNumChunkX, BLENDTEX_SIZE*iNumChunkY, pkRenderer, kPrefs, Ni2DBuffer::MULTISAMPLE_NONE); NiRenderTargetGroupPtr pkRTG = NiRenderTargetGroup::Create(pkRTTexture->GetBuffer(), pkRenderer, true, true); //-------------------------------------------------------------------------------------------------------- /* * 3. 设置摄象机 */ NiCamera kCamera; NiPoint3 kTranslate((iNumChunkX)*GRIDINCHUNK/2, (iNumChunkY)*GRIDINCHUNK/2, 200); NiPoint3 kLookAt((iNumChunkX)*GRIDINCHUNK/2, (iNumChunkY)*GRIDINCHUNK/2, 0); NiMatrix3 kRotation; NiPoint3 kUpAxis = NiPoint3::UNIT_Y; if (kTranslate.Cross(kUpAxis).Length() != 0.0f) { kRotation = NiViewMath::LookAt(kLookAt, kTranslate, kUpAxis); } else { NiPoint3 kNewUpAxis; if ((kTranslate.Dot(NiPoint3::UNIT_Z) < NiViewMath::PARALLEL_THRESHOLD) && (kTranslate.Dot(NiPoint3::UNIT_Z) > -NiViewMath::PARALLEL_THRESHOLD)) { kNewUpAxis = NiPoint3::UNIT_Z; } else if ((kTranslate.Dot(NiPoint3::UNIT_Y) < NiViewMath::PARALLEL_THRESHOLD) && (kTranslate.Dot(NiPoint3::UNIT_Y) > -NiViewMath::PARALLEL_THRESHOLD)) { kNewUpAxis = NiPoint3::UNIT_Y; } else { kNewUpAxis = NiPoint3::UNIT_X; } kRotation = NiViewMath::LookAt(kLookAt, kTranslate, kNewUpAxis); } kCamera.SetTranslate(kTranslate); kCamera.SetRotate(kRotation); kCamera.Update(0.0f); NiFrustum kFrustum(-(iNumChunkX)*GRIDINCHUNK/2, (iNumChunkX)*GRIDINCHUNK/2, (iNumChunkY)*GRIDINCHUNK/2, -(iNumChunkY)*GRIDINCHUNK/2, 0.1f, 1000.0f, true); kFrustum.m_bOrtho = true; kCamera.SetViewFrustum(kFrustum); kCamera.Update(0.0f); //-------------------------------------------------------------------------------------------------------- /* * 4. Back Up 当前 Renderer 属性 */ // back up old material, RTG, BackColor NiMaterial* pkBackUpMaterial = pkRenderer->GetDefaultMaterial(); NiRenderTargetGroup* pkBackUpRTG; NiColorA kBackUpColor; pkRenderer->GetBackgroundColor(kBackUpColor); //-------------------------------------------------------------------------------------------------------- /* * 5. 渲染所有物件到RTG */ // back up old RTG pkBackUpRTG = (NiRenderTargetGroup*)(pkRenderer->GetCurrentRenderTargetGroup()); if (pkRenderer->IsRenderTargetGroupActive()) { pkRenderer->EndUsingRenderTargetGroup(); } pkRenderer->BeginOffScreenFrame(); pkRenderer->SetBackgroundColor(NiColorA(1, 1, 1, 1)); pkRenderer->SetCameraData(&kCamera); NiVisibleArray kVisibleArray; NiCullingProcess kCullProcess(&kVisibleArray); NiEntityRenderingContext kRenderingContext; kRenderingContext.m_pkCamera = &kCamera; kRenderingContext.m_pkCullingProcess = &kCullProcess; kRenderingContext.m_pkRenderer = pkRenderer; // 先渲染地形,将地形的深度信息写入 z buffer pkRenderer->BeginUsingRenderTargetGroup(pkRTG, NiRenderer::CLEAR_ALL); NiCullScene(&kCamera, m_pkTerrain->GetTerrainRootNode(), kCullProcess, kVisibleArray, true); NiDrawVisibleArray(&kCamera, kVisibleArray); pkRenderer->EndUsingRenderTargetGroup(); kVisibleArray.RemoveAll(); pkRenderer->BeginUsingRenderTargetGroup(pkRTG, NiRenderer::CLEAR_BACKBUFFER); for (UINT i=0; i::iterator iter = m_aEntityList[uiID].begin(); while (iter != m_aEntityList[uiID].end()) { NiEntityInterface* pkEntity = (*iter); NiDefaultErrorHandlerPtr pkErrorHandler = NiNew NiDefaultErrorHandler(); pkEntity->BuildVisibleSet(&kRenderingContext, pkErrorHandler); iter++; } } NiDrawVisibleArray(&kCamera, kVisibleArray); if (pkRenderer->IsRenderTargetGroupActive()) { pkRenderer->EndUsingRenderTargetGroup(); } pkRenderer->EndOffScreenFrame(); //SaveTextureToDDS(pkRTTexture, "_tmpBeforeBlur.dds"); /* * 6. 对渲染得到的文理在 UV 方向模糊 */ pkRenderer->BeginOffScreenFrame(); _BlurTexture(pkRTTexture, fBlur, fBlurTexSize); pkRenderer->EndOffScreenFrame(); /* * 7. 恢复 Renderer 属性 */ pkRenderer->SetBackgroundColor(kBackUpColor); pkRenderer->SetDefaultMaterial(pkBackUpMaterial); if (pkBackUpRTG != NULL) { pkRenderer->BeginUsingRenderTargetGroup(pkBackUpRTG, NiRenderer::CLEAR_ALL); } else { pkRenderer->BeginUsingDefaultRenderTargetGroup(NiRenderer::CLEAR_ALL); } /* * 8. 将shadow texture 应用到地形 blend texture */ SaveTextureToDDS(pkRTTexture, "_tmpShadowTexture.dds"); NiSourceTexturePtr pkShadowTexture = NiSourceTexture::Create("_tmpShadowTexture.dds"); pkShadowTexture->LoadPixelDataFromFile(); // 遍历所有 Chunk CTerrain::stChunk* pChunks = m_pkTerrain->GetChunks(); for (int i=0; iGetBlendTexture(); NiPixelData* pkPixelData = pkBlendTexture->GetSourcePixelData(); NiPixelData* pkSourcePixelData = pkShadowTexture->GetSourcePixelData(); // 当前 chunk 对应的第一个象速在整张图上的坐标 int iTexOffsetY = (iNumChunkY - 1 - j) * BLENDTEX_SIZE; int iTexOffsetX = (i) * BLENDTEX_SIZE; // 遍历所有像素,将像素叠加到 chunk 的 blend texture alpha 通道中 for (int m=0; mMarkAsChanged(); } } CTerrainModifier::SmoothBlendTextureEdge(m_pkTerrain); // 测试部分 //SaveTextureToDDS(pkRTTexture, "e:\\test.dds"); // 把这个部分移到最后 try 一 try //-------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------- } void CAOPerVertexShadowGenerator::_BlurTexture(NiTexture* pkTexture, float fBlur, float fBlurTexSize) { fBlurTexSize = min(1.0f, fBlurTexSize); fBlurTexSize = max(fBlurTexSize, 1.0f/64.0f); //NiColorA kBGColor(1.0f, 1.0f, 1.0f, 1.0f); /* * 1. 创建 RTG */ NiRendererPtr pkRenderer = NiRenderer::GetRenderer(); unsigned int uiWidth = pkTexture->GetWidth(); unsigned int uiHeight = pkTexture->GetHeight(); unsigned int uiBlurTexWidth = uiWidth * fBlurTexSize; unsigned int uiBlurTexHeight = uiHeight * fBlurTexSize; if (pkRenderer == NULL) return; NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiRenderedTexturePtr pkRTTexture0 = NiRenderedTexture::Create(uiBlurTexWidth, uiBlurTexHeight, pkRenderer, kPrefs, Ni2DBuffer::MULTISAMPLE_NONE); // scale down 和 V blur 目标纹理 NiRenderedTexturePtr pkRTTexture1 = NiRenderedTexture::Create(uiBlurTexWidth, uiBlurTexHeight, pkRenderer, kPrefs, Ni2DBuffer::MULTISAMPLE_NONE); // U blur 目标纹理 NiRenderedTexturePtr pkRTSource = NiDynamicCast(NiRenderedTexture, pkTexture); // 源纹理/scale up 目标纹理 NiRenderTargetGroupPtr pkRTG0 = NiRenderTargetGroup::Create(pkRTTexture0->GetBuffer(), pkRenderer, true, true); NiRenderTargetGroupPtr pkRTG1 = NiRenderTargetGroup::Create(pkRTTexture1->GetBuffer(), pkRenderer, true, true); NiRenderTargetGroupPtr pkRTGFinal = NiRenderTargetGroup::Create(pkRTSource->GetBuffer(), pkRenderer, true, true); //---------------------------------------------------------------------------------------------------- /* * 2. 创建 ScreenfillRenderView/material */ NiScreenFillingRenderViewPtr pkRTViewScaleDown = NiNew NiScreenFillingRenderView; NiScreenFillingRenderViewPtr pkRTViewBlurU = NiNew NiScreenFillingRenderView; NiScreenFillingRenderViewPtr pkRTViewBlurV = NiNew NiScreenFillingRenderView; NiScreenFillingRenderViewPtr pkRTViewScaleUp = NiNew NiScreenFillingRenderView; NiMaterialPtr pkScaleDownMtl = NiSingleShaderMaterial::Create( "ScaleDownUnLum" );//ScaleDown NiMaterialPtr pkBlurUMtl = NiSingleShaderMaterial::Create( "BlurU" ); NiMaterialPtr pkBlurVMtl = NiSingleShaderMaterial::Create( "BlurV" ); NiMaterialPtr pkScaleUpMtl = NiSingleShaderMaterial::Create( "ScaleUp" ); NiPoint2 kTexelSize(1.0f/(uiBlurTexWidth), 1.0f/(uiBlurTexHeight)); kTexelSize *= fBlur; float fLum = 1.0f; float fScale = 1.0f; NiShaderFactory::UpdateGlobalShaderConstant("Bloom_Luminance", sizeof(float), &fLum); NiShaderFactory::UpdateGlobalShaderConstant("Bloom_TexSize", sizeof(NiPoint2), &kTexelSize); NiShaderFactory::UpdateGlobalShaderConstant("Bloom_Scale", sizeof(float), &fScale); bool bResult = false; // Scale Down // Extra data pkRTViewScaleDown->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkScaleDownMtl ); NiTexturingPropertyPtr pkRTViewTexProp0 = NiNew NiTexturingProperty; pkRTViewTexProp0->SetBaseTexture( pkRTSource ); pkRTViewTexProp0->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp0->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp0->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewScaleDown->AttachProperty( pkRTViewTexProp0 ); NiPoint2 kScalDownTexelSize(1.0f / uiWidth, 1.0f / uiHeight) ;// .0f, 0.0f); NiFloatsExtraData* pkEDkScalDownTexelSize = NiNew NiFloatsExtraData( 2, (float *)&kScalDownTexelSize.x); pkRTViewScaleDown->GetScreenFillingQuad().AddExtraData("TexelSize", pkEDkScalDownTexelSize); pkRTViewScaleDown->GetScreenFillingQuad().UpdateEffects(); pkRTViewScaleDown->GetScreenFillingQuad().UpdateProperties(); pkRTViewScaleDown->GetScreenFillingQuad().Update(0.0f); // Blur U //NiFloatExtraData* pkEDBlurUScale = NiNew NiFloatExtraData(1.0f); //NiFloatsExtraData* pkEDBlurUTexelSize = NiNew NiFloatsExtraData( 2, (float *)&kTexelSize.x); bResult = pkRTViewBlurU->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkBlurUMtl ); NiTexturingPropertyPtr pkRTViewTexProp1 = NiNew NiTexturingProperty; pkRTViewTexProp1->SetBaseTexture( pkRTTexture0 ); pkRTViewTexProp1->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp1->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp1->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewBlurU->AttachProperty( pkRTViewTexProp1 ); //bResult = pkRTViewBlurU->GetScreenFillingQuad().AddExtraData("Bloom_TexSize", pkEDBlurUTexelSize); //bResult = pkRTViewBlurU->GetScreenFillingQuad().AddExtraData("Bloom_Scale", pkEDBlurUScale); //pkRTViewBlurU->GetScreenFillingQuad().UpdateEffects(); //pkRTViewBlurU->GetScreenFillingQuad().UpdateProperties(); //pkRTViewBlurU->GetScreenFillingQuad().Update(0.0f); // Blur V //NiFloatExtraData* pkEDBlurVScale = NiNew NiFloatExtraData(1.0f); //NiFloatsExtraData* pkEDBlurVTexelSize = NiNew NiFloatsExtraData( 2, (float *)&kTexelSize.x); bResult = pkRTViewBlurV->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkBlurVMtl ); NiTexturingPropertyPtr pkRTViewTexProp2 = NiNew NiTexturingProperty; pkRTViewTexProp2->SetBaseTexture( pkRTTexture1 ); pkRTViewTexProp2->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp2->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp2->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewBlurV->AttachProperty(pkRTViewTexProp2); //bResult = pkRTViewBlurV->GetScreenFillingQuad().AddExtraData("Bloom_TexSize", pkEDBlurVTexelSize); //bResult = pkRTViewBlurV->GetScreenFillingQuad().AddExtraData("Bloom_Scale", pkEDBlurVScale); //pkRTViewBlurV->GetScreenFillingQuad().UpdateEffects(); //pkRTViewBlurV->GetScreenFillingQuad().UpdateProperties(); //pkRTViewBlurV->GetScreenFillingQuad().Update(0.0f); // Scale Up pkRTViewScaleUp->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkScaleUpMtl ); NiTexturingPropertyPtr pkRTViewTexProp3 = NiNew NiTexturingProperty; pkRTViewTexProp3->SetBaseTexture( pkRTTexture0 ); pkRTViewTexProp3->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp3->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp3->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewScaleUp->AttachProperty( pkRTViewTexProp3 ); //---------------------------------------------------------------------------------------------------- /* * 3. 创建 RenderStep/RenderClick */ NiDefaultClickRenderStepPtr pkRenderStep = NiNew NiDefaultClickRenderStep; // 3.1 Scale down NiViewRenderClickPtr pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewScaleDown); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTG0); pkRenderStep->AppendRenderClick(pkRenderClick); // 3.2 U Blur pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewBlurU); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTG1); pkRenderStep->AppendRenderClick(pkRenderClick); // 3.3 V Blur pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewBlurV); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTG0); pkRenderStep->AppendRenderClick(pkRenderClick); // 3.4 V Scale Up pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewScaleUp); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTGFinal); pkRenderStep->AppendRenderClick(pkRenderClick); pkRenderStep->Render(); if (pkRenderer->IsRenderTargetGroupActive()) { pkRenderer->EndUsingRenderTargetGroup(); } //SaveTextureToDDS(pkRTTexture0, "rt0.dds"); //SaveTextureToDDS(pkRTTexture1, "rt1.dds"); pkRTTexture0 = NULL; pkRTTexture1 = NULL; } #endif