#include "StdAfx.h" #include "PerEntityShadowGenerator.h" #include "NiDefaultErrorHandler.h" #include "NiDX9TextureData.h" #include "TerrainModifier.h" #include "Utility.h" #ifndef CODE_INGAME using namespace SceneCore; CPerEntityShadowGenerator::CPerEntityShadowGenerator(CTerrain* pkTerrain) : m_pkTerrain(pkTerrain) { m_aEntityList = new list[pkTerrain->GetChunkNumX()*pkTerrain->GetChunkNumY()]; } CPerEntityShadowGenerator::~CPerEntityShadowGenerator(void) { m_aEntityList->clear(); delete[] m_aEntityList; } void CPerEntityShadowGenerator::AddShadowCaster(NiEntityInterface* pkEntity) { NiObject* pkObj = NULL; pkEntity->GetPropertyData("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 && iChunkIdxGetChunkNumX()*m_pkTerrain->GetChunkNumY()) { m_aEntityList[iChunkIdx].push_back(pkEntity); } } void CPerEntityShadowGenerator::CastProjectionShadow(CTerrain* pkTerrain, NiPoint3 kLitDir, float fMaxShadowValue, float fBlur) { /* * 创建资源 */ int iNumChunksX = m_pkTerrain->GetChunkNumX(); int iNumChunksY = m_pkTerrain->GetChunkNumY(); NiRenderer* pkRenderer = NiRenderer::GetRenderer(); NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; // 创建一张大图, 将所有的 shadowed texture 拷贝上去.对其进行高斯模糊,再复制到 blend texture NiRenderedTexturePtr pkShadowedTexture = NiRenderedTexture::Create(BLENDTEX_SIZE*iNumChunksX, BLENDTEX_SIZE*iNumChunksY, pkRenderer, kPrefs, Ni2DBuffer::MULTISAMPLE_NONE); NiRenderTargetGroupPtr pkShadowedTextureRTG = NiRenderTargetGroup::Create(pkShadowedTexture->GetBuffer(), pkRenderer, true, true); // 创建一个 sysmem 中的 surface, 将 ShadowedTexture 的像素从显存中拷贝出来 LPDIRECT3DDEVICE9 pkDevice = ((NiDX9Renderer*)pkRenderer)->GetD3DDevice(); LPDIRECT3DSURFACE9 pShadowTextureSurface = NULL; HRESULT hr = pkDevice->CreateOffscreenPlainSurface( BLENDTEX_SIZE*iNumChunksX, BLENDTEX_SIZE*iNumChunksY, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pShadowTextureSurface, NULL ); if (FAILED(hr)) { return; } float fDensity = 1.0f; /* * back up 当先渲染属性 */ NiColorA kBackUpColor; pkRenderer->GetBackgroundColor(kBackUpColor); // back up old RTG NiRenderTargetGroup* pkBackUpRTG = (NiRenderTargetGroup*)(pkRenderer->GetCurrentRenderTargetGroup()); if (pkRenderer->IsRenderTargetGroupActive()) { pkRenderer->EndUsingRenderTargetGroup(); } /* * 将所有 chunk 的阴影渲染到大图 */ // 遍历所有 chunk for (int iRX=0; iRX elementChunksID; // 搜集目标 chunk 周围 9 个 chunk ID for (int iOffsetX=-2; iOffsetX<=2; iOffsetX++) { for (int iOffsetY=-2; iOffsetY<=2; iOffsetY++) { int iX = iRX+iOffsetX; int iY = iRY+iOffsetY; if (iX<0 || iX>=iNumChunksX || iY<0 || iY>=iNumChunksY) { continue; } elementChunksID.push_back(iY*iNumChunksX+iX); } } NiPoint3 kShadowDir = kLitDir; //litDirList[i]; ShadowGeometry* pkShadowGeometry = ShadowGeometry::Create(pkTerrain, kShadowDir, iChunkID, fDensity, 10, 65535); // Shadow Geometry 创建用 Create 函数,销毁用 NiDelete // 遍历 chunk 周围9个chunk 的 entity for (unsigned int k=0; k::iterator iter = m_aEntityList[uiID].begin(); while (iter != m_aEntityList[uiID].end()) { NiEntityInterface* pkEntity = (*iter); NiObject* pkObj = NULL; pkEntity->GetPropertyData("Scene Root Pointer", pkObj, 0); if (pkObj==NULL || !NiIsKindOf(NiAVObject, pkObj)) { iter++; continue; } NiAVObject* pkAVObj = NiDynamicCast(NiAVObject, pkObj); pkShadowGeometry->AddCaster(pkAVObj); iter++; } } NiCamera kCamera; kCamera.LookAtWorldPoint(NiPoint3(0,0,-1), NiPoint3(0,1,0)); kCamera.SetTranslate(0,0,200); kCamera.Update(0.0f); // 设置 Frustum 和 ViewPort NiFrustum kFrustum(iRX*GRIDINCHUNK , (iRX+1)*GRIDINCHUNK, (iRY+1)*GRIDINCHUNK, (iRY)*GRIDINCHUNK, 1, 1000.0f, true); kCamera.SetViewFrustum(kFrustum); NiRect kRect; float fPerChunkX = 1.0 / iNumChunksX; float fPerChunkY = 1.0 / iNumChunksY; kRect.m_left = iRX * fPerChunkX; kRect.m_right = (iRX+1) * fPerChunkX; kRect.m_bottom = iRY * fPerChunkY; kRect.m_top = (iRY+1) * fPerChunkY; kCamera.SetViewPort(kRect); kCamera.Update(0.0f); pkRenderer->BeginOffScreenFrame(); pkShadowGeometry->Click(0.0f, &kCamera); pkRenderer->EndOffScreenFrame(); pkRenderer->BeginOffScreenFrame(); pkRenderer->BeginUsingRenderTargetGroup(pkShadowedTextureRTG, NiRenderer::CLEAR_NONE); NiVisibleArray kVisibleArray; NiCullingProcess kCullProcess(&kVisibleArray); NiEntityRenderingContext kRenderingContext; kRenderingContext.m_pkCamera = &kCamera; kRenderingContext.m_pkCullingProcess = &kCullProcess; kRenderingContext.m_pkRenderer = pkRenderer; pkRenderer->SetCameraData(&kCamera); //pkRenderer->SetBackgroundColor(kBackUpColor); NiCullScene(&kCamera, pkShadowGeometry->GetShadowGeometry(), kCullProcess, kVisibleArray, true); NiDrawVisibleArray(&kCamera, kVisibleArray); pkRenderer->EndUsingRenderTargetGroup(); pkRenderer->EndOffScreenFrame(); NiDelete pkShadowGeometry; } } /* * 对 pkShadowedTexture 进行 blur */ pkRenderer->BeginOffScreenFrame(); _BlurTexture(pkShadowedTexture, fBlur); pkRenderer->EndOffScreenFrame(); /* * 恢复渲染属性 */ pkRenderer->SetBackgroundColor(kBackUpColor); if (pkBackUpRTG != NULL) { pkRenderer->BeginUsingRenderTargetGroup(pkBackUpRTG, NiRenderer::CLEAR_ALL); } //SaveTextureToDDS(pkShadowedTexture, "_AfterBlue.dds"); /* * 将 pkShadowedTexture 应用到 chunk 的 blend texture */ Ni2DBuffer* pkBuffer = pkShadowedTexture->GetBuffer(); NiDX92DBufferData* pkBufferData = (NiDX92DBufferData*)pkBuffer->GetRendererData(); LPDIRECT3DSURFACE9 pkSourceSurface = pkBufferData->GetSurface(); hr = D3DXLoadSurfaceFromSurface( pShadowTextureSurface, NULL, NULL, pkSourceSurface, NULL, NULL, D3DX_FILTER_POINT, 0xFF000000 ); // 将 shadowTextureSurface lock, 获取像素值 D3DLOCKED_RECT lockedRect; pShadowTextureSurface->LockRect(&lockedRect, 0, 0); DWORD* pImageData = (DWORD*)lockedRect.pBits; CTerrain::stChunk* pChunks = m_pkTerrain->GetChunks(); // 遍历所有 chunk, 将阴影写入 blend texture unsigned char ucMaxShadow = (unsigned char)(255*(1.0f-fMaxShadowValue)); for (int iRX=0; iRXGetBlendTexture(); NiPixelData* pkPixelData = pkBlendTexture->GetSourcePixelData(); for (int m=0; m>16)); if (ucShadowValue == 0) { // 不在阴影 continue; } else { unsigned char ucValue = max(ucMaxShadow, pPixel[3]-ucShadowValue); pPixel[3] = ucValue; } } } pkPixelData->MarkAsChanged(); } } pShadowTextureSurface->UnlockRect(); SAFE_RELEASE(pShadowTextureSurface); pkShadowedTextureRTG = NULL; pkShadowedTexture = NULL; CTerrainModifier::SmoothBlendTextureEdge(m_pkTerrain); m_pkTerrain->_Update(0.0f, 0.0f); } void CPerEntityShadowGenerator::_BlurTexture(NiRenderedTexture* pkTexture, float fBlur) { //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(); if (pkRenderer == NULL) return; NiTexture::FormatPrefs kPrefs; kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; NiRenderedTexturePtr pkRTTexture = NiRenderedTexture::Create(uiWidth, uiHeight, pkRenderer, kPrefs, Ni2DBuffer::MULTISAMPLE_NONE); // U blur 目标纹理 NiRenderedTexturePtr pkRTSource = pkTexture; // 源纹理/V blur 目标纹理 NiRenderTargetGroupPtr pkRTG0 = NiRenderTargetGroup::Create(pkRTTexture->GetBuffer(), pkRenderer, true, true); NiRenderTargetGroupPtr pkRTGFinal = NiRenderTargetGroup::Create(pkRTSource->GetBuffer(), pkRenderer, true, true); //---------------------------------------------------------------------------------------------------- /* * 2. 创建 ScreenfillRenderView/material */ NiScreenFillingRenderViewPtr pkRTViewBlurU = NiNew NiScreenFillingRenderView; NiScreenFillingRenderViewPtr pkRTViewBlurV = NiNew NiScreenFillingRenderView; NiMaterialPtr pkBlurUMtl = NiSingleShaderMaterial::Create( "BlurU" ); NiMaterialPtr pkBlurVMtl = NiSingleShaderMaterial::Create( "BlurV" ); bool bResult = false; // 更新 shader 参数 NiPoint2 kTexelSize(1.0f/(uiWidth), 1.0f/(uiHeight)); kTexelSize *= fBlur; NiShaderFactory::UpdateGlobalShaderConstant("Bloom_TexSize", sizeof(NiPoint2), &kTexelSize); float fScale = 1.0f; NiShaderFactory::UpdateGlobalShaderConstant("Bloom_Scale", sizeof(float), &fScale); // Blur U bResult = pkRTViewBlurU->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkBlurUMtl ); NiTexturingPropertyPtr pkRTViewTexProp1 = NiNew NiTexturingProperty; pkRTViewTexProp1->SetBaseTexture( pkRTSource ); pkRTViewTexProp1->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp1->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp1->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewBlurU->AttachProperty( pkRTViewTexProp1 ); // Blur V bResult = pkRTViewBlurV->GetScreenFillingQuad().ApplyAndSetActiveMaterial( pkBlurVMtl ); NiTexturingPropertyPtr pkRTViewTexProp2 = NiNew NiTexturingProperty; pkRTViewTexProp2->SetBaseTexture( pkRTTexture); pkRTViewTexProp2->SetBaseFilterMode( NiTexturingProperty::FILTER_BILERP ); pkRTViewTexProp2->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); pkRTViewTexProp2->SetBaseClampMode(NiTexturingProperty::CLAMP_S_CLAMP_T); pkRTViewBlurV->AttachProperty(pkRTViewTexProp2); //---------------------------------------------------------------------------------------------------- /* * 3. 创建 RenderStep/RenderClick */ NiDefaultClickRenderStepPtr pkRenderStep = NiNew NiDefaultClickRenderStep; // 3.1 create render click NiViewRenderClickPtr pkRenderClick = NiNew NiViewRenderClick; // 3.2 U Blur pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewBlurU); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTG0); pkRenderStep->AppendRenderClick(pkRenderClick); // 3.3 V Blur pkRenderClick = NiNew NiViewRenderClick; pkRenderClick->AppendRenderView(pkRTViewBlurV); pkRenderClick->SetClearAllBuffers(true); pkRenderClick->SetRenderTargetGroup(pkRTGFinal); pkRenderStep->AppendRenderClick(pkRenderClick); pkRenderStep->Render(); if (pkRenderer->IsRenderTargetGroupActive()) { pkRenderer->EndUsingRenderTargetGroup(); } pkRTTexture = NULL; //SaveTextureToDDS(pkRTTexture0, "rt0.dds"); //SaveTextureToDDS(pkRTTexture1, "rt1.dds"); } #endif