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.
928 lines
38 KiB
C++
928 lines
38 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"
|
|
#include "IIndexedMesh.h"
|
|
#include "IShader.h"
|
|
#include "Common/RenderView.h"
|
|
#include "Common/Textures/TextureManager.h"
|
|
|
|
class CREBaker
|
|
: public CRendElementBase
|
|
{
|
|
private:
|
|
IRenderElement* m_pSrc;
|
|
std::vector<IIndexedMesh*> m_pDst;
|
|
CMesh* m_pSrcMesh;
|
|
int m_nPhase;
|
|
bool m_bSmoothNormals;
|
|
const SMeshBakingMaterialParams* m_params;
|
|
int m_numParams;
|
|
|
|
public:
|
|
CREBaker(IRenderElement* pSrc, CMesh* pSrcMesh, std::vector<IIndexedMesh*> pDst, int nPhase, const SMeshBakingMaterialParams* params, int numParams, bool bSmoothNormals) { m_pSrc = pSrc; m_pDst = pDst; m_pSrcMesh = pSrcMesh; m_nPhase = nPhase; m_params = params; m_numParams = numParams; m_bSmoothNormals = bSmoothNormals; }
|
|
virtual ~CREBaker() { }
|
|
inline uint16 mfGetFlags(void) { return m_pSrc->mfGetFlags(); }
|
|
inline void mfSetFlags(uint16 fl) { m_pSrc->mfSetFlags(fl); }
|
|
inline void mfUpdateFlags(uint16 fl) { m_pSrc->mfUpdateFlags(fl); }
|
|
inline void mfClearFlags(uint16 fl) { m_pSrc->mfClearFlags(fl); }
|
|
inline bool mfCheckUpdate(int Flags, uint16 nFrame, bool /* unused */) { return m_pSrc->mfCheckUpdate(Flags, nFrame); }
|
|
virtual void mfPrepare(bool bCheckOverflow) { m_pSrc->mfPrepare(bCheckOverflow); gcpRendD3D->m_RP.m_CurVFormat = eVF_P3F_T2F_T3F; }
|
|
virtual CRenderChunk* mfGetMatInfo() { return m_pSrc->mfGetMatInfo(); }
|
|
virtual TRenderChunkArray* mfGetMatInfoList() { return m_pSrc->mfGetMatInfoList(); }
|
|
virtual int mfGetMatId() { return m_pSrc->mfGetMatId(); }
|
|
virtual void mfReset() { m_pSrc->mfReset(); }
|
|
virtual bool mfIsHWSkinned() { return m_pSrc->mfIsHWSkinned(); }
|
|
virtual CRendElementBase* mfCopyConstruct(void) { return m_pSrc->mfCopyConstruct(); }
|
|
virtual void mfCenter(Vec3& centr, CRenderObject* pObj) { m_pSrc->mfCenter(centr, pObj); }
|
|
virtual void mfGetBBox(Vec3& vMins, Vec3& vMaxs) { m_pSrc->mfGetBBox(vMins, vMaxs); }
|
|
virtual void mfGetPlane(Plane& pl) { m_pSrc->mfGetPlane(pl); }
|
|
virtual bool mfCompile(CParserBin& Parser, SParserFrame& Frame) { return m_pSrc->mfCompile(Parser, Frame); }
|
|
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
|
|
virtual void* mfGetPointer(ESrcPointer ePT, int* Stride, EParamType Type, ESrcPointer Dst, int Flags) { return m_pSrc->mfGetPointer(ePT, Stride, Type, Dst, Flags); }
|
|
virtual bool mfPreDraw(SShaderPass* sl) { return m_pSrc->mfPreDraw(sl); }
|
|
virtual bool mfUpdate(int Flags, bool bTessellation = false) { bool bRet = m_pSrc->mfUpdate(Flags, bTessellation); gcpRendD3D->m_RP.m_CurVFormat = eVF_P3F_T2F_T3F; return bRet; }
|
|
virtual void mfPrecache(const SShaderItem& SH) { m_pSrc->mfPrecache(SH); }
|
|
virtual void mfExport(struct SShaderSerializeContext& SC) { m_pSrc->mfExport(SC); }
|
|
virtual int Size() { return m_pSrc->Size(); }
|
|
virtual void GetMemoryUsage(ICrySizer* pSizer) const { m_pSrc->GetMemoryUsage(pSizer); }
|
|
};
|
|
|
|
bool CREBaker::mfDraw(CShader* ef, SShaderPass* sfm)
|
|
{
|
|
static CCryNameR triPosName("TRI_POS");
|
|
static CCryNameR triBiNormName("TRI_BINORM");
|
|
static CCryNameR triTangName("TRI_TANGENT");
|
|
static CCryNameR triUVName("TRI_UV");
|
|
static CCryNameR triColorName("TRI_COLOR");
|
|
static CCryNameR triZRange("ZOFFSET");
|
|
Vec4 zRange(10.0f, 0.5f, 0.0f, 0.0f);
|
|
CD3D9Renderer* const __restrict rd = gcpRendD3D;
|
|
|
|
const bool bReverseDepth = (rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) != 0;
|
|
|
|
zRange.z = (float)m_nPhase - 0.5f;
|
|
|
|
if (m_pDst.empty())
|
|
{
|
|
CryLog("BakeMesh: Failed as pOutput is NULL in CREBaker::mfDraw\n");
|
|
return false;
|
|
}
|
|
|
|
for (std::vector<IIndexedMesh*>::iterator mit = m_pDst.begin(), mend = m_pDst.end(); mit != mend; ++mit)
|
|
{
|
|
IIndexedMesh* pOutput = *mit;
|
|
if (!pOutput)
|
|
{
|
|
continue;
|
|
}
|
|
int numOutputTriangles = pOutput->GetIndexCount() / 3;
|
|
int numPositions = 0;
|
|
CMesh* pOutputMesh = pOutput->GetMesh();
|
|
Vec3* pOutPos = pOutputMesh->GetStreamPtrAndElementCount<Vec3>(CMesh::POSITIONS, 0, &numPositions);
|
|
SMeshTangents* pOutTangents = pOutputMesh->GetStreamPtr<SMeshTangents>(CMesh::TANGENTS, 0);
|
|
vtx_idx* pOutIndices = pOutputMesh->GetStreamPtr<vtx_idx>(CMesh::INDICES, 0);
|
|
SMeshTexCoord* pOutTexCoords = pOutputMesh->GetStreamPtr<SMeshTexCoord>(CMesh::TEXCOORDS, 0);
|
|
|
|
std::vector<Vec3> smoothedNormals;
|
|
if (m_bSmoothNormals)
|
|
{
|
|
smoothedNormals.resize(numPositions);
|
|
for (int pi = 0; pi < numPositions; pi++)
|
|
{
|
|
Vec3 p = pOutPos[pi];
|
|
Vec3 n(ZERO);
|
|
for (int i = 0; i < numOutputTriangles; i++)
|
|
{
|
|
vtx_idx idx0 = pOutIndices[3 * i + 0];
|
|
vtx_idx idx1 = pOutIndices[3 * i + 1];
|
|
vtx_idx idx2 = pOutIndices[3 * i + 2];
|
|
if (pOutPos[idx0] == p || pOutPos[idx1] == p || pOutPos[idx2] == p)
|
|
{
|
|
Vec3 faceN = (pOutPos[idx1] - pOutPos[idx0]).Cross(pOutPos[idx2] - pOutPos[idx0]);
|
|
faceN.NormalizeSafe();
|
|
n += faceN;
|
|
}
|
|
}
|
|
if (n.NormalizeSafe() == 0.0f)
|
|
{
|
|
// Make sure we actually get a valid normal even if everything went wrong
|
|
n = pOutTangents[pi].GetN().normalize();
|
|
}
|
|
smoothedNormals[pi] = n;
|
|
}
|
|
}
|
|
|
|
// Allocate and fill per-stream vertex buffers
|
|
TempDynVB<SVF_P3F_T2F_T3F> vb0(gcpRendD3D);
|
|
TempDynVB<SPipTangents> vb1(gcpRendD3D);
|
|
|
|
{
|
|
vb0.Allocate(numOutputTriangles * 3);
|
|
SVF_P3F_T2F_T3F* vInputs = vb0.Lock();
|
|
|
|
for (int i = numOutputTriangles * 3 - 1; i >= 0; i--)
|
|
{
|
|
SVF_P3F_T2F_T3F& v = vInputs[i];
|
|
vtx_idx idx = pOutIndices[i];
|
|
v.st0 = pOutTexCoords[idx].GetUV();
|
|
v.p = pOutPos[idx];
|
|
if (m_bSmoothNormals)
|
|
{
|
|
v.st1 = smoothedNormals[idx];
|
|
}
|
|
else
|
|
{
|
|
v.st1 = pOutTangents[idx].GetN().normalize();
|
|
}
|
|
}
|
|
|
|
vb0.Unlock();
|
|
vb0.Bind(VSF_GENERAL);
|
|
}
|
|
|
|
{
|
|
vb1.Allocate(numOutputTriangles * 3);
|
|
SPipTangents* pTangentsVB = vb1.Lock();
|
|
|
|
for (int i = 0; i < numOutputTriangles * 3; i++)
|
|
{
|
|
vtx_idx idx = pOutIndices[i];
|
|
pOutTangents[idx].ExportTo(pTangentsVB[i]);
|
|
}
|
|
|
|
vb1.Unlock();
|
|
vb1.Bind(VSF_TANGENTS);
|
|
}
|
|
|
|
int nStencilState =
|
|
STENC_FUNC(FSS_STENCFUNC_ALWAYS) |
|
|
STENCOP_FAIL(FSS_STENCOP_KEEP) |
|
|
STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
|
|
STENCOP_PASS(FSS_STENCOP_REPLACE);
|
|
|
|
uint32 State = rd->m_RP.m_CurState | GS_STENCIL;
|
|
|
|
if (ef->m_Flags & EF_DECAL)
|
|
{
|
|
PROFILE_LABEL("DECAL");
|
|
State = (State & ~GS_BLEND_MASK);
|
|
State |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
|
}
|
|
|
|
rd->FX_SetStencilState(nStencilState, 1, 0xFFFFFFFF, 0xFFFFFFFF);
|
|
rd->FX_SetState(State);
|
|
|
|
if (!FAILED(rd->FX_SetVertexDeclaration(VSM_GENERAL | ((1 << VSF_TANGENTS)), eVF_P3F_T2F_T3F)))
|
|
{
|
|
CMesh* pInputMesh = m_pSrcMesh;
|
|
Vec3* pInPos = pInputMesh->GetStreamPtr<Vec3>(CMesh::POSITIONS);
|
|
vtx_idx* pInIndices = pInputMesh->GetStreamPtr<vtx_idx>(CMesh::INDICES);
|
|
SMeshTexCoord* pInTexCoords = pInputMesh->GetStreamPtr<SMeshTexCoord>(CMesh::TEXCOORDS);
|
|
SMeshTangents* pInTangents = pInputMesh->GetStreamPtr<SMeshTangents>(CMesh::TANGENTS);
|
|
SMeshColor* pInColors = pInputMesh->GetStreamPtr<SMeshColor>(CMesh::COLORS, 0);
|
|
Matrix44* pTexMtx = NULL;
|
|
if (rd->m_RP.m_pShaderResources)
|
|
{
|
|
SEfResTexture* pTex = rd->m_RP.m_pShaderResources->GetTextureResource(EFTT_DIFFUSE);
|
|
if (pTex && pTex->IsHasModificators())
|
|
{
|
|
SEfTexModificator* mod = pTex->m_Ext.m_pTexModifier;
|
|
pTexMtx = &mod->m_TexMatrix;
|
|
}
|
|
}
|
|
|
|
float textureBakeLoopTimer = gEnv->pTimer->GetAsyncCurTime();
|
|
for (int i = 0; i < rd->m_RP.m_RendNumIndices / 3; i++)
|
|
{
|
|
Vec4 triPos[3];
|
|
Vec4 triUV[3];
|
|
Vec4 triTangents[2][3];
|
|
Vec4 triColor[3];
|
|
|
|
for (int t = 0; t < 3; t++)
|
|
{
|
|
vtx_idx idx = pInIndices[rd->m_RP.m_FirstIndex + i * 3 + t];
|
|
triPos[t].x = pInPos[idx].x;
|
|
triPos[t].y = pInPos[idx].y;
|
|
triPos[t].z = pInPos[idx].z;
|
|
pInTexCoords[idx].GetUV(triUV[t]);
|
|
if (pTexMtx)
|
|
{
|
|
Vec4 modTex = (*pTexMtx) * Vec4(triUV[t].x, triUV[t].y, 0.0f, 1.0f);
|
|
triUV[t].x = modTex.x;
|
|
triUV[t].y = modTex.y;
|
|
}
|
|
pInTangents[idx].GetTB(triTangents[0][t], triTangents[1][t]);
|
|
if (pInColors)
|
|
{
|
|
pInColors[idx].GetRGBA(triColor[t]), triColor[t] /= 255.0f;
|
|
}
|
|
else
|
|
{
|
|
triColor[t] = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
}
|
|
}
|
|
if (triPos[0] != triPos[1] && triPos[0] != triPos[2] && triPos[1] != triPos[2])
|
|
{
|
|
for (int ss = 0; ss < pOutputMesh->GetSubSetCount(); ss++)
|
|
{
|
|
const SMeshSubset& pSubSet = pOutput->GetSubSet(ss);
|
|
if (pSubSet.nMatID < m_numParams)
|
|
{
|
|
if (m_params[pSubSet.nMatID].bIgnore)
|
|
{
|
|
continue;
|
|
}
|
|
zRange.x = m_params[pSubSet.nMatID].rayLength;
|
|
zRange.y = m_params[pSubSet.nMatID].rayIndent;
|
|
}
|
|
else
|
|
{
|
|
zRange.x = 10.0f;
|
|
zRange.y = 0.5f;
|
|
}
|
|
zRange = bReverseDepth ? Vec4(-zRange.x, -zRange.y, zRange.z, zRange.w) : zRange;
|
|
|
|
if (i > 0)
|
|
{
|
|
CHWShader_D3D* pCurVS = (CHWShader_D3D*)sfm->m_VShader;
|
|
CHWShader_D3D* pCurPS = (CHWShader_D3D*)sfm->m_PShader;
|
|
|
|
pCurVS->UpdatePerBatchConstantBuffer();
|
|
pCurPS->UpdatePerBatchConstantBuffer();
|
|
}
|
|
rd->m_RP.m_pShader->FXSetVSFloat(triPosName, triPos, 3);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triPosName, triPos, 3);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triUVName, triUV, 3);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triZRange, &zRange, 1);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triBiNormName, triTangents[0], 3);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triTangName, triTangents[1], 3);
|
|
rd->m_RP.m_pShader->FXSetPSFloat(triColorName, triColor, 3);
|
|
rd->FX_Commit();
|
|
rd->FX_DrawPrimitive(eptTriangleList, pSubSet.nFirstIndexId, pSubSet.nNumIndices);
|
|
}
|
|
}
|
|
if ((i % 8) == 7)
|
|
{
|
|
if (!rd->m_pRT || rd->m_pRT->IsRenderThread())
|
|
{
|
|
// Send the commands to the GPU to make sure we don't timeout the driver
|
|
rd->GetDeviceContext().Flush();
|
|
Sleep(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Print a message every now and then to show we are still working.
|
|
if (gEnv->pTimer->GetAsyncCurTime() - textureBakeLoopTimer > 20.0f)
|
|
{
|
|
textureBakeLoopTimer = gEnv->pTimer->GetAsyncCurTime();
|
|
CryLog("LoD texture baker - Loop check\n");
|
|
}
|
|
}
|
|
|
|
// Release buffers once finished
|
|
vb0.Release();
|
|
vb1.Release();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
struct CompareRendItemMeshBaker
|
|
{
|
|
bool operator()(const SRendItem& a, const SRendItem& b) const
|
|
{
|
|
CShader* pShaderA, * pShaderB;
|
|
CShaderResources* pResA, * pResB;
|
|
int nTech;
|
|
SRendItem::mfGet(a.SortVal, nTech, pShaderA, pResA);
|
|
SRendItem::mfGet(b.SortVal, nTech, pShaderB, pResB);
|
|
|
|
if (pShaderA && pShaderB)
|
|
{
|
|
// sort decals to the end
|
|
if ((pShaderA->m_Flags & EF_DECAL) != (pShaderB->m_Flags & EF_DECAL))
|
|
{
|
|
return (pShaderA->m_Flags & EF_DECAL) < (pShaderB->m_Flags & EF_DECAL);
|
|
}
|
|
}
|
|
|
|
if (pResA && pResB)
|
|
{
|
|
if (pResA->IsTransparent() != pResB->IsTransparent())
|
|
{
|
|
return pResA->GetStrengthValue(EFTT_OPACITY) > pResB->GetStrengthValue(EFTT_OPACITY);
|
|
}
|
|
if (pResA->IsAlphaTested() != pResB->IsAlphaTested())
|
|
{
|
|
return pResA->GetAlphaRef() < pResB->GetAlphaRef();
|
|
}
|
|
}
|
|
|
|
int nNearA = (a.ObjSort & FOB_NEAREST);
|
|
int nNearB = (b.ObjSort & FOB_NEAREST);
|
|
if (nNearA != nNearB) // Sort by nearest flag
|
|
{
|
|
return nNearA > nNearB;
|
|
}
|
|
|
|
if (a.SortVal != b.SortVal) // Sort by shaders
|
|
{
|
|
return a.SortVal < b.SortVal;
|
|
}
|
|
|
|
if (a.pElem != b.pElem) // Sort by geometry
|
|
{
|
|
return a.pElem < b.pElem;
|
|
}
|
|
|
|
return (a.ObjSort & 0xFFFF) < (b.ObjSort & 0xFFFF); // Sort by distance
|
|
}
|
|
};
|
|
|
|
static void PatchShaderItemRecurse(_smart_ptr<IMaterial> pDst, _smart_ptr<IMaterial> pMat)
|
|
{
|
|
IMaterialManager* pMatMan = gEnv->p3DEngine->GetMaterialManager();
|
|
if (pMat && pDst && pMat != pMatMan->GetDefaultMaterial())
|
|
{
|
|
SShaderItem& siSrc(pMat->GetShaderItem());
|
|
if (siSrc.m_pShader)
|
|
{
|
|
SInputShaderResources isr(siSrc.m_pShaderResources);
|
|
SShaderItem siDst(gcpRendD3D->EF_LoadShaderItem("Illum.MeshBaker", false, 0, &isr, siSrc.m_pShader->GetGenerationMask()));
|
|
pDst->AssignShaderItem(siDst);
|
|
siDst.m_pShaderResources->UpdateConstants(siDst.m_pShader);
|
|
}
|
|
for (int i = 0; i < pMat->GetSubMtlCount(); i++)
|
|
{
|
|
_smart_ptr<IMaterial> pSubMat = pMat->GetSubMtl(i);
|
|
PatchShaderItemRecurse(pDst->GetSubMtl(i), pSubMat);
|
|
}
|
|
}
|
|
}
|
|
|
|
static _smart_ptr<IMaterial> PatchMaterial(_smart_ptr<IMaterial> pMat)
|
|
{
|
|
IMaterialManager* pMatMan = gEnv->p3DEngine->GetMaterialManager();
|
|
_smart_ptr<IMaterial> pResult = pMatMan->CloneMaterial(pMat);
|
|
|
|
PatchShaderItemRecurse(pResult, pMat);
|
|
|
|
return pResult;
|
|
}
|
|
|
|
static void EtchAlphas(std::vector<IIndexedMesh*> outputList, _smart_ptr<IMaterial> pMaterial, const SMeshBakingMaterialParams* params, int numParams)
|
|
{
|
|
CD3D9Renderer* const __restrict rd = gcpRendD3D;
|
|
|
|
if (outputList.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (std::vector<IIndexedMesh*>::iterator mit = outputList.begin(), mend = outputList.end(); mit != mend; ++mit)
|
|
{
|
|
IIndexedMesh* pOutput = *mit;
|
|
if (!pOutput)
|
|
{
|
|
continue;
|
|
}
|
|
int numOutputTriangles = pOutput->GetIndexCount() / 3;
|
|
CMesh* pOutputMesh = pOutput->GetMesh();
|
|
vtx_idx* pOutIndices = pOutputMesh->GetStreamPtr<vtx_idx>(CMesh::INDICES);
|
|
SMeshTexCoord* pOutTexCoords = pOutputMesh->GetStreamPtr<SMeshTexCoord>(CMesh::TEXCOORDS);
|
|
|
|
{
|
|
TempDynVB<SVF_P3F_T2F_T3F> vb(gRenDev);
|
|
vb.Allocate(numOutputTriangles * 3);
|
|
SVF_P3F_T2F_T3F* vInputs = vb.Lock();
|
|
|
|
for (int i = 0; i < numOutputTriangles * 3; i++)
|
|
{
|
|
SVF_P3F_T2F_T3F& v = vInputs[i];
|
|
const vtx_idx idx = pOutIndices[i];
|
|
const Vec2 uv = pOutTexCoords[idx].GetUV();
|
|
|
|
v.p.x = uv.x;
|
|
v.p.y = uv.y;
|
|
v.p.z = 0.0f;
|
|
v.st0.x = v.p.x;
|
|
v.st0.y = v.p.y;
|
|
}
|
|
|
|
vb.Unlock();
|
|
vb.Bind(VSF_GENERAL);
|
|
vb.Release();
|
|
}
|
|
|
|
if (!FAILED(rd->FX_SetVertexDeclaration(VSM_GENERAL, eVF_P3F_T2F_T3F)))
|
|
{
|
|
rd->FX_Commit();
|
|
for (int ss = 0; ss < pOutputMesh->GetSubSetCount(); ss++)
|
|
{
|
|
const SMeshSubset& pSubSet = pOutput->GetSubSet(ss);
|
|
if (pSubSet.nMatID < numParams && (params[pSubSet.nMatID].bAlphaCutout && !params[pSubSet.nMatID].bIgnore))
|
|
{
|
|
rd->FX_DrawPrimitive(eptTriangleList, pSubSet.nFirstIndexId, pSubSet.nNumIndices);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool Dilate(CTexture* pTex, CTexture* pOutput, int nPhase, std::vector<IIndexedMesh*> pInputIndexedMesh, _smart_ptr<IMaterial> pMaterial, const SMeshBakingMaterialParams* params, int numParams, SDepthTexture* pDepthStencil, const SMeshBakingInputParams* pInputParams)
|
|
{
|
|
CD3D9Renderer* const __restrict rd = gcpRendD3D;
|
|
PROFILE_LABEL_SCOPE("BakeMeshDilate");
|
|
static CCryNameR missColourName("MISSCOLOUR");
|
|
static CCryNameR tintColourName("TINTCOLOUR");
|
|
static CCryNameR pixSizeName("PIXSIZE");
|
|
static CCryNameTSCRC TechName = "MeshBakerDilate";
|
|
CShader* pSH = rd->m_cEF.mfForName("MeshBakerDilate", 0);
|
|
uint32 uvMapWidth = pTex->GetWidth();
|
|
uint32 uvMapHeight = pTex->GetHeight();
|
|
Vec4 pixSize = Vec4(1.0f / (float)uvMapWidth, 1.0f / (float)uvMapHeight, 0, 0);
|
|
const ColorF& inMissColour = pInputParams->dilateMagicColour;
|
|
Vec4 missColour = Vec4(inMissColour.r, inMissColour.g, inMissColour.b, inMissColour.a);
|
|
Vec4 whiteColour = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
uint32 extraPasses = 0;
|
|
uint32 nPasses = 0;
|
|
if (!pSH)
|
|
{
|
|
CryLog("BakeMesh: Dilate shader missing\n");
|
|
return false;
|
|
}
|
|
|
|
bool bAlphaCutout = false;
|
|
for (int i = 0; i < numParams; i++)
|
|
{
|
|
if (params[i].bAlphaCutout && !params[i].bIgnore)
|
|
{
|
|
bAlphaCutout = (nPhase == 0);
|
|
}
|
|
}
|
|
|
|
CTexture* pTemp = CTexture::CreateRenderTarget("MeshBaker_DilateTemp", uvMapWidth, uvMapHeight, Clr_Unknown, eTT_2D, FT_STATE_CLAMP, pTex->GetTextureDstFormat());
|
|
int TempX, TempY, TempWidth, TempHeight;
|
|
int nTexStateIdRepeat = CTexture::GetTexState(STexState(FILTER_TRILINEAR, false));
|
|
rd->GetViewport(&TempX, &TempY, &TempWidth, &TempHeight);
|
|
rd->RT_SetViewport(0, 0, uvMapWidth, uvMapHeight);
|
|
|
|
rd->FX_ResetPipe();
|
|
rd->D3DSetCull(eCULL_None);
|
|
pSH->FXSetTechnique(TechName);
|
|
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES | FEF_DONTSETTEXTURES);
|
|
|
|
const uint32 nPassDilateWithThresholdAlpha = 0;
|
|
const uint32 nPassDilate = 1;
|
|
const uint32 nPassDilateWithZeroAlpha = 2;
|
|
const uint32 nPassGammaCorrect = 3;
|
|
const uint32 nPassNormalCorrect = 4;
|
|
const uint32 nPassPassthrough = 5;
|
|
|
|
if (pInputParams->bDoDilationPass)
|
|
{
|
|
// Set miss colour wherever we missed
|
|
rd->FX_PushRenderTarget(0, pTex, pDepthStencil);
|
|
int nStencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_KEEP);
|
|
rd->FX_SetStencilState(nStencilState, 0, 0xFFFFFFFF, 0xFFFFFFFF);
|
|
rd->FX_SetState(GS_NODEPTHTEST | GS_STENCIL);
|
|
pSH->FXBeginPass(nPassPassthrough);
|
|
CTextureManager::Instance()->GetWhiteTexture()->Apply(0);
|
|
pSH->FXSetPSFloat(tintColourName, &missColour, 1);
|
|
rd->FX_Commit();
|
|
rd->DrawQuad(0.0f, 0.0f, 1.0f, 1.0f, ColorF(1, 1, 1, 1));
|
|
pSH->FXEndPass();
|
|
rd->FX_PopRenderTarget(0);
|
|
|
|
uint32 dilatePasses = max(uvMapWidth, uvMapHeight);
|
|
|
|
for (int p = 0; p < 2; p++)
|
|
{
|
|
if (p == 1 || (bAlphaCutout && nPhase == 0)) // If doing alpha cutout we need to dilate the alpha cutout sections first (so geometry doesn't dilate into alphaed areas)
|
|
{
|
|
for (uint32 i = 0; i < dilatePasses; i++) // Dilate as much as possible (make sure even number so result ends up in correct buffer)
|
|
{
|
|
rd->FX_PushRenderTarget(0, pTemp, pDepthStencil);
|
|
rd->FX_SetState(GS_NODEPTHTEST);
|
|
// Pass through all existing data
|
|
pSH->FXBeginPass(nPassPassthrough);
|
|
pTex->Apply(0);
|
|
rd->FX_Commit();
|
|
pSH->FXSetPSFloat(tintColourName, &whiteColour, 1);
|
|
rd->DrawQuad(0.0f, 0.0f, 1.0f, 1.0f, ColorF(1, 1, 1, 1));
|
|
// Dilate using stencil/magic colour to identify areas to dilate
|
|
if (nPhase == 0)
|
|
{
|
|
pSH->FXBeginPass(p ? nPassDilateWithThresholdAlpha : nPassDilateWithZeroAlpha);
|
|
}
|
|
else if (nPhase == 1)
|
|
{
|
|
pSH->FXBeginPass(p ? nPassDilate : nPassDilateWithZeroAlpha);
|
|
}
|
|
else
|
|
{
|
|
pSH->FXBeginPass(nPassDilateWithZeroAlpha);
|
|
}
|
|
pTex->Apply(0);
|
|
pSH->FXSetPSFloat(missColourName, &missColour, 1);
|
|
pSH->FXSetPSFloat(pixSizeName, &pixSize, 1);
|
|
nStencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_INCR);
|
|
rd->FX_SetStencilState(nStencilState, 0, 0xFFFFFFFF, 0xFFFFFFFF);
|
|
rd->FX_SetState(GS_NODEPTHTEST | GS_STENCIL);
|
|
if (p)
|
|
{
|
|
rd->DrawQuad(0.0f, 0.0f, 1.0f, 1.0f, ColorF(1, 1, 1, 1));
|
|
}
|
|
else
|
|
{
|
|
EtchAlphas(pInputIndexedMesh, pMaterial, params, numParams);
|
|
}
|
|
rd->FX_PopRenderTarget(0);
|
|
// ping pong
|
|
CTexture* tmp = pTex;
|
|
pTex = pTemp;
|
|
pTemp = tmp;
|
|
}
|
|
}
|
|
}
|
|
pSH->FXEndPass();
|
|
}
|
|
else if (bAlphaCutout)
|
|
{
|
|
// not doing dilate pass but still show alpha
|
|
Vec4 zeroAlpha(1, 1, 1, 0);
|
|
rd->FX_PushRenderTarget(0, pTex, pDepthStencil);
|
|
int nStencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_KEEP);
|
|
rd->FX_SetStencilState(nStencilState, 0, 0xFFFFFFFF, 0xFFFFFFFF);
|
|
rd->FX_SetState(GS_NODEPTHTEST | GS_STENCIL | GS_COLMASK_A);
|
|
pSH->FXBeginPass(nPassPassthrough);
|
|
CTextureManager::Instance()->GetWhiteTexture()->Apply(0);
|
|
pSH->FXSetPSFloat(tintColourName, &zeroAlpha, 1);
|
|
rd->FX_Commit();
|
|
EtchAlphas(pInputIndexedMesh, pMaterial, params, numParams);
|
|
pSH->FXEndPass();
|
|
rd->FX_PopRenderTarget(0);
|
|
}
|
|
rd->FX_SetState(GS_NODEPTHTEST);
|
|
if (pOutput) // Fix SRGB/Flipped normals problems
|
|
{
|
|
pSH->FXBeginPass((nPhase == 1) ? nPassNormalCorrect : nPassGammaCorrect);
|
|
rd->FX_PushRenderTarget(0, pOutput, NULL);
|
|
pTex->Apply(0);
|
|
rd->FX_Commit();
|
|
rd->DrawQuad(0.0f, 0.0f, 1.0f, 1.0f, ColorF(1, 1, 1, 1));
|
|
rd->FX_PopRenderTarget(0);
|
|
pSH->FXEndPass();
|
|
}
|
|
pSH->FXEnd();
|
|
rd->RT_SetViewport(TempX, TempY, TempWidth, TempHeight);
|
|
rd->FX_SetState(0);
|
|
rd->FX_Commit();
|
|
rd->FX_ResetPipe();
|
|
pTemp->Release();
|
|
pSH->Release();
|
|
return true;
|
|
}
|
|
|
|
static bool IsRenderableSubObject(IStatObj* obj, int child)
|
|
{
|
|
return obj->GetSubObject(child)->nType == STATIC_SUB_OBJECT_MESH &&
|
|
obj->GetSubObject(child)->pStatObj != NULL &&
|
|
obj->GetSubObject(child)->pStatObj->GetRenderMesh() != NULL;
|
|
}
|
|
|
|
bool CD3D9Renderer::BakeMesh([[maybe_unused]] const SMeshBakingInputParams* pInputParams, [[maybe_unused]] SMeshBakingOutput* pReturnValues)
|
|
{
|
|
#if defined(WIN64) || defined(WIN32) || defined(APPLE) || defined(LINUX)
|
|
if (gEnv->IsEditor())
|
|
{
|
|
std::vector<IRenderMesh*> pRM;
|
|
std::vector<_smart_ptr<IMaterial> > pInputMaterial;
|
|
std::vector<CMesh*> pInputMesh;
|
|
std::vector<IIndexedMesh*> pOutputMesh;
|
|
_smart_ptr<IMaterial> pOutputMaterial;
|
|
int outputWidth = pInputParams->outputTextureWidth;
|
|
int outputHeight = pInputParams->outputTextureHeight;
|
|
int cachedShaderCompileCvar = CRenderer::CV_r_shadersasynccompiling;
|
|
|
|
if (pInputParams->pInputMesh)
|
|
{
|
|
IStatObj* obj = pInputParams->pInputMesh;
|
|
if (obj->GetRenderMesh() == NULL)
|
|
{
|
|
if (obj->GetSubObjectCount() == 0)
|
|
{
|
|
CryLog("BakeMesh: Failed due to input mesh having no rendermesh and no subobjects\n");
|
|
return false;
|
|
}
|
|
for (int i = 0; i < obj->GetSubObjectCount(); i++)
|
|
{
|
|
if (IsRenderableSubObject(obj, i))
|
|
{
|
|
IStatObj* pObj = obj->GetSubObject(i)->pStatObj;
|
|
pRM.push_back(pObj->GetRenderMesh());
|
|
pInputMaterial.push_back(pInputParams->pMaterial ? pInputParams->pMaterial : pObj->GetMaterial());
|
|
pInputMesh.push_back(pObj->GetIndexedMesh(true)->GetMesh());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRM.push_back(obj->GetRenderMesh());
|
|
pInputMaterial.push_back(pInputParams->pMaterial ? pInputParams->pMaterial : obj->GetMaterial());
|
|
pInputMesh.push_back(obj->GetIndexedMesh(true)->GetMesh());
|
|
}
|
|
}
|
|
|
|
// HACK TO GET STREAMING SYSTEM TO MAKE SURE USED TEXTURES ARE STREAMED IN
|
|
gEnv->p3DEngine->ProposeContentPrecache();
|
|
// gEnv->p3DEngine->UpdateStreaming(SRenderingPassInfo::CreateGeneralPassRenderingInfo(gEnv->pSystem->GetViewCamera()));
|
|
for (std::vector<_smart_ptr<IMaterial> >::iterator it = pInputMaterial.begin(), end = pInputMaterial.end(); it != end; ++it)
|
|
{
|
|
float start = gEnv->pTimer->GetAsyncCurTime();
|
|
while (true)
|
|
{
|
|
int pRoundIds[MAX_STREAM_PREDICTION_ZONES] = {0};
|
|
(*it)->PrecacheMaterial(0.0f, NULL, true, false);
|
|
(*it)->PrecacheMaterial(0.0f, NULL, false, false);
|
|
CTexture::Update();
|
|
gEnv->pSystem->GetStreamEngine()->Update();
|
|
if ((*it)->IsStreamedIn(pRoundIds, NULL))
|
|
{
|
|
break;
|
|
}
|
|
if (gEnv->pTimer->GetAsyncCurTime() - start > 5.0f)
|
|
{
|
|
LogWarning("Time out waiting for textures to stream\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pRM.empty())
|
|
{
|
|
CryLog("BakeMesh: Failed due to no inputs\n");
|
|
return false;
|
|
}
|
|
|
|
if (pInputParams->pCageMesh)
|
|
{
|
|
IStatObj* obj = pInputParams->pCageMesh;
|
|
|
|
if (obj->GetRenderMesh() == NULL)
|
|
{
|
|
if (obj->GetSubObjectCount() == 0)
|
|
{
|
|
CryLog("BakeMesh: Failed due to cage mesh having no rendermesh and no subobjects\n");
|
|
return false;
|
|
}
|
|
for (int i = 0; i < obj->GetSubObjectCount(); i++)
|
|
{
|
|
if (IsRenderableSubObject(obj, i))
|
|
{
|
|
IStatObj* subobj = obj->GetSubObject(i)->pStatObj;
|
|
pOutputMesh.push_back(subobj->GetIndexedMesh(true));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pOutputMesh.push_back(obj->GetIndexedMesh(true));
|
|
}
|
|
pOutputMaterial = obj->GetMaterial();
|
|
}
|
|
else
|
|
{
|
|
CryLog("BakeMesh: Failed due to no low poly cage\n");
|
|
return false;
|
|
}
|
|
|
|
CRenderer::CV_r_shadersasynccompiling = 0;
|
|
|
|
std::vector<_smart_ptr<IMaterial> > pBakeMaterial;
|
|
pBakeMaterial.reserve(pInputMaterial.size());
|
|
for (std::vector<_smart_ptr<IMaterial> >::iterator it = pInputMaterial.begin(), end = pInputMaterial.end(); it != end; ++it)
|
|
{
|
|
pBakeMaterial.push_back(PatchMaterial(*it)); // Replace current shader with MeshBake
|
|
}
|
|
|
|
SDepthTexture* pTmpDepthSurface = FX_GetDepthSurface(outputWidth, outputHeight, false);
|
|
if (!pTmpDepthSurface)
|
|
{
|
|
CryLog("BakeMesh: Failed as temporary depth surface could not be created of size %dx%d\n", outputWidth, outputHeight);
|
|
CRenderer::CV_r_shadersasynccompiling = cachedShaderCompileCvar;
|
|
return false;
|
|
}
|
|
CTexture* pHighPrecisionBuffer[3], * pOutputBuffer[3];
|
|
|
|
PROFILE_LABEL_SCOPE("BakeMesh");
|
|
|
|
SRenderingPassInfo passInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(gEnv->p3DEngine->GetRenderingCamera());
|
|
|
|
if (m_RP.m_pRLD == NULL)
|
|
{
|
|
const int recursiveLevel = SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID];
|
|
m_RP.m_pRLD = &m_RP.m_pRenderViews[m_RP.m_nProcessThreadID]->m_RenderListDesc[recursiveLevel];
|
|
}
|
|
|
|
bool bAlphaCutout = false;
|
|
for (int i = 0; i < pInputParams->numMaterialParams; i++)
|
|
{
|
|
if (pInputParams->pMaterialParams[i].bAlphaCutout && !pInputParams->pMaterialParams[i].bIgnore)
|
|
{
|
|
bAlphaCutout = true;
|
|
}
|
|
}
|
|
|
|
for (int nPhase = 0; nPhase < 3; nPhase++)
|
|
{
|
|
const bool bReverseDepth = !!(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH);
|
|
ColorF Clr_Phase;
|
|
switch (nPhase)
|
|
{
|
|
case 0:
|
|
Clr_Phase = pInputParams->defaultBackgroundColour;
|
|
break;
|
|
case 1:
|
|
Clr_Phase = ColorF(0.5f, 0.5f, 1.0f, 1.0f);
|
|
break;
|
|
default:
|
|
Clr_Phase = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
|
|
}
|
|
|
|
char uniqueName[128];
|
|
const char* suffix[3] = {"Albedo", "Normal", "Refl"};
|
|
sprintf_s(uniqueName, sizeof(uniqueName), "MeshBaker_16Bit%s_%d%s", suffix[nPhase], pInputParams->nLodId, bAlphaCutout ? "_alpha" : "");
|
|
pHighPrecisionBuffer[nPhase] = CTexture::CreateRenderTarget(uniqueName, outputWidth, outputHeight, Clr_Unknown, eTT_2D, FT_STATE_CLAMP, eTF_R16G16B16A16F /*, -1, 95*/);
|
|
sprintf_s(uniqueName, sizeof(uniqueName), "MeshBaker_8Bit%s_%d%s", suffix[nPhase], pInputParams->nLodId, bAlphaCutout ? "_alpha" : "");
|
|
pOutputBuffer[nPhase] = CTexture::CreateRenderTarget(uniqueName, outputWidth, outputHeight, Clr_Unknown, eTT_2D, FT_STATE_CLAMP, eTF_R8G8B8A8 /*, -1, 95*/);
|
|
|
|
PROFILE_LABEL_SCOPE(suffix[nPhase]);
|
|
|
|
FX_ResetPipe();
|
|
FX_ClearTarget(pHighPrecisionBuffer[nPhase], Clr_Phase);
|
|
FX_ClearTarget(pTmpDepthSurface, CLEAR_ZBUFFER | CLEAR_STENCIL, Clr_FarPlane_R.r, 0);
|
|
FX_PushRenderTarget(0, pHighPrecisionBuffer[nPhase], pTmpDepthSurface);
|
|
RT_SetViewport(0, 0, outputWidth, outputHeight);
|
|
|
|
int nThreadID = m_pRT->GetThreadList();
|
|
SRendItem::m_RecurseLevel[nThreadID]++;
|
|
FX_PreRender(3);
|
|
|
|
SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
|
|
rRP.m_pRenderFunc = FX_FlushShader_General;
|
|
rRP.m_nPassGroupID = EFSLIST_GENERAL;
|
|
rRP.m_nPassGroupDIP = rRP.m_nPassGroupID;
|
|
rRP.m_nSortGroupID = 0;
|
|
FX_StartBatching();
|
|
rRP.m_nBatchFilter = FB_GENERAL;
|
|
|
|
int numChunks = 0;
|
|
for (int m = 0; m < pRM.size(); m++)
|
|
{
|
|
TRenderChunkArray& chunkList = pRM[m]->GetChunks();
|
|
numChunks += chunkList.size();
|
|
}
|
|
|
|
std::vector<CRenderObject*> pObjs;
|
|
SRendItem* ri = new SRendItem[numChunks];
|
|
numChunks = 0;
|
|
for (int m = 0; m < pRM.size(); m++)
|
|
{
|
|
TRenderChunkArray& chunkList = pRM[m]->GetChunks();
|
|
|
|
CRenderObject* pObj = aznew CRenderObject();
|
|
pObj->Init();
|
|
pObj->m_II.m_Matrix.SetIdentity();
|
|
pObj->m_II.m_Matrix.SetTranslationMat(GetCamera().GetPosition());
|
|
pObj->m_ObjFlags = 0;
|
|
pObj->m_II.m_AmbColor = Col_White;
|
|
pObj->m_nSort = 0;
|
|
pObj->m_ObjFlags |= FOB_NO_FOG | ((!pInputMesh[m]) ? FOB_SKINNED : 0);
|
|
pObj->m_pCurrMaterial = pBakeMaterial[m];
|
|
pObjs.push_back(pObj);
|
|
for (int i = 0; i < chunkList.size(); i++)
|
|
{
|
|
CRenderChunk* pChunk = &chunkList[i];
|
|
SShaderItem& pSH = pBakeMaterial[m]->GetShaderItem(pChunk->m_nMatID);
|
|
CShaderResources* pR = (CShaderResources*)pSH.m_pShaderResources;
|
|
CShader* __restrict pShader = (CShader*)pSH.m_pShader;
|
|
CREMesh* pRE = pChunk->pRE;
|
|
|
|
if (pShader->m_Flags & EF_DECAL)
|
|
{
|
|
const bool bHasDiffuse = pR ? pR->TextureSlotExists((uint16)EFTT_DIFFUSE) : false;
|
|
const bool bHasNormal = pR ? pR->TextureSlotExists((uint16)EFTT_NORMALS) : false;
|
|
const bool bHasGloss = pR ? pR->TextureSlotExists((uint16)EFTT_SMOOTHNESS) : false;
|
|
|
|
// emulate gbuffer blend masking (since we don't MRT, this won't work correctly
|
|
// in the normal pipeline)
|
|
|
|
if (!bHasDiffuse && nPhase == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (!bHasNormal && nPhase == 1)
|
|
{
|
|
continue;
|
|
}
|
|
if (!bHasGloss && nPhase == 2)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ri[numChunks].pObj = pObj;
|
|
ri[numChunks].nOcclQuery = m; // Stash in this in something that doesn't effect sorting
|
|
ri[numChunks].ObjSort = (pObj->m_ObjFlags & 0xffff0000) | pObj->m_nSort;
|
|
int nThreadID2 = m_RP.m_nProcessThreadID;
|
|
ri[numChunks].nBatchFlags = EF_BatchFlags(pSH, pObj, pRE, passInfo); // naughty
|
|
ri[numChunks].nStencRef = pObj->m_nClipVolumeStencilRef;
|
|
uint32 nResID = pR ? pR->m_Id : 0;
|
|
ri[numChunks].SortVal = (nResID << 18) | (pShader->mfGetID() << 6) | (pSH.m_nTechnique & 0x3f);
|
|
ri[numChunks].pElem = pRE;
|
|
numChunks++;
|
|
}
|
|
}
|
|
|
|
std::sort(ri, ri + numChunks, CompareRendItemMeshBaker());
|
|
|
|
for (int i = 0; i < numChunks; i++)
|
|
{
|
|
CShader* pShader;
|
|
CShaderResources* pRes;
|
|
int nTech;
|
|
SRendItem::mfGet(ri[i].SortVal, nTech, pShader, pRes);
|
|
if (pShader)
|
|
{
|
|
int m = ri[i].nOcclQuery;
|
|
ri[i].nOcclQuery = SRendItem::kOcclQueryInvalid;
|
|
CREBaker wrappedRE(ri[i].pElem, pInputMesh[m], pOutputMesh, nPhase, pInputParams->pMaterialParams, pInputParams->numMaterialParams, pInputParams->bSmoothNormals);
|
|
ri[i].pElem = &wrappedRE;
|
|
FX_ObjectChange(pShader, pRes, ri[i].pObj, &wrappedRE);
|
|
FX_Start(pShader, nTech, pRes, &wrappedRE);
|
|
wrappedRE.mfPrepare(true);
|
|
rRP.m_RIs[0].AddElem(&ri[i]);
|
|
FX_FlushShader_General();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < pObjs.size(); i++)
|
|
{
|
|
delete pObjs[i];
|
|
}
|
|
delete[] ri;
|
|
|
|
FX_PostRender();
|
|
|
|
SRendItem::m_RecurseLevel[nThreadID]--;
|
|
|
|
FX_PopRenderTarget(0);
|
|
|
|
Dilate(pHighPrecisionBuffer[nPhase], pOutputBuffer[nPhase], nPhase, pOutputMesh, pOutputMaterial, pInputParams->pMaterialParams, pInputParams->numMaterialParams, pTmpDepthSurface, pInputParams);
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (i == 2 && !pInputParams->bSaveSpecular)
|
|
{
|
|
SAFE_RELEASE(pOutputBuffer[i]);
|
|
pReturnValues->ppOuputTexture[i] = NULL;
|
|
|
|
SAFE_RELEASE(pHighPrecisionBuffer[i]);
|
|
pReturnValues->ppIntermediateTexture[i] = NULL;
|
|
continue;
|
|
}
|
|
|
|
pOutputBuffer[i]->GetDevTexture()->DownloadToStagingResource(0);
|
|
pReturnValues->ppOuputTexture[i] = pOutputBuffer[i];
|
|
pReturnValues->ppIntermediateTexture[i] = pHighPrecisionBuffer[i];
|
|
}
|
|
|
|
CRenderer::CV_r_shadersasynccompiling = cachedShaderCompileCvar;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "BakeMesh: Only exists within editor\n");
|
|
return false;
|
|
}
|
|
}
|