You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/D3DRECloud.cpp

989 lines
34 KiB
C++

/*
* 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 "RenderDll_precompiled.h"
#include "DriverD3D.h"
#include "I3DEngine.h"
//=======================================================================
extern CTexture* gTexture;
void CRECloud::IlluminateCloud(Vec3 vLightPos, [[maybe_unused]] Vec3 vObjPos, ColorF cLightColor, ColorF cAmbColor, bool bReset)
{
CryFatalError("Not implemented on D3D11+");
int iOldVP[4];
CD3D9Renderer* rd = gcpRendD3D;
int nShadeRes = m_siShadeResolution;
nShadeRes = 256;
rd->GetViewport(&iOldVP[0], &iOldVP[1], &iOldVP[2], &iOldVP[3]);
Matrix44A origMatView = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView;
Matrix44A origMatProj = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj;
rd->RT_SetViewport(0, 0, nShadeRes, nShadeRes);
Vec3 vDir = vLightPos;
vDir.Normalize();
if (bReset)
{
m_lightDirections.clear();
}
m_lightDirections.push_back(vDir);
vLightPos *= (1.1f * m_boundingBox.GetRadius());
vLightPos += m_boundingBox.GetCenter();
CameraViewParameters cam;
Vec3 vUp(0, 0, 1);
cam.LookAt(vLightPos, m_boundingBox.GetCenter(), vUp);
SortParticles(cam.ViewDir(), vLightPos, eSort_AWAY);
float DistToCntr = (m_boundingBox.GetCenter() - vLightPos) * cam.ViewDir();
float fNearDist = DistToCntr - m_boundingBox.GetRadius();
float fFarDist = DistToCntr + m_boundingBox.GetRadius();
Matrix44A* m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView;
cam.GetModelviewMatrix((float*)m);
mathMatrixOrthoOffCenter(&rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj, -m_boundingBox.GetRadius(), m_boundingBox.GetRadius(), -m_boundingBox.GetRadius(), m_boundingBox.GetRadius(), fNearDist, fFarDist);
rd->SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
rd->SetSrgbWrite(false);
rd->FX_SetState(GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST | GS_ALPHATEST_GREATER, 0);
rd->D3DSetCull(eCULL_None);
CRenderObject* pObj = rd->m_RP.m_pCurObject;
CShader* pSH = rd->m_RP.m_pShader;
SShaderTechnique* pSHT = rd->m_RP.m_pCurTechnique;
SShaderPass* pPass = rd->m_RP.m_pCurPass;
CShaderResources* pShRes = rd->m_RP.m_pShaderResources;
if (pShRes)
{
SEfResTexture* pTextureRes = pShRes->GetTextureResource(EFTT_DIFFUSE);
if (pTextureRes)
{
m_pTexParticle = pTextureRes->m_Sampler.m_pTex;
}
}
if (m_pTexParticle)
{
m_pTexParticle->Apply(0);
}
else
{
AZ_Warning("Shaders System", false, "Error: missing diffuse texture for clouds in CRECloud::IlluminateCloud");
}
rd->FX_SetFPMode();
HRESULT h = S_OK;
rd->EF_ClearTargetsLater(FRT_CLEAR, Clr_White, Clr_FarPlane.r, 0);
rd->FX_Commit();
float fPixelsPerLength = (float)nShadeRes / (2.0f * m_boundingBox.GetRadius());
// the solid angle over which we will sample forward-scattered light.
float fSolidAngle = 0.09f;
int i;
int iNumFailed = 0;
int nParts = m_particles.size();
for (i = 0; i < nParts; i++)
{
SCloudParticle* p = m_particles[i];
Vec3 vParticlePos = p->GetPosition();
Vec3 vOffset = vLightPos - vParticlePos;
float fDistance = fabs(cam.ViewDir() * vOffset) - fNearDist;
float fArea = fSolidAngle * fDistance * fDistance;
int iPixelDim = (int)(sqrtf(fArea) * fPixelsPerLength);
//iPixelDim = 1;
int iNumPixels = iPixelDim * iPixelDim;
if (iNumPixels < 1)
{
iNumPixels = 1;
iPixelDim = 1;
}
// the scale factor to convert the read back pixel colors to an average illumination of the area.
float fColorScaleFactor = fSolidAngle / (iNumPixels * 255.0f);
unsigned char* ds = new unsigned char[4 * iNumPixels];
unsigned char* c = ds;
Vec3 vWinPos;
// find the position in the buffer to which the particle position projects.
rd->ProjectToScreen(vParticlePos.x, vParticlePos.y, vParticlePos.z, &vWinPos.x, &vWinPos.y, &vWinPos.z);
vWinPos.x /= 100.0f / rd->m_NewViewport.nWidth;
vWinPos.y /= 100.0f / rd->m_NewViewport.nHeight;
// offset the projected window position by half the size of the readback region.
vWinPos.x -= 0.5f * iPixelDim;
if (vWinPos.x < 0)
{
vWinPos.x = 0;
}
vWinPos.y = (vWinPos.y - 0.5f * iPixelDim);
if (vWinPos.y < 0)
{
vWinPos.y = 0;
}
// scattering coefficient vector.
//m_sfScatterFactor = m_sfAlbedo * 80 * (1.0f/(4.0f*(float)M_PI));
ColorF vScatter = ColorF(m_sfScatterFactor, m_sfScatterFactor, m_sfScatterFactor, 1);
// add up the read back pixels (only need one component -- its grayscale)
int iSum = 0;
int nTest = 0;
for (int k = 0; k < 4 * iNumPixels; k += 4)
{
PREFAST_SUPPRESS_WARNING(6001) // ds/c is unintialized, all this code is unused, unmaintained and should be entirely removed
iSum += c[k];
nTest += 255;
}
delete [] c;
ColorF vScatteredAmount = ColorF(iSum * fColorScaleFactor, iSum * fColorScaleFactor, iSum * fColorScaleFactor, 1 - m_sfTransparency);
vScatteredAmount *= vScatter;
ColorF vColor = vScatteredAmount;
float fScat = (float)iSum / (float)nTest;
fScat = powf(fScat, 3);
//vColor = ColorF(fScat);
vColor *= cLightColor;
vColor.a = 1 - m_sfTransparency;
//ColorF Amb = ColorF(0.1f, 0.1f, 0.1f, 1.0f);
if (bReset)
{
p->SetBaseColor(cAmbColor);
p->ClearLitColors();
p->AddLitColor(vColor);
}
else
{
p->AddLitColor(vColor);
}
vScatteredAmount *= 1.5f;
// clamp the color
vScatteredAmount.clamp();
vScatteredAmount.a = 1 - m_sfTransparency;
Vec3 vPos = vParticlePos;
Vec3 x = cam.vX * p->GetRadiusX();
Vec3 y = cam.vY * p->GetRadiusY();
rd->DrawQuad3D(vPos - y - x, vPos - y + x, vPos + y + x, vPos + y - x, vScatteredAmount, p->m_vUV[0].x, p->m_vUV[0].y, p->m_vUV[1].x, p->m_vUV[1].y);
}
rd->FX_PopRenderTarget(0);
assert(0);
rd->m_RP.m_pCurObject = pObj;
rd->m_RP.m_pShader = pSH;
rd->m_RP.m_pCurTechnique = pSHT;
rd->m_RP.m_pCurPass = pPass;
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;
rd->RT_SetViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
}
void CRECloud::DisplayWithoutImpostor(const CameraViewParameters& camera)
{
CD3D9Renderer* rd = gcpRendD3D;
assert(rd->m_pRT->IsRenderThread());
int nThreadID = rd->m_RP.m_nProcessThreadID;
// copy the current camera
CameraViewParameters cam(camera);
Vec3 vUp(0, 0, 1);
Vec3 vParticlePlane = cam.vX % cam.vY;
Vec3 vParticleX = (vUp % vParticlePlane).GetNormalized();
Vec3 vParticleY = (vParticleX % vParticlePlane).GetNormalized();
float fCosAngleSinceLastSort = m_vLastSortViewDir * rd->GetViewParameters().ViewDir();
float fSquareDistanceSinceLastSort = (rd->GetViewParameters().vOrigin - m_vLastSortCamPos).GetLengthSquared();
if (fCosAngleSinceLastSort < m_sfSortAngleErrorTolerance || fSquareDistanceSinceLastSort > m_sfSortSquareDistanceTolerance)
{
Vec3 vSortPos = -cam.ViewDir();
vSortPos *= (1.1f * m_boundingBox.GetRadius());
// sort the particles from back to front wrt the camera position.
SortParticles(cam.ViewDir(), vSortPos, eSort_TOWARD);
m_vLastSortViewDir = rd->GetViewParameters().ViewDir();
m_vLastSortCamPos = rd->GetViewParameters().vOrigin;
}
ColorF color;
Vec3 eyeDir;
int nParts = m_particles.size();
int nStartPart = 0;
if (nParts == 0)
{
return;
}
int nCurParts;
CRenderObject* pObj = rd->m_RP.m_pCurObject;
SRenderObjData* pOD = pObj->GetObjData();
CShader* pSH = rd->m_RP.m_pShader;
SShaderTechnique* pSHT = rd->m_RP.m_pCurTechnique;
SShaderPass* pPass = rd->m_RP.m_pCurPass;
CREImposter* pRE = (CREImposter*)pObj->GetRE();
Vec3 vPos = pRE->GetPosition();
uint32 nPasses;
if (SRendItem::m_RecurseLevel[nThreadID] > 0)
{
static CCryNameTSCRC techName("Cloud_Recursive");
pSH->FXSetTechnique(techName);
}
else
{
static CCryNameTSCRC techName("Cloud");
pSH->FXSetTechnique(techName);
}
pSH->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
pSH->FXBeginPass(0);
CShaderResources* pShRes = rd->m_RP.m_pShaderResources;
if (pShRes)
{
SEfResTexture* pTextureRes = pShRes->GetTextureResource(EFTT_DIFFUSE);
if (pTextureRes)
m_pTexParticle = pTextureRes->m_Sampler.m_pTex;
}
if (m_pTexParticle)
{
m_pTexParticle->Apply(0);
}
else
{
AZ_Warning("ShadersSystem", false, "Error: missing diffuse texture for clouds in CRECloud::DisplayWithoutImpostor");
}
/*
// set depth texture for soft clipping of cloud particle against scene geometry
if(0 != CTexture::s_ptexZTarget)
{
STexState depthTextState( FILTER_POINT, true );
CTexture::s_ptexZTarget->Apply( 1, CTexture::GetTexState(depthTextState) );
}
*/
rd->FX_SetState(GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST | GS_ALPHATEST_GREATER, 0);
//rd->FX_SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST | GS_ALPHATEST_GREATER, 0);
rd->D3DSetCull(eCULL_None);
if (SRendItem::m_RecurseLevel[nThreadID] > 0)
{
rd->m_cEF.m_RTRect = Vec4(0, 0, 1, 1);
}
if (SRendItem::m_RecurseLevel[nThreadID] > 0)
{
Vec4 vCloudColorScale(m_fCloudColorScale, 0, 0, 0);
static CCryNameR g_CloudColorScaleName("g_CloudColorScale");
pSH->FXSetPSFloat(g_CloudColorScaleName, &vCloudColorScale, 1);
}
rd->FX_Commit();
if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
while (nStartPart < nParts)
{
nCurParts = nParts - nStartPart;
if (nCurParts > 32768)
{
nCurParts = 32768;
}
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(nCurParts * 4);
SVF_P3F_C4B_T2F* pDst = vb.Lock();
TempDynIB16 ib(gcpRendD3D);
ib.Allocate(nCurParts * 6);
uint16* pDstInds = ib.Lock();
// get various run-time parameters to determine cloud shading
Vec3 sunDir(gEnv->p3DEngine->GetSunDir().GetNormalized());
float minHeight(m_boundingBox.GetMin().z);
float totalHeight(m_boundingBox.GetMax().z - minHeight);
ColorF cloudSpec, cloudDiff;
GetIllumParams(cloudSpec, cloudDiff);
I3DEngine* p3DEngine(gEnv->p3DEngine);
assert(0 != p3DEngine);
Vec3 cloudShadingMultipliers;
p3DEngine->GetGlobalParameter(E3DPARAM_CLOUDSHADING_MULTIPLIERS, cloudShadingMultipliers);
Vec3 brightColor(cloudShadingMultipliers.x* p3DEngine->GetSunColor().CompMul(Vec3(cloudSpec.r, cloudSpec.g, cloudSpec.b)));
Vec3 negCamFrontDir(-cam.ViewDir());
m_fCloudColorScale = 1.0f;
// compute m_fCloudColorScale for HDR rendering
{
if (brightColor.x > m_fCloudColorScale)
{
m_fCloudColorScale = brightColor.x;
}
if (brightColor.y > m_fCloudColorScale)
{
m_fCloudColorScale = brightColor.y;
}
if (brightColor.z > m_fCloudColorScale)
{
m_fCloudColorScale = brightColor.z;
}
// normalize color
brightColor /= m_fCloudColorScale;
}
// render cloud particles
for (int i = 0; i < nCurParts; i++)
{
SCloudParticle* p = m_particles[i + nStartPart];
// draw the particle as a textured billboard.
int nInd = i * 4;
SVF_P3F_C4B_T2F* pQuad = &pDst[nInd];
Vec3 pos = p->GetPosition() * m_fScale + vPos;
Vec3 x = vParticleX * p->GetRadiusX() * m_fScale;
Vec3 y = vParticleY * p->GetRadiusY() * m_fScale;
//ColorB cb = color;
//uint32 cd = cb.pack_argb8888();
// determine shade for each vertex of the billboard
float f0 = sunDir.Dot(Vec3(-y - x).GetNormalized()) * 0.5f + 0.5f;
float f1 = sunDir.Dot(Vec3(-y + x).GetNormalized()) * 0.5f + 0.5f;
float f2 = sunDir.Dot(Vec3(y + x).GetNormalized()) * 0.5f + 0.5f;
float f3 = sunDir.Dot(Vec3(y - x).GetNormalized()) * 0.5f + 0.5f;
Vec3 eye0(cam.vOrigin - (pos - y - x));
eye0 = (eye0.GetLengthSquared() < 1e-4f) ? negCamFrontDir : eye0.GetNormalized();
Vec3 eye1(cam.vOrigin - (pos - y + x));
eye1 = (eye1.GetLengthSquared() < 1e-4f) ? negCamFrontDir : eye1.GetNormalized();
Vec3 eye2(cam.vOrigin - (pos + y + x));
eye2 = (eye2.GetLengthSquared() < 1e-4f) ? negCamFrontDir : eye2.GetNormalized();
Vec3 eye3(cam.vOrigin - (pos + y - x));
eye3 = (eye3.GetLengthSquared() < 1e-4f) ? negCamFrontDir : eye3.GetNormalized();
f0 *= sunDir.Dot(eye0) * 0.25f + 0.75f;
f1 *= sunDir.Dot(eye1) * 0.25f + 0.75f;
f2 *= sunDir.Dot(eye2) * 0.25f + 0.75f;
f3 *= sunDir.Dot(eye3) * 0.25f + 0.75f;
//float heightScaleTop( ( p->GetPosition().z + x.z + y.z - minHeight ) / totalHeight );
//float heightScaleBottom( ( p->GetPosition().z - x.z - y.z - minHeight ) / totalHeight );
float heightScaleTop(1);
float heightScaleBottom(1);
// compute finale shading values
f0 = clamp_tpl(f0 * heightScaleBottom, 0.0f, 1.0f);
f1 = clamp_tpl(f1 * heightScaleBottom, 0.0f, 1.0f);
f2 = clamp_tpl(f2 * heightScaleTop, 0.0f, 1.0f);
f3 = clamp_tpl(f3 * heightScaleTop, 0.0f, 1.0f);
// blend between dark and bright cloud color based on shading value
Vec3 c0(f0 * (brightColor));
Vec3 c1(f1 * (brightColor));
Vec3 c2(f2 * (brightColor));
Vec3 c3(f3 * (brightColor));
float transp(pRE->m_fCurTransparency);
// write billboard vertices
ColorF col0(c0.x, c0.y, c0.z, transp);
col0.clamp();
pQuad[0].xyz = pos - y - x;
pQuad[0].color.dcolor = ColorB(col0).pack_argb8888();
pQuad[0].st = Vec2(p->m_vUV[0].x, p->m_vUV[0].y);
ColorF col1(c1.x, c1.y, c1.z, transp);
col1.clamp();
pQuad[1].xyz = pos - y + x;
pQuad[1].color.dcolor = ColorB(col1).pack_argb8888();
pQuad[1].st = Vec2(p->m_vUV[1].x, p->m_vUV[0].y);
ColorF col2(c2.x, c2.y, c2.z, transp);
col2.clamp();
pQuad[2].xyz = pos + y + x;
pQuad[2].color.dcolor = ColorB(col2).pack_argb8888();
pQuad[2].st = Vec2(p->m_vUV[1].x, p->m_vUV[1].y);
ColorF col3(c3.x, c3.y, c3.z, transp);
col3.clamp();
pQuad[3].xyz = pos + y - x;
pQuad[3].color.dcolor = ColorB(col3).pack_argb8888();
pQuad[3].st = Vec2(p->m_vUV[0].x, p->m_vUV[1].y);
uint16* pInds = &pDstInds[i * 6];
pInds[0] = nInd;
pInds[1] = nInd + 1;
pInds[2] = nInd + 2;
pInds[3] = nInd;
pInds[4] = nInd + 2;
pInds[5] = nInd + 3;
}
vb.Unlock();
vb.Bind(0);
vb.Release();
ib.Unlock();
ib.Bind();
ib.Release();
rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, nCurParts * 4, 0, nCurParts * 6);
nStartPart += nCurParts;
}
}
rd->m_RP.m_pCurObject = pObj;
rd->m_RP.m_pShader = pSH;
rd->m_RP.m_pCurTechnique = pSHT;
rd->m_RP.m_pCurPass = pPass;
}
bool CRECloud::GenerateCloudImposter(CShader* pShader, CShaderResources* pRes, CRenderObject* pObject)
{
CD3D9Renderer* r = gcpRendD3D;
r->FX_PreRender(1);
r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags |= RBPF_DRAWTOTEXTURE;
r->m_RP.m_pRE = NULL;
r->m_RP.m_pShader = pShader;
r->m_RP.m_pShaderResources = pRes;
r->m_RP.m_pCurObject = pObject;
r->m_RP.m_RendNumVerts = 0;
r->m_RP.m_RendNumIndices = 0;
mfPrepare(false);
r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_DRAWTOTEXTURE;
r->FX_PostRender();
return true;
}
bool CRECloud::UpdateImposter(CRenderObject* pObj)
{
CD3D9Renderer* rd = gcpRendD3D;
SRenderObjData* pOD = pObj->GetObjData();
CREImposter* pRE = (CREImposter*)pObj->GetRE();
if (!pRE->PrepareForUpdate())
{
if (!CRenderer::CV_r_cloudsupdatealways && pRE->m_nFrameReset == rd->m_nFrameReset)
{
return true;
}
}
PROFILE_FRAME(Imposter_CloudUpdate);
pRE->m_nFrameReset = rd->m_nFrameReset;
int nLogX = pRE->m_nLogResolutionX;
int nLogY = pRE->m_nLogResolutionY;
int iResX = 1 << nLogX;
int iResY = 1 << nLogY;
while (iResX > SDynTexture::s_CurTexAtlasSize)
{
nLogX--;
iResX = 1 << nLogX;
}
while (iResY > SDynTexture::s_CurTexAtlasSize)
{
nLogY--;
iResY = 1 << nLogY;
}
int iOldVP[4];
rd->GetViewport(&iOldVP[0], &iOldVP[1], &iOldVP[2], &iOldVP[3]);
Matrix44A origMatView = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView;
Matrix44A origMatProj = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj;
rd->RT_SetViewport(0, 0, iResX, iResY);
#ifndef _RELEASE
rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumCloudImpostersUpdates++;
#endif
Matrix44A* m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView;
pRE->m_LastViewParameters.GetModelviewMatrix((float*)m);
m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj;
//pRE->m_LastCamera.GetProjectionMatrix(*m);
mathMatrixPerspectiveOffCenter(m, pRE->m_LastViewParameters.fWL, pRE->m_LastViewParameters.fWR, pRE->m_LastViewParameters.fWB,
pRE->m_LastViewParameters.fWT, pRE->m_LastViewParameters.fNear, pRE->m_LastViewParameters.fFar);
IDynTexture** pDT;
if (!pRE->m_bSplit)
{
if (!pRE->m_bScreenImposter)
{
pDT = &pRE->m_pTexture;
}
else
{
pDT = &pRE->m_pScreenTexture;
}
if (!*pDT)
{
*pDT = new SDynTexture2(iResX, iResY, FT_STATE_CLAMP, "CloudImposter", eTP_Clouds);
}
if (*pDT)
{
SDepthTexture* pDepth = &gcpRendD3D->m_DepthBufferOrig;
uint32 nX1, nY1, nW1, nH1;
(*pDT)->Update(iResX, iResY);
(*pDT)->GetImageRect(nX1, nY1, nW1, nH1);
#if defined(OPENGL_ES)
// OpenGLES needs the color texture size to match the depth texture
pDepth = nW1 != static_cast<int>(rd->m_d3dsdBackBuffer.Width) || nH1 != static_cast<int>(rd->m_d3dsdBackBuffer.Height) ? nullptr : pDepth;
#else
pDepth = nW1 > static_cast<int>(rd->m_d3dsdBackBuffer.Width) || nH1 > static_cast<int>(rd->m_d3dsdBackBuffer.Height) ? nullptr : pDepth;
#endif // defined(OPENGL_ES)
if (!pDepth)
{
pDepth = rd->FX_GetDepthSurface(nW1, nH1, false);
}
(*pDT)->ClearRT();
(*pDT)->SetRT(0, true, pDepth);
gTexture = (CTexture*)(*pDT)->GetTexture();
uint32 nX, nY, nW, nH;
(*pDT)->GetSubImageRect(nX, nY, nW, nH);
if (pRE->m_bScreenImposter)
{
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_cloudsdebug != 2)
{
rd->LogStrv(SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID], "Generating screen '%s' - %s (%d, %d, %d, %d) (%d)\n", gTexture->GetName(), (*pDT)->IsSecondFrame() ? "Second" : "First", nX, nY, nW, nH, gRenDev->GetFrameID(false));
}
}
else
{
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_cloudsdebug != 1)
{
rd->LogStrv(SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID], "Generating '%s' - %s (%d, %d, %d, %d) (%d)\n", gTexture->GetName(), (*pDT)->IsSecondFrame() ? "Second" : "First", nX, nY, nW, nH, gRenDev->GetFrameID(false));
}
}
int nSize = iResX * iResY * 4;
pRE->m_MemUpdated += nSize / 1024;
rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_CloudImpostersSizeUpdate += nSize;
DisplayWithoutImpostor(pRE->m_LastViewParameters);
(*pDT)->SetUpdateMask();
(*pDT)->RestoreRT(0, true);
}
}
rd->RT_SetViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
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 true;
}
bool CRECloud::mfDisplay(bool bDisplayFrontOfSplit)
{
CD3D9Renderer* rd = gcpRendD3D;
int nThreadID = rd->m_RP.m_nProcessThreadID;
CRenderObject* pObj = rd->m_RP.m_pCurObject;
CREImposter* pRE = (CREImposter*)pObj->GetRE();
Vec3 vPos = pRE->m_vPos;
CShader* pSH = rd->m_RP.m_pShader;
SShaderTechnique* pSHT = rd->m_RP.m_pCurTechnique;
SShaderPass* pPass = rd->m_RP.m_pCurPass;
#ifndef _RELEASE
rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumCloudImpostersDraw++;
#endif
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_cloudsdebug == 2 && pRE->m_bScreenImposter)
{
return true;
}
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_cloudsdebug == 1 && !pRE->m_bScreenImposter)
{
return true;
}
uint32 nPersFlags2 = rd->m_RP.m_PersFlags2;
rd->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF | RBPF2_COMMIT_CM);
uint32 nPasses;
float fAlpha = pObj->m_fAlpha;
ColorF col(1, 1, 1, fAlpha);
if (SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID] > 0)
{
DisplayWithoutImpostor(rd->GetViewParameters());
return true;
}
// if (!pRE->m_pTexture || (bDisplayFrontOfSplit && !pRE->m_pFrontTexture))
// Warning("WARNING: CRECloud::mfDisplay: missing texture!");
// else
// {
// IDynTexture *pDT;
// if (bDisplayFrontOfSplit)
// pDT = pRE->m_pFrontTexture;
// else
// pDT = pRE->m_pTexture;
//CTexture::m_Text_NoTexture->Apply(0);
// pDT->Apply(0);
// }
IDynTexture* pDT;
if (!pRE->m_bScreenImposter)
{
pDT = pRE->m_pTexture;
}
else
{
pDT = pRE->m_pScreenTexture;
}
float fOffsetU = 0, fOffsetV = 0;
if (pDT && (!bDisplayFrontOfSplit || (bDisplayFrontOfSplit && pRE->m_pFrontTexture)))
{
pDT->Apply(0);
fOffsetU = 0.5f / (float) pDT->GetWidth();
fOffsetV = 0.5f / (float) pDT->GetHeight();
}
// set depth texture for soft clipping of cloud against scene geometry
if (0 != CTexture::s_ptexZTarget)
{
STexState depthTextState(FILTER_POINT, true);
CTexture::s_ptexZTarget->Apply(1, CTexture::GetTexState(depthTextState));
}
int State = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA | GS_ALPHATEST_GREATER;
if (pRE->m_bSplit)
{
if (!bDisplayFrontOfSplit)
{
State |= GS_DEPTHWRITE;
}
else
{
State |= GS_NODEPTHTEST;
}
}
// Martin test - for clouds particle soft clipping against terrain
// State |= GS_NODEPTHTEST;
// Added for Sun-rays to work with clouds:
// - force depth writing so that sun-rays interact with clouds.
// - also make sure we don't make any depth test (it's already done in pixel shader) so that no alpha test artifacts are visible
//State |= GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL;
rd->FX_SetState(State, 0);
Vec3 x, y, z;
Vec4 vCloudColorScale(m_fCloudColorScale, 0, 0, 0);
if (!pRE->m_bScreenImposter)
{
z = vPos - pRE->m_LastViewParameters.vOrigin;
z.Normalize();
x = (z ^ pRE->m_LastViewParameters.vY);
x.Normalize();
x *= pRE->m_fRadiusX;
y = (x ^ z);
y.Normalize();
y *= pRE->m_fRadiusY;
const CameraViewParameters& cam = rd->GetViewParameters();
Matrix44A* m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView;
cam.GetModelviewMatrix((float*)m);
m = &rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj;
mathMatrixPerspectiveOffCenter(m, cam.fWL, cam.fWR, cam.fWB, cam.fWT, cam.fNear, cam.fFar);
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->m20 = (rti->nGridSizeX - 1.f) - rti->nPosX * 2.0f;
m->m21 = -((rti->nGridSizeY - 1.f) - rti->nPosY * 2.0f);
}
}
rd->D3DSetCull(eCULL_None);
static CCryNameTSCRC techName("Cloud_Imposter");
pSH->FXSetTechnique(techName);
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES);
pSH->FXBeginPass(0);
static CCryNameR g_CloudColorScaleName("g_CloudColorScale");
pSH->FXSetPSFloat(g_CloudColorScaleName, &vCloudColorScale, 1);
Vec3 lPos;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_POS, lPos);
Vec4 lightningPosition(lPos.x, lPos.y, lPos.z, 0.0f);
static CCryNameR LightningPosName("LightningPos");
pSH->FXSetVSFloat(LightningPosName, &lightningPosition, 1);
Vec3 lCol;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_COLOR, lCol);
Vec3 lSize;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_SIZE, lSize);
Vec4 lightningColorSize(lCol.x, lCol.y, lCol.z, lSize.x * 0.01f);
static CCryNameR LightningColSizeName("LightningColSize");
pSH->FXSetVSFloat(LightningColSizeName, &lightningColorSize, 1);
rd->m_RP.m_nCommitFlags |= FC_MATERIAL_PARAMS;
rd->FX_Commit();
rd->DrawQuad3D(pRE->m_vQuadCorners[0] + vPos,
pRE->m_vQuadCorners[1] + vPos,
pRE->m_vQuadCorners[2] + vPos,
pRE->m_vQuadCorners[3] + vPos, col, 0 + fOffsetU, 1 - fOffsetV, 1 - fOffsetU, 0 + fOffsetV);
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_impostersdraw & 4)
{
rd->FX_SetState(GS_NODEPTHTEST);
SAuxGeomRenderFlags auxFlags;
auxFlags.SetDepthTestFlag(e_DepthTestOff);
rd->GetIRenderAuxGeom()->SetRenderFlags(auxFlags);
rd->GetIRenderAuxGeom()->DrawAABB(AABB(pRE->m_WorldSpaceBV.GetMin(), pRE->m_WorldSpaceBV.GetMax()), false, Col_White, eBBD_Faceted);
}
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_impostersdraw & 2)
{
CRenderObject* pObject = rd->m_RP.m_pCurObject;
int colR = ((DWORD)((UINT_PTR)pObject) >> 4) & 0xf;
int colG = ((DWORD)((UINT_PTR)pObject) >> 8) & 0xf;
int colB = ((DWORD)((UINT_PTR)pObject) >> 12) & 0xf;
Vec3 v[4];
v[0] = vPos - y - x;
v[1] = vPos - y + x;
v[2] = vPos + y + x;
v[3] = vPos + y - x;
vtx_idx inds[6];
inds[0] = 0;
inds[1] = 1;
inds[2] = 2;
inds[3] = 0;
inds[4] = 2;
inds[5] = 3;
SAuxGeomRenderFlags auxFlags;
auxFlags.SetFillMode(e_FillModeWireframe);
auxFlags.SetDepthTestFlag(e_DepthTestOn);
rd->GetIRenderAuxGeom()->SetRenderFlags(auxFlags);
rd->GetIRenderAuxGeom()->DrawTriangles(v, 4, inds, 6, Col_Green);
}
}
else
{
x = pRE->m_LastViewParameters.vX;
x *= 0.5f * (pRE->m_LastViewParameters.fWR - pRE->m_LastViewParameters.fWL);
y = pRE->m_LastViewParameters.vY;
y *= 0.5f * (pRE->m_LastViewParameters.fWT - pRE->m_LastViewParameters.fWB);
z = -pRE->m_LastViewParameters.vZ;
z *= pRE->m_LastViewParameters.fNear;
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_impostersdraw & 4)
{
rd->GetIRenderAuxGeom()->DrawAABB(AABB(pRE->m_WorldSpaceBV.GetMin(), pRE->m_WorldSpaceBV.GetMax()), false, Col_Red, eBBD_Faceted);
}
// draw a polygon with this texture...
Matrix44A 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);
}
}
Matrix44A 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();
pSH->FXSetTechnique("Cloud_ScreenImposter");
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES);
pSH->FXBeginPass(0);
float fNear = pRE->m_fNear;
float fFar = pRE->m_fFar;
if (fNear < 0 || fNear > 1)
{
fNear = 0.92f;
}
if (fFar < 0 || fFar > 1)
{
fFar = 0.999f;
}
float fZ = (fNear + fFar) * 0.5f;
Vec4 pos(pRE->GetPosition(), 1);
static CCryNameR vCloudWSPosName("vCloudWSPos");
pSH->FXSetVSFloat(vCloudWSPosName, &pos, 1);
static CCryNameR g_CloudColorScaleName("g_CloudColorScale");
pSH->FXSetPSFloat(g_CloudColorScaleName, &vCloudColorScale, 1);
Vec3 lPos;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_POS, lPos);
Vec4 lightningPosition(lPos.x, lPos.y, lPos.z, col.a);
static CCryNameR LightningPosName("LightningPos");
pSH->FXSetVSFloat(LightningPosName, &lightningPosition, 1);
Vec3 lCol;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_COLOR, lCol);
Vec3 lSize;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKY_HIGHLIGHT_SIZE, lSize);
Vec4 lightningColorSize(lCol.x, lCol.y, lCol.z, lSize.x * 0.01f);
static CCryNameR LightningColSizeName("LightningColSize");
pSH->FXSetVSFloat(LightningColSizeName, &lightningColorSize, 1);
{
TempDynVB<SVF_P3F_T2F_T3F> vb(gRenDev);
vb.Allocate(4);
SVF_P3F_T2F_T3F* vQuad = vb.Lock();
Vec3 vCoords[8];
gcpRendD3D->GetViewParameters().CalcVerts(vCoords);
Vec3 vRT = vCoords[4] - vCoords[0];
Vec3 vLT = vCoords[5] - vCoords[1];
Vec3 vLB = vCoords[6] - vCoords[2];
Vec3 vRB = vCoords[7] - vCoords[3];
vQuad[0].p.x = -1;
vQuad[0].p.y = -1;
vQuad[0].p.z = fZ;
vQuad[0].st0[0] = 0;
vQuad[0].st0[1] = 1;
vQuad[0].st1 = vLB;
vQuad[1].p.x = 1;
vQuad[1].p.y = -1;
vQuad[1].p.z = fZ;
vQuad[1].st0[0] = 1;
vQuad[1].st0[1] = 1;
vQuad[1].st1 = vRB;
vQuad[3].p.x = 1;
vQuad[3].p.y = 1;
vQuad[3].p.z = fZ;
vQuad[3].st0[0] = 1;
vQuad[3].st0[1] = 0;
vQuad[3].st1 = vRT;
vQuad[2].p.x = -1;
vQuad[2].p.y = 1;
vQuad[2].p.z = fZ;
vQuad[2].st0[0] = 0;
vQuad[2].st0[1] = 0;
vQuad[2].st1 = vLT;
vb.Unlock();
vb.Bind(0);
rd->m_RP.m_nCommitFlags |= FC_MATERIAL_PARAMS;
rd->FX_Commit();
if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_T2F_T3F)))
{
rd->FX_DrawPrimitive(eptTriangleStrip, 0, 4);
}
vb.Release();
}
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;
}
pSH->FXEndPass();
pSH->FXEnd();
rd->m_RP.m_PersFlags2 = nPersFlags2;
rd->m_RP.m_pCurObject = pObj;
rd->m_RP.m_pShader = pSH;
rd->m_RP.m_pCurTechnique = pSHT;
rd->m_RP.m_pCurPass = pPass;
return true;
}
bool CRECloud::mfDraw([[maybe_unused]] CShader* ef, [[maybe_unused]] SShaderPass* pPass)
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_impostersdraw)
{
return true;
}
CD3D9Renderer* rd = gcpRendD3D;
CRenderObject* pObj = rd->m_RP.m_pCurObject;
CREImposter* pRE = (CREImposter*)pObj->GetRE();
mfDisplay(false);
if (pRE->IsSplit())
{
// now display the front half of the split impostor.
mfDisplay(true);
}
return true;
}