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/Common/DeferredRenderUtils.cpp

649 lines
19 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 "ShadowUtils.h"
#include "DeferredRenderUtils.h"
void CDeferredRenderUtils::CreateUnitFrustumMesh(int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//////////////////////////////////////////////////////////////////////////
// Geometry generating
//////////////////////////////////////////////////////////////////////////
int32 nBaseVertexIndex = 0;
indBuff.clear();
indBuff.reserve(indBuff.size() + (tessx * tessy - 1) * 6); //TOFIX: correct number of indices
vertBuff.clear();
vertBuff.reserve(nBaseVertexIndex + tessx * tessy);
float pViewport[4] = {0.0f, 0.0f, 1.0f, 1.0f};
float fViewportMinZ = 0.0f;
float fViewportMaxZ = 1.0f;
float szx = 1.0f;
float szy = 1.0f;
float deltax = szx / (tessx - 1.0f);
float deltay = szy / (tessy - 1.0f);
SVF_P3F_C4B_T2F vert;
Vec3 tri_vert;
Vec3 a;
Vec3 vPos;
//generate tessellation for far plane
a.z = 1.0f;
for (int i = 0; i < tessy; i++)
{
for (int j = 0; j < tessx; j++)
{
a.x = j * deltax;
a.y = i * deltay;
//pre-transform viewport transform vertices in static mesh
vPos.x = (a.x - pViewport[0]) * 2.0f / pViewport[2] - 1.0f;
vPos.y = 1.0f - ((a.y - pViewport[1]) * 2.0f / pViewport[3]); //flip coords for y axis
vPos.z = (a.z - fViewportMinZ) / (fViewportMaxZ - fViewportMinZ);
vert.xyz = vPos;
vert.st = Vec2(1.0f, 1.0f); //valid extraction
vertBuff.push_back(vert);
}
}
//push light origin
vert.xyz = Vec3(0, 0, 0);
vert.st = Vec2(0.0f, 0.0f); //do not extract
vertBuff.push_back(vert);
//init indices for triangles drawing
for (int i = 0; i < tessy - 1; i++)
{
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)(i * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
}
}
//Additional faces
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)((tessy - 1) * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)((tessy - 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(j + nBaseVertexIndex));
indBuff.push_back((uint16)(j + 1 + nBaseVertexIndex));
}
for (int i = 0; i < tessy - 1; i++)
{
indBuff.push_back((uint16)((i + 1) * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(i * tessx + (tessx - 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (tessx - 1) + nBaseVertexIndex));
}
}
//push rectangle mesh
void CDeferredRenderUtils::CreateUnitFrustumMeshTransformed(SRenderLight* pLight, ShadowMapFrustum* pFrustum, int nAxis, int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//assert(pFrustum!=NULL);
assert(pLight != NULL);
Vec3& vLightPos = pLight->m_Origin;
f32 fLightRadius = pLight->m_fRadius;
int32 pViewport[4] = {0, 0, 1, 1};
Matrix44A mProjection;
Matrix44A mView;
if (pFrustum == NULL)
{
//for light source
CShadowUtils::GetCubemapFrustumForLight(pLight, nAxis, g_fOmniLightFov /*pLight->m_fLightFrustumAngle*/ + 3.0f, &mProjection, &mView, false); // 3.0f - offset to make sure that frustums are intersected
}
else
{
if (!pFrustum->bOmniDirectionalShadow)
{
//temporarily disabled since mLightProjMatrix contains pre-multiplied matrix already
//pmProjection = &(pFrustum->mLightProjMatrix);
mProjection = gRenDev->m_IdentityMatrix;
mView = pFrustum->mLightViewMatrix;
}
else
{
//calc one of cubemap's frustums
Matrix33 mRot = (Matrix33(pLight->m_ObjMatrix));
//rotation for shadow frustums is disabled
CShadowUtils::GetCubemapFrustum(FTYP_OMNILIGHTVOLUME, pFrustum, nAxis, &mProjection, &mView /*, &mRot*/);
}
}
//////////////////////////////////////////////////////////////////////////
// Geometry generating
//////////////////////////////////////////////////////////////////////////
//add geometry to the existing one
int32 nBaseVertexIndex = vertBuff.size();
indBuff.clear();
indBuff.reserve(indBuff.size() + (tessx * tessy - 1) * 6); //TOFIX: correct number of indices
vertBuff.clear();
vertBuff.reserve(nBaseVertexIndex + tessx * tessy);
float szx = 1.0f;
float szy = 1.0f;
float deltax = szx / (tessx - 1);
float deltay = szy / (tessy - 1);
SVF_P3F_C4B_T2F vert;
Vec3 tri_vert;
Vec3 a;
//generate tessellation for far plane
a.z = 1.0f;
for (int i = 0; i < tessy; i++)
{
for (int j = 0; j < tessx; j++)
{
a.x = j * deltax;
a.y = i * deltay;
// A
mathVec3UnProject(&tri_vert, &a, pViewport, &mProjection, &mView, &gRenDev->m_IdentityMatrix, g_CpuFlags);
//calc vertex expansion in world space coords
Vec3 vLightDir = tri_vert - vLightPos;
vLightDir.Normalize();
vLightDir.SetLength(fLightRadius * 1.05f);
vert.xyz = vLightPos + vLightDir;
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
}
}
//push light origin
vert.xyz = vLightPos;
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
//init indices for triangles drawing
for (int i = 0; i < tessy - 1; i++)
{
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)(i * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
}
}
//Additional faces
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)((tessy - 1) * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)((tessy - 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(j + nBaseVertexIndex));
indBuff.push_back((uint16)(j + 1 + nBaseVertexIndex));
}
for (int i = 0; i < tessy - 1; i++)
{
indBuff.push_back((uint16)((i + 1) * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(i * tessx + (tessx - 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (tessx - 1) + nBaseVertexIndex));
}
}
//////////////////////////////////////////////////////////////////////////
// Approximate with 8 vertices
//////////////////////////////////////////////////////////////////////////
void CreateSimpleLightFrustumMeshTransformed(ShadowMapFrustum* pFrustum, int nFrustNum, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//SVF_P3F_T2F_T3F
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
assert(pFrustum != NULL);
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
//first vertex for cone
//vert.xyz = Vec3(0.0f, 0.0f, 0.0f);
//vert.st = Vec2(0.0f, 0.0f);
//vertBuff.push_back(vert);
int32 pViewport[4] = {0, 0, 1, 1};
Matrix44A* pmProjection;
Matrix44A* pmView;
Matrix44A mProjectionCM;
Matrix44A mViewCM;
if (!pFrustum->bOmniDirectionalShadow)
{
//temporarily disabled since mLightProjMatrix contains pre-multiplied matrix already
//pmProjection = &(pFrustum->mLightProjMatrix);
pmProjection = &gRenDev->m_IdentityMatrix;
pmView = &(pFrustum->mLightViewMatrix);
}
else
{
//calc one of cubemap's frustums
CShadowUtils::GetCubemapFrustum(FTYP_OMNILIGHTVOLUME, pFrustum, nFrustNum, &mProjectionCM, &mViewCM);
pmProjection = &mProjectionCM;
pmView = &mViewCM;
}
//Create frustum
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
vNDC = Vec3((i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f
);
//TD: convert math functions to column ordered matrices
Vec3 pvObj(vert.xyz);
mathVec3UnProject(&pvObj, &vNDC, pViewport, pmProjection, pmView, &gRenDev->m_IdentityMatrix, g_CpuFlags);
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
}
//CCW faces
static uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
//Sphere light volumes
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::SphereTessR(Vec3& v0, Vec3& v1, Vec3& v2, int depth, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
if (depth == 0)
{
SVF_P3F_C4B_T2F vert;
int nVertCount = vertBuff.size();
vert.st = Vec2(0.0f, 0.0f);
vert.xyz = v0;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = v1;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = v2;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
}
else
{
Vec3 v01, v12, v02;
v01 = (v0 + v1).GetNormalized();
v12 = (v1 + v2).GetNormalized();
v02 = (v0 + v2).GetNormalized();
SphereTessR(v0, v01, v02, depth - 1, indBuff, vertBuff);
SphereTessR(v01, v1, v12, depth - 1, indBuff, vertBuff);
SphereTessR(v12, v02, v01, depth - 1, indBuff, vertBuff);
SphereTessR(v12, v2, v02, depth - 1, indBuff, vertBuff);
}
}
void CDeferredRenderUtils::SphereTess(Vec3& v0, Vec3& v1, Vec3& v2, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
int depth;
Vec3 w0, w1, w2;
int i, j, k;
SVF_P3F_C4B_T2F vert;
vert.st = Vec2(0.0f, 0.0f);
int nVertCount = vertBuff.size();
depth = 2;
for (i = 0; i < depth; i++)
{
for (j = 0; i + j < depth; j++)
{
k = depth - i - j;
{
w0 = (i * v0 + j * v1 + k * v2) / depth;
w1 = ((i + 1) * v0 + j * v1 + (k - 1) * v2)
/ depth;
w2 = (i * v0 + (j + 1) * v1 + (k - 1) * v2)
/ depth;
}
w0.Normalize();
w1.Normalize();
w2.Normalize();
vert.xyz = w1;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = w0;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = w2;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
}
}
}
#define X .525731112119133606f
#define Z .850650808352039932f
void CDeferredRenderUtils::CreateUnitSphere(int rec, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
static Vec3 verts[12] =
{
Vec3(-X, 0, Z),
Vec3(X, 0, Z),
Vec3(-X, 0, -Z),
Vec3(X, 0, -Z),
Vec3(0, Z, X),
Vec3(0, Z, -X),
Vec3(0, -Z, X),
Vec3(0, -Z, -X),
Vec3(Z, X, 0),
Vec3(-Z, X, 0),
Vec3(Z, -X, 0),
Vec3(-Z, -X, 0)
};
static int indices[20][3] =
{
{0, 4, 1},
{0, 9, 4},
{9, 5, 4},
{4, 5, 8},
{4, 8, 1},
{8, 10, 1},
{8, 3, 10},
{5, 3, 8},
{5, 2, 3},
{2, 7, 3},
{7, 10, 3},
{7, 6, 10},
{7, 11, 6},
{11, 0, 6},
{0, 1, 6},
{6, 1, 10},
{9, 0, 11},
{9, 11, 2},
{9, 2, 5},
{7, 2, 11},
};
indBuff.clear();
vertBuff.clear();
SVF_P3F_C4B_T2F vert;
vert.st = Vec2(0.0f, 0.0f);
//debug
/*for(int i=0; i<12; i++)
{
vert.xyz = verts[i];
vertBuff.push_back(vert);
}
for (int i = 19; i >= 0; i--)
{
indBuff.push_back( (uint16)indices[i][2] );
indBuff.push_back( (uint16)indices[i][1] );
indBuff.push_back( (uint16)indices[i][0] );
}*/
for (int i = 19; i >= 0; i--)
{
Vec3& v0 = verts[indices[i][2]];
Vec3& v1 = verts[indices[i][1]];
Vec3& v2 = verts[indices[i][0]];
//SphereTess(v0, v1, v2, indBuff, vertBuff);
SphereTessR(v0, v1, v2, rec, indBuff, vertBuff);
}
}
#undef X
#undef Z
void CDeferredRenderUtils::CreateUnitBox(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
//Create unit box
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
vNDC = Vec3((i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f
);
vert.xyz = vNDC;
vert.st = Vec2(0.0f, 0.0f);
vert.color.dcolor = -1;
vertBuff.push_back(vert);
}
//CCW faces
uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
// Approximate with 8 vertices
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::CreateSimpleLightFrustumMesh(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//SVF_P3F_T2F_T3F
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
int32 pViewport[4] = {0, 0, 1, 1};
float fViewportMinZ = 0.0f, fViewportMaxZ = 1.0f;
Matrix44A mProjectionCM;
Matrix44A mViewCM;
Vec3 vPos;
//Create frustum
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
//vNDC = Vec3((i==0 || i==3 || i==4 || i==7) ? 0.0f : 1.0f,
// (i==0 || i==1 || i==4 || i==5) ? 0.0f : 1.0f,
// (i==0 || i==1 || i==2 || i==3) ? 0.0f : 1.0f
// );
vNDC = Vec3((i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f);
//pre-transform viewport transform vertices in static mesh
vPos.x = (vNDC.x - pViewport[0]) * 2.0f / pViewport[2] - 1.0f;
vPos.y = 1.0f - ((vNDC.y - pViewport[1]) * 2.0f / pViewport[3]); //flip coords for y axis
vPos.z = (vNDC.z - fViewportMinZ) / (fViewportMaxZ - fViewportMinZ);
vert.xyz = vPos;
vert.st = Vec2(1.0f, 1.0f); //valid extraction
vertBuff.push_back(vert);
}
//CCW faces
static uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
//FS quad
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::CreateQuad(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
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) },
};
vertBuff.clear();
vertBuff.reserve(4);
vertBuff.push_back(pScreenQuad[0]);
vertBuff.push_back(pScreenQuad[1]);
vertBuff.push_back(pScreenQuad[2]);
vertBuff.push_back(pScreenQuad[3]);
indBuff.clear();
}