/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "StdAfx.h" #include "DriverD3D.h" #include "../Common/RendElements/Stars.h" #include "I3DEngine.h" #include "../Common/PostProcess/PostProcessUtils.h" #include "../Common/PostProcess/PostEffects.h" #include "D3DPostProcess.h" #include "CREParticle.h" #include "CREParticleGPU.h" #include "D3DGPUParticleEngine.h" #include "../Common/Renderer.h" #include "../Common/Textures/TextureManager.h" #pragma warning(disable: 4244) //======================================================================= bool CRESky::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd = gcpRendD3D; #if !defined(_RELEASE) if (ef->m_eShaderType != eST_Sky) { CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for sky"); return false; } #endif if (!rd->m_RP.m_pShaderResources || !rd->m_RP.m_pShaderResources->m_pSky) { return false; } // pass 0 - skybox SSkyInfo* pSky = rd->m_RP.m_pShaderResources->m_pSky; if (!pSky->m_SkyBox[0]) { return false; } float v(gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKYBOX_MULTIPLIER)); rd->SetMaterialColor(v, v, v, m_fAlpha); if (!sfm) { ef->FXSetTechnique(CCryNameTSCRC((uint32)0)); } uint32 nPasses = 0; ef->FXBegin(&nPasses, FEF_DONTSETTEXTURES); //ef->FXBegin(&nPasses, 0 ); if (!nPasses) { return false; } ef->FXBeginPass(0); rd->FX_PushVP(); rd->m_NewViewport.fMinZ = 1.0f; rd->m_NewViewport.fMaxZ = 1.0f; rd->m_bViewportDirty = true; STexState pTexState; pTexState.SetFilterMode(FILTER_LINEAR); pTexState.SetClampMode(1, 1, 1); int texStateID = CTexture::GetTexState(pTexState); const float fSkyBoxSize = SKY_BOX_SIZE; rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); if (rd->m_RP.m_nBatchFilter & FB_Z) { CTextureManager::Instance()->GetBlackTexture()->Apply(0, texStateID); { // top SVF_P3F_C4B_T2F data[] = { {Vec3(+fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(-fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(+fSkyBoxSize, +fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(-fSkyBoxSize, +fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 0)} }; CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 4, eptTriangleStrip); } { // nesw SVF_P3F_C4B_T2F data[] = { { Vec3(-fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(+fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(+fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(+fSkyBoxSize, +fSkyBoxSize, +fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(+fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(-fSkyBoxSize, +fSkyBoxSize, +fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(-fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(-fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), { {0} }, Vec2(0, 0)}, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, }; CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 10, eptTriangleStrip); } { // b SVF_P3F_C4B_T2F data[] = { {Vec3(+fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(+fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)}, {Vec3(-fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), { {0} }, Vec2(0, 0)} }; CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 4, eptTriangleStrip); } } else { { // top SVF_P3F_C4B_T2F data[] = { {Vec3(fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1, 1.f - 1)}, {Vec3(-fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 1.f - 1)}, {Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1, 1.f - 0)}, {Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0, 1.f - 0)} }; ((CTexture*)(pSky->m_SkyBox[2]))->Apply(0, texStateID); CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 4, eptTriangleStrip); } Vec3 camera = iSystem->GetViewCamera().GetPosition(); camera.z = max(0.f, camera.z); float fWaterCamDiff = max(0.f, camera.z - m_fTerrainWaterLevel); float fMaxDist = gEnv->p3DEngine->GetMaxViewDistance() / 1024.f; float P = (fWaterCamDiff) / 128 + max(0.f, (fWaterCamDiff) * 0.03f / fMaxDist); P *= m_fSkyBoxStretching; float D = (fWaterCamDiff) / 10.0f * fSkyBoxSize / 124.0f - /*P*/ 0 + 8; D = max(0.f, D); if (m_fTerrainWaterLevel > camera.z && SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID] == 0) { P = (fWaterCamDiff); D = (fWaterCamDiff); } float fTexOffset; fTexOffset = 1.0f / max(pSky->m_SkyBox[1]->GetHeight(), 1); { // s SVF_P3F_C4B_T2F data[] = { { Vec3(-fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1.0, 1.f - 1.0) }, { Vec3(fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0.0, 1.f - 1.0) }, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -P), { {0} }, Vec2(1.0, 1.f - 0.5 - fTexOffset) }, { Vec3(fSkyBoxSize, -fSkyBoxSize, -P), { {0} }, Vec2(0.0, 1.f - 0.5 - fTexOffset) }, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -D), { {0} }, Vec2(1.0, 1.f - 0.5 - fTexOffset) }, { Vec3(fSkyBoxSize, -fSkyBoxSize, -D), { {0} }, Vec2(0.0, 1.f - 0.5 - fTexOffset) } }; ((CTexture*)(pSky->m_SkyBox[1]))->Apply(0, texStateID); CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 6, eptTriangleStrip); } { // e SVF_P3F_C4B_T2F data[] = { { Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1.0, 1.f - 0.0) }, { Vec3(-fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0.0, 1.f - 0.0) }, { Vec3(-fSkyBoxSize, fSkyBoxSize, -P), { {0} }, Vec2(1.0, 1.f - 0.5f + fTexOffset) }, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -P), { {0} }, Vec2(0.0, 1.f - 0.5f + fTexOffset) }, { Vec3(-fSkyBoxSize, fSkyBoxSize, -D), { {0} }, Vec2(1.0, 1.f - 0.5f + fTexOffset) }, { Vec3(-fSkyBoxSize, -fSkyBoxSize, -D), { {0} }, Vec2(0.0, 1.f - 0.5f + fTexOffset) } }; CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 6, eptTriangleStrip); } fTexOffset = 1.0f / max(pSky->m_SkyBox[0]->GetHeight(), 1); { // n SVF_P3F_C4B_T2F data[] = { { Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1.0, 1.f - 1.0) }, { Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0.0, 1.f - 1.0) }, { Vec3(fSkyBoxSize, fSkyBoxSize, -P), { {0} }, Vec2(1.0, 1.f - 0.5 - fTexOffset) }, { Vec3(-fSkyBoxSize, fSkyBoxSize, -P), { {0} }, Vec2(0.0, 1.f - 0.5 - fTexOffset) }, { Vec3(fSkyBoxSize, fSkyBoxSize, -D), { {0} }, Vec2(1.0, 1.f - 0.5 - fTexOffset) }, { Vec3(-fSkyBoxSize, fSkyBoxSize, -D), { {0} }, Vec2(0.0, 1.f - 0.5 - fTexOffset) } }; ((CTexture*)(pSky->m_SkyBox[0]))->Apply(0, texStateID); CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 6, eptTriangleStrip); } { // w SVF_P3F_C4B_T2F data[] = { { Vec3(fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(1.0, 1.f - 0.0) }, { Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), { {0} }, Vec2(0.0, 1.f - 0.0) }, { Vec3(fSkyBoxSize, -fSkyBoxSize, -P), { {0} }, Vec2(1.0, 1.f - 0.5f + fTexOffset) }, { Vec3(fSkyBoxSize, fSkyBoxSize, -P), { {0} }, Vec2(0.0, 1.f - 0.5f + fTexOffset) }, { Vec3(fSkyBoxSize, -fSkyBoxSize, -D), { {0} }, Vec2(1.0, 1.f - 0.5f + fTexOffset) }, { Vec3(fSkyBoxSize, fSkyBoxSize, -D), { {0} }, Vec2(0.0, 1.f - 0.5f + fTexOffset) } }; CVertexBuffer vertexBuffer(data, eVF_P3F_C4B_T2F); rd->DrawPrimitivesInternal(&vertexBuffer, 6, eptTriangleStrip); } } rd->FX_PopVP(); rd->FX_ResetPipe(); return true; } static void FillSkyTextureData(CTexture* pTexture, const void* pData, const uint32 width, const uint32 height, const uint32 pitch) { assert(pTexture && pTexture->GetWidth() == width && pTexture->GetHeight() == height); CDeviceTexture* pDevTex = pTexture->GetDevTexture(); assert(pDevTex); if (!pDevTex) { return; } gcpRendD3D->GetDeviceContext().UpdateSubresource(pDevTex->Get2DTexture(), 0, 0, pData, sizeof(CryHalf4) * width, sizeof(CryHalf4) * width * height); } bool CREHDRSky::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd(gcpRendD3D); #if !defined(_RELEASE) if (ef->m_eShaderType != eST_Sky) { CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for sky"); return false; } #endif if (!rd->m_RP.m_pShaderResources || !rd->m_RP.m_pShaderResources->m_pSky) { return false; } SSkyInfo* pSky(rd->m_RP.m_pShaderResources->m_pSky); if (!pSky->m_SkyBox[0]) { return false; } assert(m_pRenderParams); if (!m_pRenderParams) { return false; } assert(m_pRenderParams->m_pSkyDomeMesh.get()); if (!m_pRenderParams->m_pSkyDomeMesh) { return false; } bool isNotZPass = (rd->m_RP.m_nBatchFilter & FB_Z) == 0; if (isNotZPass) { // re-create sky dome textures if necessary bool forceTextureUpdate(false); if (!CTexture::IsTextureExist(m_pSkyDomeTextureMie) || !CTexture::IsTextureExist(m_pSkyDomeTextureRayleigh)) { GenerateSkyDomeTextures(SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight); forceTextureUpdate = true; } // dyn tex data lost due to device reset? if (m_frameReset != rd->m_nFrameReset) { forceTextureUpdate = true; m_frameReset = rd->m_nFrameReset; } // update sky dome texture if new data is available if (m_skyDomeTextureLastTimeStamp != m_pRenderParams->m_skyDomeTextureTimeStamp || forceTextureUpdate) { FillSkyTextureData(m_pSkyDomeTextureMie, m_pRenderParams->m_pSkyDomeTextureDataMie, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight, m_pRenderParams->m_skyDomeTexturePitch); FillSkyTextureData(m_pSkyDomeTextureRayleigh, m_pRenderParams->m_pSkyDomeTextureDataRayleigh, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight, m_pRenderParams->m_skyDomeTexturePitch); // update time stamp of last update m_skyDomeTextureLastTimeStamp = m_pRenderParams->m_skyDomeTextureTimeStamp; } } // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (!nPasses) { return false; } ef->FXBeginPass(0); I3DEngine* p3DEngine(gEnv->p3DEngine); rd->FX_PushVP(); rd->m_NewViewport.fMinZ = 1.0f; rd->m_NewViewport.fMaxZ = 1.0f; rd->m_bViewportDirty = true; if (isNotZPass) { // shader constants -- set sky dome texture and texel size assert(m_pSkyDomeTextureMie && m_pSkyDomeTextureMie->GetWidth() == SSkyLightRenderParams::skyDomeTextureWidth && m_pSkyDomeTextureMie->GetHeight() == SSkyLightRenderParams::skyDomeTextureHeight); assert(m_pSkyDomeTextureRayleigh && m_pSkyDomeTextureRayleigh->GetWidth() == SSkyLightRenderParams::skyDomeTextureWidth && m_pSkyDomeTextureRayleigh->GetHeight() == SSkyLightRenderParams::skyDomeTextureHeight); Vec4 skyDomeTexSizeVec((float) SSkyLightRenderParams::skyDomeTextureWidth, (float) SSkyLightRenderParams::skyDomeTextureHeight, 0.0f, 0.0f); static CCryNameR Param1Name("SkyDome_TextureSize"); ef->FXSetPSFloat(Param1Name, &skyDomeTexSizeVec, 1); Vec4 skyDomeTexelSizeVec(1.0f / (float) SSkyLightRenderParams::skyDomeTextureWidth, 1.0f / (float) SSkyLightRenderParams::skyDomeTextureHeight, 0.0f, 0.0f); static CCryNameR Param2Name("SkyDome_TexelSize"); ef->FXSetPSFloat(Param2Name, &skyDomeTexelSizeVec, 1); // shader constants -- phase function constants static CCryNameR Param3Name("SkyDome_PartialMieInScatteringConst"); static CCryNameR Param4Name("SkyDome_PartialRayleighInScatteringConst"); static CCryNameR Param5Name("SkyDome_SunDirection"); static CCryNameR Param6Name("SkyDome_PhaseFunctionConstants"); ef->FXSetPSFloat(Param3Name, &m_pRenderParams->m_partialMieInScatteringConst, 1); ef->FXSetPSFloat(Param4Name, &m_pRenderParams->m_partialRayleighInScatteringConst, 1); ef->FXSetPSFloat(Param5Name, &m_pRenderParams->m_sunDirection, 1); ef->FXSetPSFloat(Param6Name, &m_pRenderParams->m_phaseFunctionConsts, 1); // shader constants -- night sky relevant constants Vec3 nightSkyHorizonCol; p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_HORIZON_COLOR, nightSkyHorizonCol); Vec3 nightSkyZenithCol; p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_ZENITH_COLOR, nightSkyZenithCol); float nightSkyZenithColShift(p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_ZENITH_SHIFT)); const float minNightSkyZenithGradient(-0.1f); static CCryNameR Param7Name("SkyDome_NightSkyColBase"); static CCryNameR Param8Name("SkyDome_NightSkyColDelta"); static CCryNameR Param9Name("SkyDome_NightSkyZenithColShift"); Vec4 nsColBase(nightSkyHorizonCol, 0); ef->FXSetPSFloat(Param7Name, &nsColBase, 1); Vec4 nsColDelta(nightSkyZenithCol - nightSkyHorizonCol, 0); ef->FXSetPSFloat(Param8Name, &nsColDelta, 1); Vec4 nsZenithColShift(1.0f / (nightSkyZenithColShift - minNightSkyZenithGradient), -minNightSkyZenithGradient / (nightSkyZenithColShift - minNightSkyZenithGradient), 0, 0); ef->FXSetPSFloat(Param9Name, &nsZenithColShift, 1); CREHDRSky::SetCommonMoonParams(ef, true); Vec3 nightMoonColor; p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_COLOR, nightMoonColor); Vec4 nsMoonColor(nightMoonColor, 0); static CCryNameR Param11Name("SkyDome_NightMoonColor"); ef->FXSetPSFloat(Param11Name, &nsMoonColor, 1); Vec3 nightMoonInnerCoronaColor; p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_INNERCORONA_COLOR, nightMoonInnerCoronaColor); float nightMoonInnerCoronaScale(1.0f + 1000.0f * p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_INNERCORONA_SCALE)); Vec4 nsMoonInnerCoronaColorScale(nightMoonInnerCoronaColor, nightMoonInnerCoronaScale); static CCryNameR Param12Name("SkyDome_NightMoonInnerCoronaColorScale"); ef->FXSetPSFloat(Param12Name, &nsMoonInnerCoronaColorScale, 1); Vec3 nightMoonOuterCoronaColor; p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_OUTERCORONA_COLOR, nightMoonOuterCoronaColor); float nightMoonOuterCoronaScale(1.0f + 1000.0f * p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_OUTERCORONA_SCALE)); Vec4 nsMoonOuterCoronaColorScale(nightMoonOuterCoronaColor, nightMoonOuterCoronaScale); static CCryNameR Param13Name("SkyDome_NightMoonOuterCoronaColorScale"); ef->FXSetPSFloat(Param13Name, &nsMoonOuterCoronaColorScale, 1); } HRESULT hr(S_OK); // commit all render changes // David S. workaround for Mali driver's bug if (isNotZPass && (gRenDev->GetFeatures() & RFT_HW_ARM_MALI)) { uint32 newState = rd->m_RP.m_CurState; newState |= GS_STENCIL; rd->FX_SetStencilState( STENC_FUNC(FSS_STENCFUNC_ALWAYS) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP), 1, 0xFFFFFFFF, 0xFFFFFFFF); rd->FX_SetState(newState); } rd->FX_Commit(); // set vertex declaration and streams of sky dome CRenderMesh* pSkyDomeMesh = static_cast(m_pRenderParams->m_pSkyDomeMesh.get()); hr = rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F); if (!FAILED(hr)) { // set vertex and index buffer pSkyDomeMesh->CheckUpdate(0); size_t vbOffset(0); size_t ibOffset(0); D3DBuffer* pVB = rd->m_DevBufMan.GetD3D(pSkyDomeMesh->GetVBStream(VSF_GENERAL), &vbOffset); D3DBuffer* pIB = rd->m_DevBufMan.GetD3D(pSkyDomeMesh->GetIBStream(), &ibOffset); assert(pVB); assert(pIB); if (!pVB || !pIB) { return false; } hr = rd->FX_SetVStream(0, pVB, vbOffset, pSkyDomeMesh->GetStreamStride(VSF_GENERAL)); hr = rd->FX_SetIStream(pIB, ibOffset, (sizeof(vtx_idx) == 2 ? Index16 : Index32)); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); // draw sky dome rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, pSkyDomeMesh->GetNumVerts(), 0, pSkyDomeMesh->GetNumInds()); } ef->FXEndPass(); ef->FXEnd(); if (m_pStars) { m_pStars->Render(m_moonTexId > 0 ? true : false); } rd->FX_PopVP(); gcpRendD3D->FX_ResetPipe(); return true; } void CStars::Render(bool bUseMoon) { CD3D9Renderer* rd(gcpRendD3D); I3DEngine* p3DEngine(gEnv->p3DEngine); float starIntensity(p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_STAR_INTENSITY)); if (m_pStarMesh && m_pShader && rd->m_RP.m_nPassGroupID == EFSLIST_GENERAL && (rd->m_RP.m_nBatchFilter & FB_GENERAL) && starIntensity > 1e-3f) { ////////////////////////////////////////////////////////////////////////// // set shader static CCryNameTSCRC shaderTech("Stars"); m_pShader->FXSetTechnique(shaderTech); uint32 nPasses(0); m_pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES); if (!nPasses) { return; } m_pShader->FXBeginPass(0); ////////////////////////////////////////////////////////////////////////// // setup params int vpX(0), vpY(0), vpWidth(0), vpHeight(0); rd->GetViewport(&vpX, &vpY, &vpWidth, &vpHeight); const float size = 5.0f * min(1.f, min(vpWidth / 1280.f, vpHeight / 720.f)); float flickerTime(gEnv->pTimer->GetCurrTime()); static CCryNameR vspnStarSize("StarSize"); Vec4 paramStarSize(size / (float)vpWidth, size / (float)vpHeight, 0, flickerTime * 0.5f); m_pShader->FXSetVSFloat(vspnStarSize, ¶mStarSize, 1); static CCryNameR pspnStarIntensity("StarIntensity"); Vec4 paramStarIntensity(starIntensity* min(1.f, size), 0, 0, 0); m_pShader->FXSetPSFloat(pspnStarIntensity, ¶mStarIntensity, 1); CREHDRSky::SetCommonMoonParams(m_pShader, bUseMoon); ////////////////////////////////////////////////////////////////////////// // commit & draw int32 nRenderState = GS_BLSRC_ONE | GS_BLDST_ONE; rd->FX_SetState(nRenderState); rd->FX_Commit(); if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3S_C4B_T2S))) { size_t offset(0); //void* pVB(m_pStarVB->GetStream(VSF_GENERAL, &offset)); //rd->FX_SetVStream(0, pVB, offset, m_VertexSize[m_pStarVB->m_vertexformat]); CRenderMesh* pStarMesh = static_cast(m_pStarMesh.get()); pStarMesh->CheckUpdate(0); D3DBuffer* pVB = rd->m_DevBufMan.GetD3D(pStarMesh->GetVBStream(VSF_GENERAL), &offset); rd->FX_SetVStream(0, pVB, offset, pStarMesh->GetStreamStride(VSF_GENERAL)); rd->FX_SetIStream(0, 0, Index16); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); rd->FX_DrawPrimitive(eptTriangleList, 0, 6 * m_numStars); } m_pShader->FXEndPass(); m_pShader->FXEnd(); } } bool CREFogVolume::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd(gcpRendD3D); #if !defined(_RELEASE) if (ef->m_eShaderType != eST_PostProcess) { CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for fog volume"); return false; } #endif // shader technique is multi-pass but it doesn't need to be rendered twice. if (rd->m_RP.m_nNumRendPasses > 1) { return false; } // rendered to volume texture if (CD3D9Renderer::CV_r_VolumetricFog != 0 && rd->m_RP.m_nPassGroupID == EFSLIST_FOG_VOLUME) { // calculate depth bounds of FogVolume. // reusing light depth bounds code from CDeferredShading::GetLightDepthBounds(). // This is not optimal for a box. Matrix34 temp = m_matWSInv.GetInverted(); AABB aabbInObj(1.0f); AABB aabbInWS = AABB::CreateTransformedAABB(temp, aabbInObj); float fRadius = aabbInWS.GetRadius(); Vec3 cameraFront = rd->GetViewParameters().vZ; cameraFront.Normalize(); Vec3 pBounds = cameraFront * fRadius; Vec3 pMax = m_center - pBounds; Vec3 pMin = m_center + pBounds; float fMinW, fMaxW; fMaxW = rd->GetViewParameters().WorldToCamZ(pMax); fMinW = rd->GetViewParameters().WorldToCamZ(pMin); fMinW = max(-fMinW, 0.000001f); fMaxW = max(-fMaxW, 0.000001f); // don't render when FogVolume is out of volume texture. Vec3 volumetricFogRaymarchEnd; gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG2_CTRL_PARAMS, volumetricFogRaymarchEnd); if (fMinW > volumetricFogRaymarchEnd.x) { return false; } PROFILE_LABEL_SCOPE("FOG_VOLUME"); // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (0 == nPasses) { assert(0); return(false); } uint64 nFlagsShaderRTSave = rd->m_RP.m_FlagsShader_RT; rd->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE0]; if (m_affectsThisAreaOnly) { rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0]; } // set volumetric fog injection pass ef->FXBeginPass(1); if (m_viewerInsideVolume) { rd->SetCullMode(R_CULL_FRONT); } else { rd->SetCullMode(R_CULL_BACK); } rd->FX_SetState(GS_BLSRC_ONE | GS_BLDST_ONE | GS_NODEPTHTEST); // set vs constants static CCryNameR invObjSpaceMatrixName("invObjSpaceMatrix"); ef->FXSetVSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matWSInv.m00, 3); ef->FXSetPSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matWSInv.m00, 3); const Vec4 cEyePosVec(m_eyePosInWS, !m_viewerInsideVolume ? 1 : 0); static CCryNameR eyePosInWSName("eyePosInWS"); ef->FXSetVSFloat(eyePosInWSName, &cEyePosVec, 1); const Vec4 cNearCutoffVec(m_nearCutoff, m_nearCutoff, m_nearCutoff, m_nearCutoff); static CCryNameR nearCutoffName("nearCutoff"); ef->FXSetVSFloat(nearCutoffName, &cNearCutoffVec, 1); // set ps constants const Vec4 cFogColVec(m_fogColor.r, m_fogColor.g, m_fogColor.b, 0); static CCryNameR fogColorName("fogColor"); ef->FXSetPSFloat(fogColorName, &cFogColVec, 1); float globalDensity = m_globalDensity * 0.1f;// scale density to volumetric fog. const Vec4 cGlobalDensityVec(globalDensity, 1.44269502f * globalDensity, m_noiseElapsedTime, 0); static CCryNameR globalDensityName("globalDensity"); ef->FXSetPSFloat(globalDensityName, &cGlobalDensityVec, 1); const Vec4 cDensityOffsetVec(m_densityOffset, m_densityOffset, m_densityOffset, m_densityOffset); static CCryNameR densityOffsetName("densityOffset"); ef->FXSetPSFloat(densityOffsetName, &cDensityOffsetVec, 1); uint32 nData = m_stencilRef + 1;// first ref value is reserved, see CDeferredShading::PrepareClipVolumeData function. const Vec4 cHeigthFallOffBasePointVec(m_heightFallOffBasePoint, *alias_cast(&nData)); static CCryNameR heightFallOffBasePointName("heightFallOffBasePoint"); ef->FXSetPSFloat(heightFallOffBasePointName, &cHeigthFallOffBasePointVec, 1); const Vec4 cHeightFallOffDirScaledVec(m_heightFallOffDirScaled * 0.015625f, 0); // scale fall off ramp to volumetric fog. static CCryNameR heightFallOffDirScaledName("heightFallOffDirScaled"); ef->FXSetPSFloat(heightFallOffDirScaledName, &cHeightFallOffDirScaledVec, 1); const Vec4 cOutsideSoftEdgesLerpVec(m_softEdgesLerp.x, m_softEdgesLerp.y, 0, 0); static CCryNameR outsideSoftEdgesLerpName("outsideSoftEdgesLerp"); ef->FXSetPSFloat(outsideSoftEdgesLerpName, &cOutsideSoftEdgesLerpVec, 1); const Vec4 cEyePosInWSVec(m_eyePosInWS, 0); ef->FXSetPSFloat(eyePosInWSName, &cEyePosInWSVec, 1); const Vec4 cEyePosInOSVec(m_eyePosInOS, 0); static CCryNameR eyePosInOSName("eyePosInOS"); ef->FXSetPSFloat(eyePosInOSName, &cEyePosInOSVec, 1); const Vec4 cEyePosInOSx2Vec(2.0f * m_eyePosInOS, 0); static CCryNameR eyePosInOSx2Name("eyePosInOSx2"); ef->FXSetPSFloat(eyePosInOSx2Name, &cEyePosInOSx2Vec, 1); float softEdgeLerp = (m_softEdgesLerp.x > 0.0f) ? m_softEdgesLerp.x : 0.0001f; const Vec4 cFogVolumePos(m_center, 1.0f / softEdgeLerp); static CCryNameR fogVolumePosName("fogVolumePos"); ef->FXSetPSFloat(fogVolumePosName, &cFogVolumePos, 1); float rampDist = m_rampParams.y - m_rampParams.x; rampDist = rampDist < 0.1f ? 0.1f : rampDist; float invRampDist = 1.0f / rampDist; const Vec4 cRampParams(invRampDist, -m_rampParams.x* invRampDist, m_rampParams.z, -m_rampParams.z + 1.0f); static CCryNameR rampParamsName("rampParams"); ef->FXSetPSFloat(rampParamsName, &cRampParams, 1); const float normalizeFactor = (1.0f / (1.0f + 0.5f)); const Vec4 cWindOffset(m_windOffset.x, m_windOffset.y, m_windOffset.z, m_noiseScale* normalizeFactor); static CCryNameR windOffsetName("windOffset"); ef->FXSetPSFloat(windOffsetName, &cWindOffset, 1); const Vec4 cNoiseFreq(m_noiseFreq.x, m_noiseFreq.y, m_noiseFreq.z, m_noiseOffset); static CCryNameR noiseFreqName("noiseFreq"); ef->FXSetPSFloat(noiseFreqName, &cNoiseFreq, 1); // find minimum and maximum affected slices const int slicesPerInstance = 28; const int depthMaxCount = CTexture::s_ptexVolumetricFogDensity->GetDepth(); static CCryNameR sliceBounds("sliceBounds"); Vec4 vSliceBounds(fMinW, fMaxW, slicesPerInstance, 0.0f); ef->FXSetGSFloat(sliceBounds, &vSliceBounds, 1); // commit all render changes rd->FX_Commit(); // set vertex declaration and streams of skydome if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F))) { // define bounding box geometry const uint32 c_numBBVertices(8); SVF_P3F_C4B_T2F bbVertices[ c_numBBVertices ] = { { Vec3(m_localAABB.min.x, m_localAABB.min.y, m_localAABB.min.z) }, { Vec3(m_localAABB.min.x, m_localAABB.max.y, m_localAABB.min.z) }, { Vec3(m_localAABB.max.x, m_localAABB.max.y, m_localAABB.min.z) }, { Vec3(m_localAABB.max.x, m_localAABB.min.y, m_localAABB.min.z) }, { Vec3(m_localAABB.min.x, m_localAABB.min.y, m_localAABB.max.z) }, { Vec3(m_localAABB.min.x, m_localAABB.max.y, m_localAABB.max.z) }, { Vec3(m_localAABB.max.x, m_localAABB.max.y, m_localAABB.max.z) }, { Vec3(m_localAABB.max.x, m_localAABB.min.y, m_localAABB.max.z) } }; const uint32 c_numBBIndices(36); static const uint16 bbIndices[ c_numBBIndices ] = { 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 3, 2, 6, 3, 6, 7, 4, 5, 1, 4, 1, 0, 1, 5, 6, 1, 6, 2, 4, 0, 3, 4, 3, 7 }; // copy vertices into dynamic VB TempDynVB::CreateFillAndBind(bbVertices, c_numBBVertices, 0); // copy indices into dynamic IB TempDynIB16::CreateFillAndBind(bbIndices, c_numBBIndices); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); // use instanced draw for rendering multiple slices at once int instanceCount = (depthMaxCount / slicesPerInstance) + ((depthMaxCount % slicesPerInstance) != 0 ? 1 : 0); rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, instanceCount, 0, c_numBBIndices, true); } ef->FXEndPass(); ef->FXEnd(); rd->m_RP.m_FlagsShader_RT = nFlagsShaderRTSave; return true; } PROFILE_LABEL_SCOPE("FOG_VOLUME"); // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (0 == nPasses) { assert(0); return(false); } ef->FXBeginPass(0); if (m_viewerInsideVolume) { rd->SetCullMode(R_CULL_FRONT); int nState = GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; nState |= m_nearCutoff ? 0 : GS_NODEPTHTEST; rd->FX_SetState(nState); } else { rd->SetCullMode(R_CULL_BACK); rd->FX_SetState(GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); } // set vs constants static CCryNameR invObjSpaceMatrixName("invObjSpaceMatrix"); ef->FXSetVSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matWSInv.m00, 3); const Vec4 cEyePosVec(m_eyePosInWS, !m_viewerInsideVolume ? 1 : 0); static CCryNameR eyePosInWSName("eyePosInWS"); ef->FXSetVSFloat(eyePosInWSName, &cEyePosVec, 1); const Vec4 cEyePosInOSVec(m_eyePosInOS, 0); static CCryNameR eyePosInOSName("eyePosInOS"); ef->FXSetVSFloat(eyePosInOSName, &cEyePosInOSVec, 1); const Vec4 cNearCutoffVec(m_nearCutoff, m_nearCutoff, m_nearCutoff, m_nearCutoff); static CCryNameR nearCutoffName("nearCutoff"); ef->FXSetVSFloat(nearCutoffName, &cNearCutoffVec, 1); // set ps constants const Vec4 cFogColVec(m_fogColor.r, m_fogColor.g, m_fogColor.b, 0); static CCryNameR fogColorName("fogColor"); ef->FXSetPSFloat(fogColorName, &cFogColVec, 1); const Vec4 cGlobalDensityVec(m_globalDensity, 1.44269502f * m_globalDensity, 0, 0); static CCryNameR globalDensityName("globalDensity"); ef->FXSetPSFloat(globalDensityName, &cGlobalDensityVec, 1); const Vec4 cDensityOffsetVec(m_densityOffset, m_densityOffset, m_densityOffset, m_densityOffset); static CCryNameR densityOffsetName("densityOffset"); ef->FXSetPSFloat(densityOffsetName, &cDensityOffsetVec, 1); const Vec4 cHeigthFallOffBasePointVec(m_heightFallOffBasePoint, 0); static CCryNameR heightFallOffBasePointName("heightFallOffBasePoint"); ef->FXSetPSFloat(heightFallOffBasePointName, &cHeigthFallOffBasePointVec, 1); const Vec4 cHeightFallOffDirScaledVec(m_heightFallOffDirScaled, 0); static CCryNameR heightFallOffDirScaledName("heightFallOffDirScaled"); ef->FXSetPSFloat(heightFallOffDirScaledName, &cHeightFallOffDirScaledVec, 1); const Vec4 cOutsideSoftEdgesLerpVec(m_softEdgesLerp.x, m_softEdgesLerp.y, 0, 0); static CCryNameR outsideSoftEdgesLerpName("outsideSoftEdgesLerp"); ef->FXSetPSFloat(outsideSoftEdgesLerpName, &cOutsideSoftEdgesLerpVec, 1); const Vec4 cEyePosInWSVec(m_eyePosInWS, 0); ef->FXSetPSFloat(eyePosInWSName, &cEyePosInWSVec, 1); const Vec4 cEyePosInOSx2Vec(2.0f * m_eyePosInOS, 0); static CCryNameR eyePosInOSx2Name("eyePosInOSx2"); ef->FXSetPSFloat(eyePosInOSx2Name, &cEyePosInOSx2Vec, 1); // commit all render changes rd->FX_Commit(); // set vertex declaration and streams of skydome if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F))) { // define bounding box geometry const uint32 c_numBBVertices(8); SVF_P3F_C4B_T2F bbVertices[ c_numBBVertices ] = { { Vec3(m_localAABB.min.x, m_localAABB.min.y, m_localAABB.min.z) }, { Vec3(m_localAABB.min.x, m_localAABB.max.y, m_localAABB.min.z) }, { Vec3(m_localAABB.max.x, m_localAABB.max.y, m_localAABB.min.z) }, { Vec3(m_localAABB.max.x, m_localAABB.min.y, m_localAABB.min.z) }, { Vec3(m_localAABB.min.x, m_localAABB.min.y, m_localAABB.max.z) }, { Vec3(m_localAABB.min.x, m_localAABB.max.y, m_localAABB.max.z) }, { Vec3(m_localAABB.max.x, m_localAABB.max.y, m_localAABB.max.z) }, { Vec3(m_localAABB.max.x, m_localAABB.min.y, m_localAABB.max.z) } }; const uint32 c_numBBIndices(36); static const uint16 bbIndices[ c_numBBIndices ] = { 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 3, 2, 6, 3, 6, 7, 4, 5, 1, 4, 1, 0, 1, 5, 6, 1, 6, 2, 4, 0, 3, 4, 3, 7 }; // copy vertices into dynamic VB TempDynVB::CreateFillAndBind(bbVertices, c_numBBVertices, 0); // copy indices into dynamic IB TempDynIB16::CreateFillAndBind(bbIndices, c_numBBIndices); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); // draw skydome rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, c_numBBVertices, 0, c_numBBIndices); } ef->FXEndPass(); ef->FXEnd(); return(true); } bool CREVolumeObject::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd(gcpRendD3D); I3DEngine* p3DEngine(gEnv->p3DEngine); uint32 nFlagsPS2 = rd->m_RP.m_PersFlags2; rd->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF | RBPF2_COMMIT_CM); // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (!nPasses) { return false; } ef->FXBeginPass(0); if (m_nearPlaneIntersectsVolume) { rd->SetCullMode(R_CULL_FRONT); rd->FX_SetState(GS_COLMASK_RGB | GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); } else { rd->SetCullMode(R_CULL_BACK); rd->FX_SetState(GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); } // set vs constants static CCryNameR invObjSpaceMatrixName("invObjSpaceMatrix"); ef->FXSetVSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matInv.m00, 3); const Vec4 cEyePosVec(m_eyePosInWS, 0); static CCryNameR eyePosInWSName("eyePosInWS"); ef->FXSetVSFloat(eyePosInWSName, &cEyePosVec, 1); const Vec4 cViewerOutsideVec(!m_viewerInsideVolume ? 1 : 0, m_nearPlaneIntersectsVolume ? 1 : 0, 0, 0); static CCryNameR viewerIsOutsideName("viewerIsOutside"); ef->FXSetVSFloat(viewerIsOutsideName, &cViewerOutsideVec, 1); const Vec4 cEyePosInOSVec(m_eyePosInOS, 0); static CCryNameR eyePosInOSName("eyePosInOS"); ef->FXSetVSFloat(eyePosInOSName, &cEyePosInOSVec, 1); // set ps constants const Vec4 cEyePosInWSVec(m_eyePosInWS, 0); ef->FXSetPSFloat(eyePosInWSName, &cEyePosInWSVec, 1); ColorF specColor(1, 1, 1, 1); ColorF diffColor(1, 1, 1, 1); CShaderResources* pRes(rd->m_RP.m_pShaderResources); if (pRes && pRes->HasLMConstants()) { specColor = pRes->GetColorValue(EFTT_SPECULAR); diffColor = pRes->GetColorValue(EFTT_DIFFUSE); } Vec3 cloudShadingMultipliers; p3DEngine->GetGlobalParameter(E3DPARAM_CLOUDSHADING_MULTIPLIERS, cloudShadingMultipliers); Vec3 brightColor(p3DEngine->GetSunColor() * cloudShadingMultipliers.x); brightColor = brightColor.CompMul(Vec3(specColor.r, specColor.g, specColor.b)); { static CCryNameR darkColorName("darkColor"); const Vec4 data(0, 0, 0, m_alpha); ef->FXSetPSFloat(darkColorName, &data, 1); } { static CCryNameR brightColorName("brightColor"); const Vec4 data(brightColor, m_alpha); ef->FXSetPSFloat(brightColorName, &data, 1); } const Vec4 cVolumeTraceStartPlane(m_volumeTraceStartPlane.n, m_volumeTraceStartPlane.d); static CCryNameR volumeTraceStartPlaneName("volumeTraceStartPlane"); ef->FXSetPSFloat(volumeTraceStartPlaneName, &cVolumeTraceStartPlane, 1); const Vec4 cScaleConsts(m_scale, 0, 0, 0); static CCryNameR scaleConstsName("scaleConsts"); ef->FXSetPSFloat(scaleConstsName, &cScaleConsts, 1); // TODO: optimize shader and remove need to pass inv obj space matrix ef->FXSetPSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matInv.m00, 3); // commit all render changes rd->FX_Commit(); // set vertex declaration and streams if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F))) { CRenderMesh* pHullMesh = static_cast(m_pHullMesh.get()); // set vertex and index buffer pHullMesh->CheckUpdate(0); size_t vbOffset(0); size_t ibOffset(0); D3DBuffer* pVB = rd->m_DevBufMan.GetD3D(pHullMesh->GetVBStream(VSF_GENERAL), &vbOffset); D3DBuffer* pIB = rd->m_DevBufMan.GetD3D(pHullMesh->GetIBStream(), &ibOffset); assert(pVB); assert(pIB); if (!pVB || !pIB) { return false; } HRESULT hr(S_OK); hr = rd->FX_SetVStream(0, pVB, vbOffset, pHullMesh->GetStreamStride(VSF_GENERAL)); hr = rd->FX_SetIStream(pIB, ibOffset, (sizeof(vtx_idx) == 2 ? Index16 : Index32)); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); rd->FX_DrawIndexedPrimitive(pHullMesh->GetPrimitiveType(), 0, 0, pHullMesh->GetNumVerts(), 0, pHullMesh->GetNumInds()); } ef->FXEndPass(); ef->FXEnd(); rd->FX_ResetPipe(); rd->m_RP.m_PersFlags2 = nFlagsPS2; return true; } #if !defined(EXCLUDE_DOCUMENTATION_PURPOSE) bool CREPrismObject::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd(gcpRendD3D); // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (!nPasses) { return false; } ef->FXBeginPass(0); // commit all render changes // rd->FX_Commit(); static SVF_P3F_C4B_T2F pScreenQuad[] = { { Vec3(0, 0, 0), { {0} }, Vec2(0, 0) }, { Vec3(0, 1, 0), { {0} }, Vec2(0, 1) }, { Vec3(1, 0, 0), { {0} }, Vec2(1, 0) }, { Vec3(1, 1, 0), { {0} }, Vec2(1, 1) }, }; pScreenQuad[0].xyz = Vec3(0, 0, 0); pScreenQuad[1].xyz = Vec3(0, 1, 0); pScreenQuad[2].xyz = Vec3(1, 0, 0); pScreenQuad[3].xyz = Vec3(1, 1, 0); CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F); gcpRendD3D->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip); ef->FXEndPass(); ef->FXEnd(); return true; } #endif // EXCLUDE_DOCUMENTATION_PURPOSE bool CREWaterVolume::mfDraw(CShader* ef, SShaderPass* sfm) { assert(m_pParams); if (!m_pParams) { return false; } CD3D9Renderer* rd(gcpRendD3D); IF (ef->m_eShaderType != eST_Water, 0) { #if !defined(_RELEASE) // CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for water / water fog volume"); #endif return false; } //@NOTE: CV_r_watercaustics will be removed when the infinite ocean component feature toggle is removed. bool bCaustics = CRenderer::CV_r_watercaustics && CRenderer::CV_r_watervolumecaustics && m_pParams->m_caustics && (-m_pParams->m_fogPlane.d >= 1.0f); // unfortunately packing to RG8 limits us to heights over 1 meter, so we just disable if volume goes below. // Don't render caustics pass unless needed. if ((rd->m_RP.m_nBatchFilter & FB_WATER_CAUSTIC) && !bCaustics) { return false; } uint64 nFlagsShaderRTSave = gcpRendD3D->m_RP.m_FlagsShader_RT; rd->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE5]); const bool renderFogShadowWater = (CRenderer::CV_r_FogShadowsWater > 0) && (m_pParams->m_fogShadowing > 0.01f); Vec4 volFogShadowRange(0, 0, clamp_tpl(m_pParams->m_fogShadowing, 0.0f, 1.0f), 1.0f - clamp_tpl(m_pParams->m_fogShadowing, 0.0f, 1.0f)); #if defined(VOLUMETRIC_FOG_SHADOWS) const bool renderFogShadow = gcpRendD3D->m_bVolFogShadowsEnabled; { Vec3 volFogShadowRangeP; gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG_SHADOW_RANGE, volFogShadowRangeP); volFogShadowRangeP.x = clamp_tpl(volFogShadowRangeP.x, 0.01f, 1.0f); volFogShadowRange.x = volFogShadowRangeP.x; volFogShadowRange.y = volFogShadowRangeP.y; } if (renderFogShadow) { gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE5]; } if (!renderFogShadowWater) // set up forward shadows in case they will not be set up below { rd->FX_SetupShadowsForTransp(); } #endif if (renderFogShadowWater) { rd->FX_SetupShadowsForTransp(); gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0]; } Matrix44A origMatProj; Matrix44A origMatView; origMatProj.SetIdentity(); origMatView.SetIdentity(); if (!m_drawWaterSurface && m_pParams->m_viewerInsideVolume) { // set projection matrix for full screen quad origMatProj = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj; Matrix44A* m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj; mathMatrixOrthoOffCenterLH(m, -1, 1, -1, 1, -1, 1); if (SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID] <= 0) { const SRenderTileInfo* rti = rd->GetRenderTileInfo(); if (rti->nGridSizeX > 1.f || rti->nGridSizeY > 1.f) { // shift and scale viewport m->m00 *= rti->nGridSizeX; m->m11 *= rti->nGridSizeY; m->m30 = -((rti->nGridSizeX - 1.f) - rti->nPosX * 2.0f); m->m31 = ((rti->nGridSizeY - 1.f) - rti->nPosY * 2.0f); } } // set view matrix to identity origMatView = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView; rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView.SetIdentity(); } // render uint32 nPasses(0); ef->FXBegin(&nPasses, 0); if (0 == nPasses) { // reset matrices rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView = origMatView; rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj = origMatProj; return false; } ef->FXBeginPass(0); // set ps constants if (!m_drawWaterSurface || m_drawFastPath && !m_pParams->m_viewerInsideVolume) { if (!m_pOceanParams) { // fog color & density const Vec3 col = m_pParams->m_fogColorAffectedBySun ? m_pParams->m_fogColor.CompMul(gEnv->p3DEngine->GetSunColor()) : m_pParams->m_fogColor; const Vec4 fogColorDensity(col, 1.44269502f * m_pParams->m_fogDensity); // log2(e) = 1.44269502 static CCryNameR Param1Name("cFogColorDensity"); ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1); } else { // fog color & density Vec4 fogColorDensity(m_pOceanParams->m_fogColor.CompMul(gEnv->p3DEngine->GetSunColor()), 1.44269502f * m_pOceanParams->m_fogDensity); // log2(e) = 1.44269502 static CCryNameR Param1Name("cFogColorDensity"); ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1); // fog color shallow & water level Vec4 fogColorShallowWaterLevel(m_pOceanParams->m_fogColorShallow.CompMul(gEnv->p3DEngine->GetSunColor()), -m_pParams->m_fogPlane.d); static CCryNameR Param2Name("cFogColorShallowWaterLevel"); ef->FXSetPSFloat(Param2Name, &fogColorShallowWaterLevel, 1); if (m_pParams->m_viewerInsideVolume) { // under water in-scattering constant term = exp2( -fogDensity * ( waterLevel - cameraPos.z) ) float c(expf(-m_pOceanParams->m_fogDensity * (-m_pParams->m_fogPlane.d - rd->GetCamera().GetPosition().z))); Vec4 underWaterInScatterConst(c, 0, 0, 0); static CCryNameR Param3Name("cUnderWaterInScatterConst"); ef->FXSetPSFloat(Param3Name, &underWaterInScatterConst, 1); } } Vec4 fogPlane(m_pParams->m_fogPlane.n.x, m_pParams->m_fogPlane.n.y, m_pParams->m_fogPlane.n.z, m_pParams->m_fogPlane.d); static CCryNameR Param4Name("cFogPlane"); ef->FXSetPSFloat(Param4Name, &fogPlane, 1); if (m_pParams->m_viewerInsideVolume) { Vec4 perpDist(m_pParams->m_fogPlane | rd->GetViewParameters().vOrigin, 0, 0, 0); static CCryNameR Param5Name("cPerpDist"); ef->FXSetPSFloat(Param5Name, &perpDist, 1); } } // Disable fog when inside volume or when not using fast path - could assign custom RT flag for this instead if (m_drawFastPath && m_pParams->m_viewerInsideVolume || !m_drawFastPath && m_drawWaterSurface) { // fog color & density const Vec4 fogColorDensity(0, 0, 0, 0); static CCryNameR Param1Name("cFogColorDensity"); ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1); } { static CCryNameR pszParamBBoxMin("vBBoxMin"); static CCryNameR pszParamBBoxMax("vBBoxMax"); const Vec4 vBBoxMin(m_pParams->m_WSBBox.min, 1.0f); const Vec4 vBBoxMax(m_pParams->m_WSBBox.max, 1.0f); ef->FXSetPSFloat(pszParamBBoxMin, &vBBoxMin, 1); ef->FXSetPSFloat(pszParamBBoxMax, &vBBoxMax, 1); } // set vs constants Vec4 viewerColorToWaterPlane(m_pParams->m_viewerCloseToWaterPlane && m_pParams->m_viewerCloseToWaterVolume ? 0.0f : 1.0f, m_pParams->m_viewerCloseToWaterVolume ? 2.0f * 2.0f : 0.0f, 0.0f, 0.0f); static CCryNameR Param6Name("cViewerColorToWaterPlane"); ef->FXSetVSFloat(Param6Name, &viewerColorToWaterPlane, 1); if (bCaustics) { Vec4 pCausticsParams = Vec4(0.0f /* Not used */, m_pParams->m_causticIntensity, m_pParams->m_causticTiling, m_pParams->m_causticHeight); static CCryNameR m_pCausticParams("vCausticParams"); ef->FXSetPSFloat(m_pCausticParams, &pCausticsParams, 1); } static CCryNameR volFogShadowRangeN("volFogShadowRange"); ef->FXSetPSFloat(volFogShadowRangeN, &volFogShadowRange, 1); if (renderFogShadowWater) { //set world basis float maskRTWidth = float(rd->GetWidth()); float maskRTHeight = float(rd->GetHeight()); Vec4 vScreenScale(1.0f / maskRTWidth, 1.0f / maskRTHeight, 0.0f, 0.0f); Vec4r vWBasisX, vWBasisY, vWBasisZ, vCamPos; Vec4 vParamValue, vMag; CShadowUtils::ProjectScreenToWorldExpansionBasis(rd->m_IdentityMatrix, rd->GetCamera(), Vec2(rd->m_TemporalJitterClipSpace.x, rd->m_TemporalJitterClipSpace.y), maskRTWidth, maskRTHeight, vWBasisX, vWBasisY, vWBasisZ, vCamPos, true, NULL); Vec4 vWorldBasisX = vWBasisX; Vec4 vWorldBasisY = vWBasisY; Vec4 vWorldBasisZ = vWBasisZ; Vec4 vCameraPos = vCamPos; static CCryNameR m_pScreenScale("ScreenScale"); static CCryNameR m_pCamPos("vCamPos"); static CCryNameR m_pWBasisX("vWBasisX"); static CCryNameR m_pWBasisY("vWBasisY"); static CCryNameR m_pWBasisZ("vWBasisZ"); ef->FXSetPSFloat(m_pScreenScale, &vScreenScale, 1); ef->FXSetPSFloat(m_pCamPos, &vCameraPos, 1); ef->FXSetPSFloat(m_pWBasisX, &vWorldBasisX, 1); ef->FXSetPSFloat(m_pWBasisY, &vWorldBasisY, 1); ef->FXSetPSFloat(m_pWBasisZ, &vWorldBasisZ, 1); } #if defined(VOLUMETRIC_FOG_SHADOWS) if (renderFogShadow) { Vec3 volFogShadowDarkeningP; gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG_SHADOW_DARKENING, volFogShadowDarkeningP); Vec4 volFogShadowDarkening(volFogShadowDarkeningP, 0); static CCryNameR volFogShadowDarkeningN("volFogShadowDarkening"); ef->FXSetPSFloat(volFogShadowDarkeningN, &volFogShadowDarkening, 1); const float aSun = (1.0f - clamp_tpl(volFogShadowDarkeningP.y, 0.0f, 1.0f)) * 1.0f; const float bSun = 1.0f - aSun; const float aAmb = (1.0f - clamp_tpl(volFogShadowDarkeningP.z, 0.0f, 1.0f)) * 0.4f; const float bAmb = 1.0f - aAmb; Vec4 volFogShadowDarkeningSunAmb(aSun, bSun, aAmb, bAmb); static CCryNameR volFogShadowDarkeningSunAmbN("volFogShadowDarkeningSunAmb"); ef->FXSetPSFloat(volFogShadowDarkeningSunAmbN, &volFogShadowDarkeningSunAmb, 1); } #endif if (m_drawWaterSurface || !m_pParams->m_viewerInsideVolume) { // copy vertices into dynamic VB TempDynVB::CreateFillAndBind(m_pParams->m_pVertices, m_pParams->m_numVertices, 0); // copy indices into dynamic IB TempDynIB16::CreateFillAndBind(m_pParams->m_pIndices, m_pParams->m_numIndices); // set vertex declaration if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F))) { // commit all render changes rd->FX_Commit(); // draw eRenderPrimitiveType eType = eptTriangleList; if (CHWShader_D3D::s_pCurInstHS) { eType = ept3ControlPointPatchList; } rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); rd->FX_DrawIndexedPrimitive(eType, 0, 0, m_pParams->m_numVertices, 0, m_pParams->m_numIndices); } } else { // copy vertices into dynamic VB TempDynVB vb(gcpRendD3D); vb.Allocate(4); SVF_P3F_T3F* pVB = vb.Lock(); Vec3 coords[8]; rd->GetViewParameters().CalcVerts(coords); pVB[0].p.x = -1; pVB[0].p.y = 1; pVB[0].p.z = 0.5f; pVB[0].st = coords[5] - coords[1]; pVB[1].p.x = 1; pVB[1].p.y = 1; pVB[1].p.z = 0.5f; pVB[1].st = coords[4] - coords[0]; pVB[2].p.x = -1; pVB[2].p.y = -1; pVB[2].p.z = 0.5f; pVB[2].st = coords[6] - coords[2]; pVB[3].p.x = 1; pVB[3].p.y = -1; pVB[3].p.z = 0.5f; pVB[3].st = coords[7] - coords[3]; vb.Unlock(); vb.Bind(0); vb.Release(); // set vertex declaration if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_T3F))) { // commit all render changes rd->FX_Commit(); rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); rd->FX_DrawPrimitive(eptTriangleStrip, 0, 4); } // reset matrices rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView = origMatView; rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj = origMatProj; } ef->FXEndPass(); ef->FXEnd(); gcpRendD3D->m_RP.m_FlagsShader_RT = nFlagsShaderRTSave; return true; } void CREWaterOcean::Create(uint32 nVerticesCount, SVF_P3F_C4B_T2F* pVertices, uint32 nIndicesCount, const void* pIndices, uint32 nIndexSizeof) { if (!nVerticesCount || !pVertices || !nIndicesCount || !pIndices || (nIndexSizeof != 2 && nIndexSizeof != 4)) { return; } CD3D9Renderer* rd(gcpRendD3D); ReleaseOcean(); m_nVerticesCount = nVerticesCount; m_nIndicesCount = nIndicesCount; m_nIndexSizeof = nIndexSizeof; HRESULT hr(S_OK); ////////////////////////////////////////////////////////////////////////////////////////////////// // Create vertex buffer ////////////////////////////////////////////////////////////////////////////////////////////////// { D3DBuffer* pVertexBuffer = 0; D3D11_BUFFER_DESC BufDesc; SVF_P3F_C4B_T2F* dst = 0; uint32 size = nVerticesCount * sizeof(SVF_P3F_C4B_T2F); BufDesc.ByteWidth = size; BufDesc.Usage = D3D11_USAGE_DEFAULT; BufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; BufDesc.CPUAccessFlags = 0; BufDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA pInitData; pInitData.pSysMem = pVertices; pInitData.SysMemPitch = 0; pInitData.SysMemSlicePitch = 0; gcpRendD3D->m_DevMan.CreateD3D11Buffer(&BufDesc, &pInitData, &pVertexBuffer, "OceanMesh"); m_pVertices = pVertexBuffer; } ////////////////////////////////////////////////////////////////////////////////////////////////// // Create index buffer ////////////////////////////////////////////////////////////////////////////////////////////////// { D3DBuffer* pIndexBuffer = 0; const uint32 size = nIndicesCount * m_nIndexSizeof; D3D11_BUFFER_DESC BufDesc; BufDesc.ByteWidth = size; BufDesc.Usage = D3D11_USAGE_DEFAULT; BufDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; BufDesc.CPUAccessFlags = 0; BufDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA pInitData; pInitData.pSysMem = pIndices; pInitData.SysMemPitch = 0; pInitData.SysMemSlicePitch = 0; gcpRendD3D->m_DevMan.CreateD3D11Buffer(&BufDesc, &pInitData, &pIndexBuffer, "OceanMesh"); m_pIndices = pIndexBuffer; } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// void CREWaterOcean::FrameUpdate() { static bool bInitialize = true; if (bInitialize) { WaterSimMgr()->Create(1.0, 1.0f, 1.0f); bInitialize = false; } const int nGridSize = 64; // Update Vertex Texture if (!CTexture::IsTextureExist(CTexture::s_ptexWaterOcean)) { CTexture::s_ptexWaterOcean->Create2DTexture(nGridSize, nGridSize, 1, FT_DONT_RELEASE | FT_NOMIPS | FT_STAGE_UPLOAD, 0, eTF_R32G32B32A32F, eTF_R32G32B32A32F); } CTexture* pTexture = CTexture::s_ptexWaterOcean; // Copy data.. if (CTexture::IsTextureExist(pTexture)) { Vec4* pDispGrid = WaterSimMgr()->GetDisplaceGrid(); if (pDispGrid == nullptr) { return; } const auto oceanData = gEnv->p3DEngine->GetOceanAnimationParams(); const float fUpdateTime = 0.125f * gEnv->pTimer->GetCurrTime() * oceanData.fWavesSpeed; int nFrameID = gRenDev->GetFrameID(); void* pRawPtr = NULL; WaterSimMgr()->Update(nFrameID, fUpdateTime, false, pRawPtr); uint32 pitch = 4 * sizeof(f32) * nGridSize; uint32 width = nGridSize; uint32 height = nGridSize; STALL_PROFILER("update subresource") CDeviceTexture * pDevTex = pTexture->GetDevTexture(); pDevTex->UploadFromStagingResource(0, [=](void* pData, uint32 rowPitch, uint32 slicePitch) { cryMemcpy(pData, pDispGrid, 4 * width * height * sizeof(f32)); return true; }); } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// void CREWaterOcean::ReleaseOcean() { ID3D11Buffer* pVertices = (ID3D11Buffer*)m_pVertices; ID3D11Buffer* pIndices = (ID3D11Buffer*)m_pIndices; gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(pVertices); m_pVertices = nullptr; gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(pIndices); m_pIndices = nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// bool CREWaterOcean::mfDraw(CShader* ef, SShaderPass* sfm) { if (!m_nVerticesCount || !m_nIndicesCount || !m_pVertices || !m_pIndices) { return false; } CD3D9Renderer* rd(gcpRendD3D); if (CTexture::s_ptexWaterOcean) { CTexture::s_ptexWaterOcean->SetFilterMode(FILTER_LINEAR); CTexture::s_ptexWaterOcean->SetClampingMode(0, 0, 1); CTexture::s_ptexWaterOcean->UpdateTexStates(); } if (CTexture::s_ptexWaterRipplesDDN) { CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(true); CTexture::s_ptexWaterRipplesDDN->SetFilterMode(FILTER_LINEAR); CTexture::s_ptexWaterRipplesDDN->SetClampingMode(0, 0, 1); CTexture::s_ptexWaterRipplesDDN->UpdateTexStates(); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// uint64 nFlagsShaderRTprev = rd->m_RP.m_FlagsShader_RT; uint32 nFlagsPF2prev = rd->m_RP.m_PersFlags2; rd->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF | RBPF2_COMMIT_CM); // render uint32 nPasses(0); // set streams HRESULT hr(S_OK); STexStageInfo pPrevTexState0 = CTexture::s_TexStages[0]; STexStageInfo pPrevTexState1 = CTexture::s_TexStages[1]; STexState pState(FILTER_BILINEAR, false); const int texStateID(CTexture::GetTexState(pState)); N3DEngineCommon::SOceanInfo& OceanInfo = gRenDev->m_p3DEngineCommon.m_OceanInfo; Vec4& pParams = OceanInfo.m_vMeshParams; uint32 nPrevStateOr = rd->m_RP.m_StateOr; uint32 nPrevStateAnd = rd->m_RP.m_StateAnd; ef->FXSetTechnique("Water"); ef->FXBegin(&nPasses, 0); if (0 == nPasses) { return false; } if (gRenDev->GetViewParameters().vOrigin.z > OceanInfo.m_fWaterLevel) { rd->m_RP.m_StateAnd |= GS_DEPTHFUNC_MASK; rd->m_RP.m_StateOr |= GS_DEPTHWRITE | GS_DEPTHFUNC_LEQUAL; } ef->FXBeginPass(0); if (CTexture::s_ptexWaterOcean) { CTexture::s_ptexWaterOcean->SetVertexTexture(true); CTexture::s_ptexWaterOcean->Apply(0, texStateID); CTexture::s_ptexWaterOcean->SetVertexTexture(false); } if (CTexture::s_ptexWaterRipplesDDN) { CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(true); CTexture::s_ptexWaterRipplesDDN->Apply(1, texStateID); CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(false); } hr = rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F); if (!FAILED(hr)) { // commit all render changes rd->FX_Commit(); hr = rd->FX_SetVStream(0, m_pVertices, 0, sizeof(SVF_P3F_C4B_T2F)); hr = rd->FX_SetIStream(m_pIndices, 0, (m_nIndexSizeof == 2 ? Index16 : Index32)); eRenderPrimitiveType eType = rd->m_bUseWaterTessHW ? eptTriangleList : eptTriangleStrip; #ifdef WATER_TESSELLATION_RENDERER if (CHWShader_D3D::s_pCurInstHS) { eType = ept3ControlPointPatchList; } #endif rd->GetPerInstanceConstantBufferPool().SetConstantBuffer(rd->m_RP.m_RIs[0][0]); rd->FX_DrawIndexedPrimitive(eType, 0, 0, m_nVerticesCount, 0, m_nIndicesCount); } ef->FXEndPass(); ef->FXEnd(); rd->m_RP.m_StateOr = nPrevStateOr; rd->m_RP.m_StateAnd = nPrevStateAnd; CTexture::s_TexStages[0] = pPrevTexState0; CTexture::s_TexStages[1] = pPrevTexState1; gcpRendD3D->FX_ResetPipe(); rd->m_RP.m_FlagsShader_RT = nFlagsShaderRTprev; rd->m_RP.m_PersFlags2 = nFlagsPF2prev; return true; } //========================================================================================= CREOcclusionQuery::~CREOcclusionQuery() { mfReset(); } void CREOcclusionQuery::mfReset() { ID3D11Query* pVizQuery = (ID3D11Query*)m_nOcclusionID; SAFE_RELEASE(pVizQuery); m_nOcclusionID = 0; m_nDrawFrame = 0; m_nCheckFrame = 0; m_nVisSamples = 0; m_bSucceeded = false; } uint32 CREOcclusionQuery::m_nQueriesPerFrameCounter = 0; uint32 CREOcclusionQuery::m_nReadResultNowCounter = 0; uint32 CREOcclusionQuery::m_nReadResultTryCounter = 0; bool CREOcclusionQuery::mfDraw(CShader* ef, SShaderPass* sfm) { PROFILE_FRAME(CREOcclusionQuery::mfDraw); CD3D9Renderer* r = gcpRendD3D; gRenDev->m_cEF.mfRefreshSystemShader("OcclusionTest", CShaderMan::s_ShaderOcclTest); CShader* pSh = CShaderMan::s_ShaderOcclTest; if (!pSh || pSh->m_HWTechniques.empty()) { return false; } if (!(r->m_Features & RFT_OCCLUSIONTEST)) { // If not supported m_nVisSamples = r->GetWidth() * r->GetHeight(); return true; } int w = r->GetWidth(); int h = r->GetHeight(); if (!m_nOcclusionID) { HRESULT hr; ID3D11Query* pVizQuery = NULL; D3D11_QUERY_DESC qdesc; qdesc.MiscFlags = 0; //D3D11_QUERY_MISC_PREDICATEHINT; qdesc.Query = D3D11_QUERY_OCCLUSION; hr = r->GetDevice().CreateQuery(&qdesc, &pVizQuery); if (pVizQuery) { m_nOcclusionID = (UINT_PTR)pVizQuery; } } int nFrame = r->GetFrameID(); if (!m_nDrawFrame) // only allow queries update, if finished already with previous query { // draw test box if (m_nOcclusionID) { D3DQuery* pVizQuery = (D3DQuery*)m_nOcclusionID; r->GetDeviceContext().Begin(pVizQuery); const t_arrDeferredMeshIndBuff& arrDeferredInds = r->GetDeferredUnitBoxIndexBuffer(); const t_arrDeferredMeshVertBuff& arrDeferredVerts = r->GetDeferredUnitBoxVertexBuffer(); //allocate vertices TempDynVB::CreateFillAndBind(&arrDeferredVerts[0], arrDeferredVerts.size(), 0); //allocate indices TempDynIB16::CreateFillAndBind(&arrDeferredInds[0], arrDeferredInds.size()); Matrix44A origMatView = r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView; Matrix34 mat; mat.SetIdentity(); mat.SetScale(m_vBoxMax - m_vBoxMin, m_vBoxMin); const Matrix44 cTransPosed = Matrix44(mat).GetTransposed(); r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView = cTransPosed * r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView; uint32 nPasses; pSh->FXSetTechnique("General"); pSh->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES); pSh->FXBeginPass(0); int nPersFlagsSave = r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags; int nObjFlagsSave = r->m_RP.m_ObjFlags; CRenderObject* pCurObjectSave = r->m_RP.m_pCurObject; CShader* pShaderSave = r->m_RP.m_pShader; SShaderTechnique* pCurTechniqueSave = r->m_RP.m_pCurTechnique; if (r->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F) == S_OK) { r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY; r->m_RP.m_pCurObject = r->m_RP.m_pIdendityRenderObject; r->m_RP.m_pShader = pSh; r->m_RP.m_pCurTechnique = pSh->m_HWTechniques[0]; r->FX_SetState(GS_COLMASK_NONE | GS_DEPTHFUNC_LEQUAL); r->SetCullMode(R_CULL_NONE); r->FX_Commit(); r->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, arrDeferredVerts.size(), 0, arrDeferredInds.size()); } pSh->FXEndPass(); pSh->FXEnd(); r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView = origMatView; r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags = nPersFlagsSave; r->m_RP.m_ObjFlags = nObjFlagsSave; r->m_RP.m_pCurObject = pCurObjectSave; r->m_RP.m_pShader = pShaderSave; r->m_RP.m_pCurTechnique = pCurTechniqueSave; r->GetDeviceContext().End(pVizQuery); CREOcclusionQuery::m_nQueriesPerFrameCounter++; m_nDrawFrame = 1; } m_bSucceeded = false; // m_nDrawFrame = nFrame; } return true; } bool CREOcclusionQuery::mfReadResult_Now() { int nFrame = gcpRendD3D->GetFrameID(); ID3D11Query* pVizQuery = (ID3D11Query*)m_nOcclusionID; if (pVizQuery) { HRESULT hRes = S_FALSE; while (hRes == S_FALSE) { hRes = gcpRendD3D->GetDeviceContext().GetData(pVizQuery, (void*) &m_nVisSamples, sizeof(uint64), 0); } if (hRes == S_OK) { m_nDrawFrame = 0; m_nCheckFrame = nFrame; } } m_nReadResultNowCounter++; m_bSucceeded = (m_nCheckFrame == nFrame); return m_bSucceeded; } bool CREOcclusionQuery::mfReadResult_Try(uint32 nDefaultNumSamples) { return gRenDev->m_pRT->RC_OC_ReadResult_Try(nDefaultNumSamples, this); } bool CREOcclusionQuery::RT_ReadResult_Try(uint32 nDefaultNumSamples) { PROFILE_FRAME(CREOcclusionQuery::mfReadResult_Try); int nFrame = gcpRendD3D->GetFrameID(); ID3D11Query* pVizQuery = (ID3D11Query*)m_nOcclusionID; if (pVizQuery) { HRESULT hRes = S_FALSE; hRes = gcpRendD3D->GetDeviceContext().GetData(pVizQuery, (void*) &m_nVisSamples, sizeof(uint64), D3D11_ASYNC_GETDATA_DONOTFLUSH); if (hRes == S_OK) { m_nDrawFrame = 0; m_nCheckFrame = nFrame; } } m_nReadResultTryCounter++; #ifdef DO_RENDERLOG if (!m_nVisSamples) { if (CRenderer::CV_r_log) { gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "OcclusionQuery: Water is not visible\n"); } } else { if (CRenderer::CV_r_log) { gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "OcclusionQuery: Water is visible (%d samples)\n", m_nVisSamples); } } #endif m_bSucceeded = (m_nCheckFrame == nFrame); return m_bSucceeded; } //=================================================================================== static float sInterpolate(float& pprev, float& prev, float& next, float& nnext, float ppweight, float pweight, float nweight, float nnweight) { return pprev * ppweight + prev * pweight + next * nweight + nnext * nnweight; } static float sSpline(float x) { float fX = fabsf(x); if (fX > 2.0f) { return 0; } if (fX > 1.0f) { return (2.0f - fX) * (2.0f - fX) * (2.0f - fX) / 6.0f; } return 2.0f / 3.0f - fX * fX + 0.5f * fX * fX * fX; } void CRenderMesh::DrawImmediately() { CD3D9Renderer* rd = gcpRendD3D; HRESULT hr = rd->FX_SetVertexDeclaration(0, _GetVertexFormat()); if (FAILED(hr)) { CRY_ASSERT(!"CRenderMesh::DrawImmediately failed"); return; } // set vertex and index buffer CheckUpdate(0); size_t vbOffset(0); size_t ibOffset(0); D3DBuffer* pVB = rd->m_DevBufMan.GetD3D(GetVBStream(VSF_GENERAL), &vbOffset); D3DBuffer* pIB = rd->m_DevBufMan.GetD3D(GetIBStream(), &ibOffset); assert(pVB); assert(pIB); if (!pVB || !pIB) { assert(!"CRenderMesh::DrawImmediately failed"); return; } hr = rd->FX_SetVStream(0, pVB, vbOffset, GetStreamStride(VSF_GENERAL)); hr = rd->FX_SetIStream(pIB, ibOffset, (sizeof(vtx_idx) == 2 ? Index16 : Index32)); // draw indexed mesh rd->FX_DrawIndexedPrimitive(GetPrimitiveType(), 0, 0, GetNumVerts(), 0, GetNumInds()); } //========================================================================================= bool CREParticle::mfPreDraw(SShaderPass* sl) { CD3D9Renderer* rd(gcpRendD3D); SRenderPipeline& rp(rd->m_RP); if (rp.m_RendNumVerts) { #if !defined(_RELEASE) if (!(rp.m_FlagsPerFlush & RBSI_EXTERN_VMEM_BUFFERS)) { __debugbreak(); } #endif assert(rp.m_pExternalVertexBuffer); assert(rp.m_pExternalIndexBuffer); // bind out external vertex/index buffer to use those directly, the client code has to set them up correctly rp.m_pExternalVertexBuffer->Bind(0, 0, rp.m_StreamStride); rp.m_pExternalIndexBuffer->Bind(0); // adjust the first index to render from as well as // other renderer stats rp.m_FirstIndex = rp.m_nExternalVertexBufferFirstIndex; rp.m_FirstVertex = rp.m_nExternalVertexBufferFirstVertex; rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_StreamStride * rp.m_RendNumVerts; rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_RendNumIndices * sizeof(uint16); // clear external video memory buffer flag rp.m_FlagsPerFlush &= ~RBSI_EXTERN_VMEM_BUFFERS; rp.m_nExternalVertexBufferFirstIndex = 0; rp.m_nExternalVertexBufferFirstVertex = 0; rp.m_pExternalVertexBuffer = NULL; rp.m_pExternalIndexBuffer = NULL; /* Confetti: David Srour * Following is a hack! For some reason, a stream remains in slot 1 which causes * a crash on iOS. * Either DX is smart enough not to use that slot or DX path cleans up slot 1 properly. * TODO: investigate further */ #ifdef CRY_USE_METAL rd->FX_SetVStream(1, NULL, 0, 0); #endif // Confetti end: David Srour } return true; } bool CREParticle::mfDraw(CShader* ef, SShaderPass* sl) { CD3D9Renderer* rd(gcpRendD3D); SRenderPipeline& rp(rd->m_RP); rd->FX_Commit(); if (!CHWShader_D3D::s_pCurInstVS && !CHWShader_D3D::s_pCurInstPS || CHWShader_D3D::s_pCurInstPS->m_bFallback || CHWShader_D3D::s_pCurInstVS->m_bFallback) { return false; } // rendered to volume texture if (rd->m_RP.m_nPassGroupID == EFSLIST_FOG_VOLUME) { if (CD3D9Renderer::CV_r_VolumetricFog != 0 && (rp.m_pCurTechnique && !(rp.m_pCurTechnique->m_Flags & FHF_USE_HULL_SHADER) && (rp.m_pCurTechnique->m_Flags & FHF_USE_GEOMETRY_SHADER))) { // TODO: calculate depth bounds of all patticles. // don't render when all particles are out of fog density texture. if (rp.m_RendNumIndices == 0) { // Draw a quad or octagon, with instanced sprite data int nInstanceVerts = (rp.m_ObjFlags & FOB_OCTAGONAL) ? 8 : 4; rd->FX_DrawPrimitive(eptTriangleStrip, rp.m_FirstVertex, rp.m_RendNumVerts, nInstanceVerts); } else { // Draw non-instanced tri list rd->FX_DrawIndexedPrimitive(eptTriangleList, rp.m_FirstVertex, 0, rp.m_RendNumVerts, rp.m_FirstIndex, rp.m_RendNumIndices); } return true; } return false; } if (rp.m_pCurTechnique && (rp.m_pCurTechnique->m_Flags & FHF_USE_HULL_SHADER)) { // Tessellated shader if (!CHWShader_D3D::s_pCurInstHS && !CHWShader_D3D::s_pCurInstDS || CHWShader_D3D::s_pCurInstHS->m_bFallback || CHWShader_D3D::s_pCurInstDS->m_bFallback) { return false; } if (rp.m_RendNumIndices == 0) { // Draw separated point sprites rd->FX_DrawPrimitive(ept1ControlPointPatchList, rp.m_FirstVertex, rp.m_RendNumVerts); } else { // Draw connected quads rd->FX_DrawIndexedPrimitive(ept4ControlPointPatchList, rp.m_FirstVertex, 0, rp.m_RendNumVerts, rp.m_FirstIndex, rp.m_RendNumIndices); } } else { if (rp.m_RendNumIndices == 0) { // Draw a quad or octagon, with instanced sprite data int nInstanceVerts = (rp.m_ObjFlags & FOB_OCTAGONAL) ? 8 : 4; rd->FX_DrawPrimitive(eptTriangleStrip, rp.m_FirstVertex, rp.m_RendNumVerts, nInstanceVerts); } else { // Draw non-instanced tri list rd->FX_DrawIndexedPrimitive(eptTriangleList, rp.m_FirstVertex, 0, rp.m_RendNumVerts, rp.m_FirstIndex, rp.m_RendNumIndices); } } return true; } //========================================================================================= bool CREParticleGPU::mfPreDraw(SShaderPass* sl) { // predraw is not called for customdraw/sky based render calls. return true; } bool CREParticleGPU::mfDraw(CShader* ef, SShaderPass* sl) { PROFILE_LABEL_SCOPE("PARTICLES"); if (!m_instance || !gRenDev->GetGPUParticleEngine()) { return false; } gRenDev->GetGPUParticleEngine()->Render(m_instance, m_pass, m_shadowMode, m_cameraFOV, m_aspectRatio, m_isWireframeEnabled); return true; } //========================================================================================= bool CREHDRProcess::mfDraw(CShader* ef, SShaderPass* sfm) { CD3D9Renderer* rd = gcpRendD3D; if (!(rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR)) { return false; } assert(rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR || rd->m_RP.m_CurState & GS_WIREFRAME); rd->FX_HDRPostProcessing(); return true; } bool CREBeam::mfDraw(CShader* ef, SShaderPass* sl) { #if defined(AZ_RESTRICTED_PLATFORM) #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DRenderRE_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DRenderRE_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DRenderRE_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else CD3D9Renderer* rd = gcpRendD3D; int nThreadID = rd->m_RP.m_nProcessThreadID; if (SRendItem::m_RecurseLevel[nThreadID] != 0) { return false; } PROFILE_LABEL_SCOPE("LIGHT BEAM"); EShaderQuality nShaderQuality = (EShaderQuality)gcpRendD3D->EF_GetShaderQuality(eST_FX); ERenderQuality nRenderQuality = gRenDev->m_RP.m_eQuality; bool bLowSpecShafts = (nShaderQuality == eSQ_Low) || (nRenderQuality == eRQ_Low); STexState pState(FILTER_BILINEAR, true); const int texStateID(CTexture::GetTexState(pState)); STexState pStatePoint(FILTER_POINT, true); const int texStateIDPoint(CTexture::GetTexState(pStatePoint)); bool bViewerInsideCone = false; CTexture* pLowResRT = CTexture::s_ptexZTargetScaled2; // CTexture::s_ptexBackBufferScaled[1]; CTexture* pLowResRTDepth = CTexture::s_ptexDepthBufferQuarter; SDepthTexture D3dDepthSurface; SDepthTexture* pCurrDepthSurf = NULL; #if D3DRENDERRE_CPP_TRAIT_MFDRAW_SETDEPTHSURF // Depth surface nastiness if (CTexture::IsTextureExist(pLowResRTDepth)) { D3dDepthSurface.nWidth = pLowResRTDepth->GetWidth(); D3dDepthSurface.nHeight = pLowResRTDepth->GetHeight(); D3dDepthSurface.nFrameAccess = -1; D3dDepthSurface.bBusy = false; D3dDepthSurface.pTex = pLowResRTDepth; D3dDepthSurface.pSurf = pLowResRTDepth->GetDeviceDepthStencilSurf(); D3dDepthSurface.pTarget = pLowResRTDepth->GetDevTexture()->Get2DTexture(); pCurrDepthSurf = &D3dDepthSurface; } #endif CRenderObject* pObj = rd->m_RP.m_pCurObject; SRenderObjData* pOD = pObj->GetObjData(); uint16 nLightID = pOD->m_nLightID; SRenderLight* pDL = rd->EF_GetDeferredLightByID(nLightID); bool bCastsShadows = ((pDL->m_Flags & (DLF_CASTSHADOW_MAPS | DLF_PROJECT)) == (DLF_CASTSHADOW_MAPS | DLF_PROJECT)) ? true : false; const CRenderObject::SInstanceInfo& rInstInfo = pObj->m_II; Matrix34A objMatInv = rInstInfo.m_Matrix.GetInverted(); Matrix44A mLightProj, mLightView; CShadowUtils::GetCubemapFrustumForLight(pDL, 0, pDL->m_fLightFrustumAngle * 2.f, &mLightProj, &mLightView, true); Matrix44 projMat = mLightView * mLightProj; const CameraViewParameters& RCam = gRenDev->GetViewParameters(); float fLightAngle = pDL->m_fLightFrustumAngle; float fAngleCoeff = 1.0f / tan_tpl((90.0f - fLightAngle) * gf_PI / 180.0f); float fNear = pDL->m_fProjectorNearPlane; float fFar = pDL->m_fRadius; float fScaleNear = fNear * fAngleCoeff; float fScaleFar = fFar * fAngleCoeff; Vec3 vLightPos = pDL->m_Origin; Vec3 vAxis = rInstInfo.m_Matrix.GetColumn0(); float fSin, fCos; sincos_tpl(fLightAngle * gf_PI / 180.0f, &fSin, &fCos); Vec4 vLightParams = Vec4(fFar, fAngleCoeff, fNear, fFar); Vec4 vSphereParams = Vec4(vLightPos, fFar); Vec4 vConeParams = Vec4(vAxis, fCos); Vec4 pLightPos = Vec4(vLightPos, 1.0f); Vec4 cLightDiffuse = Vec4(pDL->m_Color.r, pDL->m_Color.g, pDL->m_Color.b, pDL->m_SpecMult); Vec3 vEye = RCam.vOrigin; Vec3 vCoords[9]; // Evaluate campos to near plane verts as a sphere. RCam.CalcVerts(vCoords); vCoords[4] = vEye; AABB camExtents(vCoords, 5); float fRadius = camExtents.GetRadius(); Vec3 vCentre = camExtents.GetCenter(); float fCosSq = fCos * fCos; Vec3 vVertToSphere = vCentre - vLightPos; Vec3 d = vVertToSphere + vAxis * (fRadius / fSin); float dSq = d.dot(d); float e = d.dot(vAxis); float eSq = e * e; if ((e > 0.0f) && (eSq >= (dSq * fCosSq))) { float fSinSq = fSin * fSin; dSq = vVertToSphere.dot(vVertToSphere); e = vVertToSphere.dot(vAxis); if ((e < (fFar + fRadius)) && (e > (fNear - fRadius))) // test capping planes { bViewerInsideCone = true; } } Vec4 cEyePosVec(vEye, !bViewerInsideCone ? 1 : 0); Vec4 vShadowCoords = Vec4(0.0f, 0.0f, 1.0f, 1.0f); CTexture* shadowTexture = nullptr; CTexture* projectedTexture = nullptr; if (bCastsShadows) { const ShadowMapFrustum& shadowFrustum = CShadowUtils::GetFirstFrustum(nLightID); if (shadowFrustum.bUseShadowsPool) { shadowTexture = CTexture::s_ptexRT_ShadowPool; float width = CTexture::s_ptexRT_ShadowPool->GetWidth(); float height = CTexture::s_ptexRT_ShadowPool->GetHeight(); vShadowCoords = Vec4(shadowFrustum.packX[0] / width, shadowFrustum.packY[0] / height, shadowFrustum.packWidth[0] / width, shadowFrustum.packHeight[0] / height); } } if (pDL->m_pLightImage) { projectedTexture = (CTexture*)pDL->m_pLightImage; } Vec4 sampleOffsets[5]; { const float tU = 1.0f / (float)pLowResRT->GetWidth(); const float tV = 1.0f / (float)pLowResRT->GetHeight(); sampleOffsets[0] = Vec4(0, 0, 0, 0); sampleOffsets[1] = Vec4(0, -tV, tU, tV); sampleOffsets[2] = Vec4(-tU, 0, -tU, tV); sampleOffsets[3] = Vec4(tU, 0, tU, -tV); sampleOffsets[4] = Vec4(0, tV, -tU, -tV); } Vec4 vMisc = Vec4(1.0f / (float)gcpRendD3D->m_nShadowPoolWidth, 1.0f / (float)gcpRendD3D->m_nShadowPoolHeight, 0.0f, 0.0f); const int ZPass = 2; // passes can be buggy, use manual ordering const int VolumetricPass = 1; const int FinalPass = 0; rd->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]); if (bCastsShadows) { rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0]; } //Setup geometry const int nNumSides = BEAM_RE_CONE_SIDES; const uint32 c_numBBVertices(nNumSides * 2 + 2); SVF_P3F_C4B_T2F bbVertices[c_numBBVertices]; const uint32 c_numBBIndices((nNumSides) * 6 * 2); uint16 bbIndices[c_numBBIndices]; SetupGeometry(&bbVertices[0], &bbIndices[0], fAngleCoeff, fNear, fFar); // copy vertices into dynamic VB TempDynVB::CreateFillAndBind(bbVertices, c_numBBVertices, 0); // copy indices into dynamic IB TempDynIB16::CreateFillAndBind(bbIndices, c_numBBIndices); uint32 nPasses = 0; ef->FXBegin(&nPasses, FEF_DONTSETSTATES); assert(nPasses == (ZPass + 1)); int nStartPass = (bViewerInsideCone || !pCurrDepthSurf) ? VolumetricPass : ZPass; for (int nCurPass = nStartPass; nCurPass > -1; nCurPass--) { ef->FXBeginPass(nCurPass); //set world basis float maskRTWidthL = pLowResRT->GetWidth(); float maskRTHeightL = pLowResRT->GetHeight(); float maskRTWidthH = rd->GetWidth(); float maskRTHeightH = rd->GetHeight(); Vec4 vScreenScale(1.0f / maskRTWidthL, 1.0f / maskRTHeightL, 1.0f / maskRTWidthH, 1.0f / maskRTHeightH); if (nCurPass == nStartPass && pLowResRT) { rd->FX_PushRenderTarget(0, pLowResRT, pCurrDepthSurf, -1, false, 1); rd->FX_SetColorDontCareActions(0, false, false); //Check gmem path for performance when using this pass. rd->FX_ClearTarget(pLowResRT, Clr_Transparent); rd->FX_ClearTarget(pCurrDepthSurf, CLEAR_ZBUFFER); } uint32 nState = (nCurPass == FinalPass) ? (GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA) : 0; if (bViewerInsideCone) { rd->SetCullMode(R_CULL_FRONT); } else { rd->SetCullMode(R_CULL_BACK); } if (bViewerInsideCone || !pCurrDepthSurf) { nState |= GS_NODEPTHTEST; } else { nState |= (nCurPass == ZPass) ? (GS_DEPTHWRITE | GS_COLMASK_NONE) : 0; } rd->FX_SetState(nState); // set vs constants if (nCurPass == VolumetricPass) { ef->FXSetVSFloat(m_eyePosInWSName, &cEyePosVec, 1); ef->FXSetPSFloat(m_eyePosInWSName, &cEyePosVec, 1); ef->FXSetPSFloat(m_projMatrixName, (const Vec4*)&projMat.m00, 4); ef->FXSetPSFloat(m_shadowCoordsName, (const Vec4*)&vShadowCoords, 1); ef->FXSetPSFloat(m_lightParamsName, &vLightParams, 1); ef->FXSetPSFloat(m_sphereParamsName, &vSphereParams, 1); ef->FXSetPSFloat(m_coneParamsName, &vConeParams, 1); ef->FXSetPSFloat(m_lightPosName, &pLightPos, 1); ef->FXSetPSFloat(m_miscOffsetsName, &vMisc, 1); } else if (nCurPass == FinalPass) { ef->FXSetPSFloat(m_sampleOffsetsName, &sampleOffsets[0], 5); } ef->FXSetPSFloat(m_lightDiffuseName, &cLightDiffuse, 1); ef->FXSetPSFloat(m_screenScaleName, &vScreenScale, 1); if (nCurPass == FinalPass && pLowResRT) { pLowResRT->Apply(7, texStateID); } if (projectedTexture) { projectedTexture->Apply(5, texStateID); } if (bCastsShadows && shadowTexture) { shadowTexture->Apply(6, texStateID); // bilinear is a hack, but looks better } //pShadowTex->Apply(6, texStateIDPoint); rd->m_RP.m_nCommitFlags |= FC_MATERIAL_PARAMS; // commit all render changes rd->FX_Commit(); // set vertex declaration and streams of skydome if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F))) { // draw skydome rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, c_numBBVertices, 0, c_numBBIndices); } if ((nCurPass == VolumetricPass) && pLowResRT) { rd->FX_PopRenderTarget(0); } } return true; #endif } bool CREGameEffect::mfDraw(CShader* ef, SShaderPass* sfm) { CRY_ASSERT_MESSAGE(gRenDev->m_pRT->IsRenderThread(), "Trying to render from wrong thread"); CRY_ASSERT(ef); CRY_ASSERT(sfm); if (m_pImpl) { #ifndef _RELEASE _smart_ptr pMaterial = (gRenDev->m_RP.m_pCurObject) ? (gRenDev->m_RP.m_pCurObject->m_pCurrMaterial) : NULL; const char* pEffectName = (pMaterial) ? (PathUtil::GetFileName(pMaterial->GetName())) : "GameEffectRenderElement"; PROFILE_LABEL_SCOPE(pEffectName); #endif uint32 passCount = 0; bool successFlag = true; // Begin drawing ef->FXBegin(&passCount, 0); if (passCount > 0) { // Begin pass ef->FXBeginPass(0); // Draw element successFlag = m_pImpl->mfDraw(ef, sfm, gRenDev->m_RP.m_pCurObject); // End pass ef->FXEndPass(); } // End drawing ef->FXEnd(); return successFlag; } return false; } #if defined(USE_GEOM_CACHES) // Each call of CREGeomCache::mfDraw render *all* meshes that share the same material in the geom cache. See CGeomCacheRenderNode::Render bool CREGeomCache::mfDraw(CShader* ef, SShaderPass* sfm) { PROFILE_FRAME(CREGeomCache::mfDraw); const uint numMeshes = m_meshRenderData.size(); CD3D9Renderer* const pRenderer = gcpRendD3D; SRenderPipeline& rRP = pRenderer->m_RP; SThreadInfo& threadInfo = rRP.m_TI[rRP.m_nProcessThreadID]; CRenderObject* const pRenderObject = rRP.m_pCurObject; Matrix34A matrix = pRenderObject->m_II.m_Matrix; CHWShader_D3D* const pCurVS = (CHWShader_D3D*)sfm->m_VShader; const bool bIsShadowPass = (threadInfo.m_PersFlags & RBPF_SHADOWGEN) != 0; const CCamera& camera = bIsShadowPass ? rRP.m_ShadowInfo.m_pCurShadowFrustum->FrustumPlanes[rRP.m_ShadowInfo.m_nOmniLightSide] : gRenDev->GetCamera(); Matrix44A prevMatrix; #if AZ_RENDER_TO_TEXTURE_GEM_ENABLED // render to texture does not currently support motion blur in the render target if (threadInfo.m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE) { prevMatrix = rRP.m_pCurObject->m_II.m_Matrix; } else { CMotionBlur::GetPrevObjToWorldMat(rRP.m_pCurObject, prevMatrix); } #else CMotionBlur::GetPrevObjToWorldMat(rRP.m_pCurObject, prevMatrix); #endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED const uint64 oldFlagsShader_RT = rRP.m_FlagsShader_RT; uint64 flagsShader_RT = rRP.m_FlagsShader_RT; const int oldFlagsPerFlush = rRP.m_FlagsPerFlush; bool bResetVertexDecl = false; for (uint nMesh = 0; nMesh < numMeshes; ++nMesh) { const SMeshRenderData& meshData = m_meshRenderData[nMesh]; CRenderMesh* const pRenderMesh = static_cast(meshData.m_pRenderMesh.get()); const uint numInstances = meshData.m_instances.size(); if (pRenderMesh && numInstances > 0) { PROFILE_LABEL_SHADER(pRenderMesh->GetSourceName() ? pRenderMesh->GetSourceName() : "Unknown mesh-resource name"); const CRenderMesh* const pVertexContainer = pRenderMesh->_GetVertexContainer(); if (!pVertexContainer->_HasVBStream(VSF_GENERAL) || !pRenderMesh->_HasIBStream()) { // Should never happen. Video buffer is missing continue; } const bool bHasVelocityStream = pRenderMesh->_HasVBStream(VSF_VERTEX_VELOCITY); const bool bIsMotionBlurPass = (rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS) != 0; pRenderMesh->BindStreamsToRenderPipeline(); rRP.m_RendNumVerts = pRenderMesh->GetNumVerts(); if (ef->m_HWTechniques.Num() && pRenderMesh->CanRender()) { const TRenderChunkArray& chunks = pRenderMesh->GetChunks(); const uint numChunks = chunks.size(); for (uint i = 0; i < numChunks; ++i) { const CRenderChunk& chunk = chunks[i]; if (chunk.m_nMatID != m_materialId) { continue; } rRP.m_FirstIndex = chunk.nFirstIndexId; rRP.m_RendNumIndices = chunk.nNumIndices; #if defined(HW_INSTANCING_ENABLED) && D3DRENDERRE_CPP_TRAIT_MFDRAW_USEINSTANCING const bool bUseInstancing = (CRenderer::CV_r_geominstancing != 0) && (numInstances > CRenderer::CV_r_GeomCacheInstanceThreshold); #else const bool bUseInstancing = false; #endif TempDynInstVB instVB(gcpRendD3D); uint numInstancesToDraw = 0; byte* __restrict pInstanceMatricesVB = NULL; // Note: Geom cache instancing is a horrible mess at the moment, because it re-uses // FX_DrawInstances which supports both constant based and attribute based instancing // and all platforms. // // This only sets up the data structures for D3D11 attribute based // instancing. Need to clean this up later and ideally use constant based instancing. const uint64 lastFlagsShader_RT = rRP.m_FlagsShader_RT; rRP.m_FlagsShader_RT = flagsShader_RT | (bUseInstancing ? g_HWSR_MaskBit[HWSR_INSTANCING_ATTR] : 0); if (lastFlagsShader_RT != rRP.m_FlagsShader_RT) { pCurVS->mfSet(bUseInstancing ? HWSF_INSTANCED : 0); } CHWShader_D3D::SHWSInstance* pVPInst = pCurVS->m_pCurInst; int32 nUsedAttr = 3, nInstAttrMask = 0; byte Attributes[32]; if (bUseInstancing) { pVPInst->GetInstancingAttribInfo(Attributes, nUsedAttr, nInstAttrMask); instVB.Allocate(numInstances, nUsedAttr * INST_PARAM_SIZE); pInstanceMatricesVB = (byte*)(instVB.Lock()); } const uint32 nStride = nUsedAttr * sizeof(float[4]); // Fill the stream 3 for per-instance data byte* pWalkData = pInstanceMatricesVB; for (uint nInstance = 0; nInstance < numInstances; ++nInstance) { const SMeshInstance& instance = meshData.m_instances[nInstance]; Matrix34A pieceMatrix = matrix * instance.m_matrix; AABB pieceWorldAABB; pieceWorldAABB.SetTransformedAABB(pieceMatrix, instance.m_aabb); if (!camera.IsAABBVisible_F(pieceWorldAABB)) { continue; } // Needs to be in this scope, because it's used by FX_DrawIndexedMesh Matrix44A prevPieceMatrix = prevMatrix * instance.m_prevMatrix; if (bIsMotionBlurPass) { const float fThreshold = 0.01f; if (bUseInstancing || (rRP.m_nBatchFilter & FB_Z) || !Matrix34::IsEquivalent(pieceMatrix, Matrix34(prevPieceMatrix), fThreshold) || bHasVelocityStream) { rRP.m_FlagsPerFlush |= RBSI_CUSTOM_PREVMATRIX; rRP.m_pPrevMatrix = &prevPieceMatrix; } else { // Don't draw pieces without any motion in motion blur pass continue; } } if (!bUseInstancing) { pRenderer->GetPerInstanceConstantBufferPool().UpdateConstantBuffer([&](void* mappedData) { *reinterpret_cast(mappedData) = pieceMatrix; }, threadInfo.m_RealTime); pRenderObject->m_II.m_Matrix = pieceMatrix; pCurVS->UpdatePerInstanceConstantBuffer(); // Check if instancing messed with vertex declaration if (bResetVertexDecl) { pRenderer->FX_SetVertexDeclaration(rRP.m_FlagsStreams_Decl, rRP.m_CurVFormat); bResetVertexDecl = false; } pRenderer->FX_DrawIndexedMesh(pRenderMesh->GetPrimitiveType()); } else { *reinterpret_cast(pWalkData) = pieceMatrix; if (pVPInst->m_nParams_Inst >= 0) { SCGParamsGroup& Group = CGParamManager::s_Groups[pVPInst->m_nParams_Inst]; pCurVS->UpdatePerInstanceConstants(eHWSC_Vertex, Group.pParams, Group.nParams, pWalkData); } pWalkData += nStride; ++numInstancesToDraw; } } if (bUseInstancing) { instVB.Unlock(); instVB.Bind(3, nUsedAttr * INST_PARAM_SIZE); instVB.Release(); pCurVS->UpdatePerInstanceConstantBuffer(); pRenderer->FX_DrawInstances(ef, sfm, 0, 0, numInstancesToDraw - 1, nUsedAttr, pInstanceMatricesVB, nInstAttrMask, Attributes, 0); bResetVertexDecl = true; } } } } } // Reset matrix to original value for cases when render object gets reused pRenderObject->m_II.m_Matrix = matrix; rRP.m_FlagsShader_RT = oldFlagsShader_RT; rRP.m_FlagsPerFlush = oldFlagsPerFlush; return true; } #endif