1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 // -------------------------------------------------------------------------
4 // File name: decals.cpp
6 // Created: 28/5/2001 by Vladimir Kajalin
7 // Compilers: Visual Studio.NET
8 // Description: draw, create decals on the world
9 // -------------------------------------------------------------------------
12 ////////////////////////////////////////////////////////////////////////////
16 #include "DecalManager.h"
19 #include "Vegetation.h"
22 IGeometry
* CDecal::s_pSphere
= 0;
24 void CDecal::ResetStaticData()
26 SAFE_RELEASE(s_pSphere
);
29 int CDecal::Update(bool& active
, const float fFrameTime
)
31 // process life time and disable decal when needed
32 m_fLifeTime
-= fFrameTime
;
39 else if (m_ownerInfo
.pRenderNode
&& m_ownerInfo
.pRenderNode
->m_nInternalFlags
& IRenderNode::UPDATE_DECALS
)
47 Vec3
CDecal::GetWorldPosition()
51 if (m_ownerInfo
.pRenderNode
)
53 if (m_eDecalType
== eDecalType_OS_SimpleQuad
|| m_eDecalType
== eDecalType_OS_OwnersVerticesUsed
)
55 assert(m_ownerInfo
.pRenderNode
);
56 if (m_ownerInfo
.pRenderNode
)
59 if (m_ownerInfo
.GetOwner(objMat
) != nullptr)
60 vPos
= objMat
.TransformPoint(vPos
);
68 void CDecal::Render(const float fCurTime
, int nAfterWater
, float fDistanceFading
, float fDistance
, const SRenderingPassInfo
& passInfo
)
70 FUNCTION_PROFILER_3DENGINE
;
72 if (!m_pMaterial
|| !m_pMaterial
->GetShaderItem().m_pShader
|| m_pMaterial
->GetShaderItem().m_pShader
->GetShaderType() != eST_General
)
73 return; // shader not supported for decals
75 // Get decal alpha from life time
76 float fAlpha
= m_fLifeTime
* 2;
83 fAlpha
*= fDistanceFading
;
87 fSizeK
= min(1.f
, sqrt_tpl((fCurTime
- m_fLifeBeginTime
) / m_fGrowTime
));
93 fSizeAlphaK
= min(1.f
, sqrt_tpl((fCurTime
- m_fLifeBeginTime
) / m_fGrowTimeAlpha
));
99 SDeferredDecal newItem
;
100 newItem
.fAlpha
= fAlpha
;
101 newItem
.pMaterial
= m_pMaterial
;
102 newItem
.nSortOrder
= m_sortPrio
;
105 Vec3 vRight
, vUp
, vNorm
;
108 if (m_ownerInfo
.GetOwner(objMat
) != nullptr)
110 vRight
= objMat
.TransformVector(m_vRight
* m_fSize
);
111 vUp
= objMat
.TransformVector(m_vUp
* m_fSize
);
112 vNorm
= objMat
.TransformVector((Vec3(m_vRight
).Cross(m_vUp
)) * m_fSize
);
116 vRight
= (m_vRight
* m_fSize
);
117 vUp
= (m_vUp
* m_fSize
);
118 vNorm
= ((Vec3(m_vRight
).Cross(m_vUp
)) * m_fSize
);
121 Matrix33 matRotation
;
122 matRotation
.SetColumn(0, vRight
);
123 matRotation
.SetColumn(1, vUp
);
124 matRotation
.SetColumn(2, vNorm
* GetFloatCVar(e_DecalsDeferredDynamicDepthScale
));
125 newItem
.projMatrix
.SetRotation33(matRotation
);
126 newItem
.projMatrix
.SetTranslation(m_vWSPos
+ vNorm
* .1f
* m_fWSSize
);
128 if (m_fGrowTimeAlpha
)
129 newItem
.fGrowAlphaRef
= max(.02f
, 1.f
- fSizeAlphaK
);
131 newItem
.fGrowAlphaRef
= 0;
133 GetRenderer()->EF_AddDeferredDecal(newItem
, passInfo
);
137 switch (m_eDecalType
)
139 case eDecalType_WS_Merged
:
140 case eDecalType_OS_OwnersVerticesUsed
:
142 // check if owner mesh was deleted
143 if (m_pRenderMesh
&& (m_pRenderMesh
->GetVertexContainer() == m_pRenderMesh
) && m_pRenderMesh
->GetVerticesCount() < 3)
149 // setup transformation
150 CRenderObject
* pObj
= passInfo
.GetIRenderView()->AllocateTemporaryRenderObject();
157 if (m_ownerInfo
.pRenderNode
&& !m_ownerInfo
.GetOwner(objMat
))
162 else if (!m_ownerInfo
.pRenderNode
)
164 objMat
.SetIdentity();
165 if (m_eDecalType
== eDecalType_WS_Merged
)
167 objMat
.SetTranslation(m_vPos
);
168 pObj
->m_ObjFlags
|= FOB_TRANS_MASK
;
172 pObj
->SetMatrix(objMat
, passInfo
);
173 if (m_ownerInfo
.pRenderNode
)
174 pObj
->m_ObjFlags
|= FOB_TRANS_MASK
;
176 pObj
->m_nSort
= m_sortPrio
;
178 // somehow it's need's to be twice bigger to be same as simple decals
179 float fSize2
= m_fSize
* fSizeK
* 2.f
;///m_ownerInfo.pRenderNode->GetScale();
180 if (fSize2
< 0.0001f
)
185 float correctScale(-1);
186 m_arrBigDecalRMCustomData
[0] = correctScale
* m_vUp
.x
/ fSize2
;
187 m_arrBigDecalRMCustomData
[1] = correctScale
* m_vUp
.y
/ fSize2
;
188 m_arrBigDecalRMCustomData
[2] = correctScale
* m_vUp
.z
/ fSize2
;
190 Vec3 vPosDecS
= m_vPos
;
191 if (m_eDecalType
== eDecalType_WS_Merged
)
195 m_arrBigDecalRMCustomData
[0] * vPosDecS
.x
+
196 m_arrBigDecalRMCustomData
[1] * vPosDecS
.y
+
197 m_arrBigDecalRMCustomData
[2] * vPosDecS
.z
;
199 m_arrBigDecalRMCustomData
[3] = -D0
+ 0.5f
;
202 m_arrBigDecalRMCustomData
[4] = m_vRight
.x
/ fSize2
;
203 m_arrBigDecalRMCustomData
[5] = m_vRight
.y
/ fSize2
;
204 m_arrBigDecalRMCustomData
[6] = m_vRight
.z
/ fSize2
;
207 m_arrBigDecalRMCustomData
[4] * vPosDecS
.x
+
208 m_arrBigDecalRMCustomData
[5] * vPosDecS
.y
+
209 m_arrBigDecalRMCustomData
[6] * vPosDecS
.z
;
211 m_arrBigDecalRMCustomData
[7] = -D1
+ 0.5f
;
213 // pass attenuation info
214 m_arrBigDecalRMCustomData
[8] = vPosDecS
.x
;
215 m_arrBigDecalRMCustomData
[9] = vPosDecS
.y
;
216 m_arrBigDecalRMCustomData
[10] = vPosDecS
.z
;
217 m_arrBigDecalRMCustomData
[11] = m_fSize
;
220 Vec3
vNormal(Vec3(correctScale
* m_vUp
).Cross(m_vRight
).GetNormalized());
221 m_arrBigDecalRMCustomData
[12] = vNormal
.x
* (m_fSize
/ m_fWSSize
);
222 m_arrBigDecalRMCustomData
[13] = vNormal
.y
* (m_fSize
/ m_fWSSize
);
223 m_arrBigDecalRMCustomData
[14] = vNormal
.z
* (m_fSize
/ m_fWSSize
);
224 m_arrBigDecalRMCustomData
[15] = 0;
226 CStatObj
* pBody
= NULL
;
227 bool bUseBending
= GetCVars()->e_VegetationBending
!= 0;
228 if (m_ownerInfo
.pRenderNode
&& m_ownerInfo
.pRenderNode
->GetRenderNodeType() == eERType_Vegetation
)
230 CVegetation
* pVegetation
= (CVegetation
*)m_ownerInfo
.pRenderNode
;
231 CRY_ASSERT_MESSAGE(pVegetation
!= nullptr, "pVegetation is nullptr");
232 pBody
= pVegetation
->GetStatObj();
233 CRY_ASSERT_MESSAGE(pBody
!= nullptr, "pBody is nullptr");
235 if (pVegetation
&& pBody
&& bUseBending
)
237 pVegetation
->FillBendingData(pObj
, passInfo
);
239 IMaterial
* pMat
= m_ownerInfo
.pRenderNode
->GetMaterial();
240 pMat
= pMat
->GetSubMtl(m_ownerInfo
.nMatID
);
243 // Support for public parameters from owner (deformations)
244 SShaderItem
& SH
= pMat
->GetShaderItem();
245 if (SH
.m_pShaderResources
)
247 //IMaterial* pMatDecal = m_pMaterial;
248 //SShaderItem& SHDecal = pMatDecal->GetShaderItem();
251 pObj
->m_nMDV
= SH
.m_pShader
->GetVertexModificator();
252 //if (SHDecal.m_pShaderResources && pObj->m_nMDV)
253 //SH.m_pShaderResources->ExportModificators(SHDecal.m_pShaderResources, pObj);
257 if (m_eDecalType
== eDecalType_OS_OwnersVerticesUsed
)
258 pObj
->m_ObjFlags
|= FOB_OWNER_GEOMETRY
;
259 IFoliage
* pFol
= pVegetation
->GetFoliage();
262 SRenderObjData
* pOD
= pObj
->GetObjData();
265 pOD
->m_pSkinningData
= pFol
->GetSkinningData(objMat
, passInfo
);
268 if (pBody
&& pBody
->m_pRenderMesh
)
270 m_pRenderMesh
->SetVertexContainer(pBody
->m_pRenderMesh
);
274 // draw complex decal using new indices and original object vertices
275 pObj
->m_fAlpha
= fAlpha
;
276 pObj
->m_ObjFlags
|= FOB_DECAL
| FOB_DECAL_TEXGEN_2D
| FOB_INSHADOW
;
277 pObj
->SetAmbientColor(m_vAmbient
, passInfo
);
279 m_pRenderMesh
->SetREUserData(m_arrBigDecalRMCustomData
, 0, fAlpha
);
280 m_pRenderMesh
->AddRenderElements(m_pMaterial
, pObj
, passInfo
, EFSLIST_GENERAL
, nAfterWater
);
284 case eDecalType_OS_SimpleQuad
:
286 assert(m_ownerInfo
.pRenderNode
);
287 if (!m_ownerInfo
.pRenderNode
)
290 // transform decal in software from owner space into world space and render as quad
292 IStatObj
* pEntObject
= m_ownerInfo
.GetOwner(objMat
);
296 Vec3 vPos
= objMat
.TransformPoint(m_vPos
);
297 Vec3 vRight
= objMat
.TransformVector(m_vRight
* m_fSize
);
298 Vec3 vUp
= objMat
.TransformVector(m_vUp
* m_fSize
);
301 uCol
.dcolor
= 0xffffffff;
302 uCol
.bcolor
[3] = fastround_positive(fAlpha
* 255);
304 AddDecalToRenderView(fDistance
, m_pMaterial
, m_sortPrio
, vRight
* fSizeK
, vUp
* fSizeK
, uCol
,
305 OS_ALPHA_BLEND
, m_vAmbient
, vPos
, nAfterWater
,
306 m_ownerInfo
.pRenderNode
->GetRenderNodeType() == eERType_Vegetation
? (CVegetation
*) m_ownerInfo
.pRenderNode
: nullptr, passInfo
);
310 case eDecalType_WS_SimpleQuad
:
312 // draw small world space decal untransformed
315 uCol
.bcolor
[3] = fastround_positive(fAlpha
* 255);
316 AddDecalToRenderView(fDistance
, m_pMaterial
, m_sortPrio
, m_vRight
* m_fSize
* fSizeK
,
317 m_vUp
* m_fSize
* fSizeK
, uCol
, OS_ALPHA_BLEND
, m_vAmbient
, m_vPos
, nAfterWater
, nullptr, passInfo
);
321 case eDecalType_WS_OnTheGround
:
323 RenderBigDecalOnTerrain(fAlpha
, fSizeK
, passInfo
);
329 void CDecal::FreeRenderData()
331 // delete render mesh
332 m_pRenderMesh
= NULL
;
334 m_ownerInfo
.pRenderNode
= 0;
337 void CDecal::RenderBigDecalOnTerrain(float fAlpha
, float fScale
, const SRenderingPassInfo
& passInfo
)
339 float fRadius
= m_fSize
* fScale
;
341 // check terrain bounds
342 if (m_vPos
.x
< -fRadius
|| m_vPos
.y
< -fRadius
)
344 if (m_vPos
.x
>= CTerrain::GetTerrainSize() + fRadius
|| m_vPos
.y
>= CTerrain::GetTerrainSize() + fRadius
)
347 fRadius
+= CTerrain::GetHeightMapUnitSize();
349 if (fabs(m_vPos
.z
- Get3DEngine()->GetTerrainZ((m_vPos
.x
), (m_vPos
.y
))) > fRadius
)
350 return; // too far from ground surface
353 float fSize2
= m_fSize
* fScale
* 2.f
;
358 float correctScale(-1);
359 m_arrBigDecalRMCustomData
[0] = correctScale
* m_vUp
.x
/ fSize2
;
360 m_arrBigDecalRMCustomData
[1] = correctScale
* m_vUp
.y
/ fSize2
;
361 m_arrBigDecalRMCustomData
[2] = correctScale
* m_vUp
.z
/ fSize2
;
365 m_arrBigDecalRMCustomData
[3] = -D0
+ 0.5f
;
368 m_arrBigDecalRMCustomData
[4] = m_vRight
.x
/ fSize2
;
369 m_arrBigDecalRMCustomData
[5] = m_vRight
.y
/ fSize2
;
370 m_arrBigDecalRMCustomData
[6] = m_vRight
.z
/ fSize2
;
374 m_arrBigDecalRMCustomData
[7] = -D1
+ 0.5f
;
376 // pass attenuation info
377 m_arrBigDecalRMCustomData
[8] = 0;
378 m_arrBigDecalRMCustomData
[9] = 0;
379 m_arrBigDecalRMCustomData
[10] = 0;
380 m_arrBigDecalRMCustomData
[11] = fSize2
;
382 Vec3
vNormal(Vec3(correctScale
* m_vUp
).Cross(m_vRight
).GetNormalized());
383 m_arrBigDecalRMCustomData
[12] = vNormal
.x
;
384 m_arrBigDecalRMCustomData
[13] = vNormal
.y
;
385 m_arrBigDecalRMCustomData
[14] = vNormal
.z
;
386 m_arrBigDecalRMCustomData
[15] = 0;
388 CRenderObject
* pObj
= GetIdentityCRenderObject(passInfo
);
391 pObj
->SetMatrix(Matrix34::CreateTranslationMat(m_vPos
), passInfo
);
392 pObj
->m_ObjFlags
|= FOB_TRANS_TRANSLATE
;
394 pObj
->m_fAlpha
= fAlpha
;
395 pObj
->m_ObjFlags
|= FOB_DECAL
| FOB_DECAL_TEXGEN_2D
| FOB_INSHADOW
;
396 pObj
->SetAmbientColor(m_vAmbient
, passInfo
);
398 pObj
->m_nSort
= m_sortPrio
;
401 planes
[0].SetPlane(m_vRight
, m_vRight
* m_fSize
+ m_vPos
);
402 planes
[1].SetPlane(-m_vRight
, -m_vRight
* m_fSize
+ m_vPos
);
403 planes
[2].SetPlane(m_vUp
, m_vUp
* m_fSize
+ m_vPos
);
404 planes
[3].SetPlane(-m_vUp
, -m_vUp
* m_fSize
+ m_vPos
);
406 // m_pRenderMesh might get updated by the following function
407 GetTerrain()->RenderArea(m_vPos
, fRadius
, m_pRenderMesh
,
408 pObj
, m_pMaterial
, "BigDecalOnTerrain", m_arrBigDecalRMCustomData
, GetCVars()->e_DecalsClip
? planes
: NULL
, passInfo
);
411 //////////////////////////////////////////////////////////////////////////
412 void CDecal::AddDecalToRenderView(float fDistance
,
413 IMaterial
* pMaterial
,
414 const uint8 sortPrio
,
417 const UCol
& ucResCol
,
418 const uint8 uBlendType
,
419 const Vec3
& vAmbientColor
,
421 const int nAfterWater
,
422 CVegetation
* pVegetation
,
423 const SRenderingPassInfo
& passInfo
)
425 FUNCTION_PROFILER_3DENGINE
;
426 MEMSTAT_CONTEXT(EMemStatContextType::Other
, "AddDecalToRenderer");
428 CRenderObject
* pRenderObject(GetIdentityCRenderObject(passInfo
));
432 // prepare render object
433 pRenderObject
->m_fDistance
= fDistance
;
434 pRenderObject
->m_fAlpha
= (float)ucResCol
.bcolor
[3] / 255.f
;
435 pRenderObject
->SetAmbientColor(vAmbientColor
, passInfo
);
436 pRenderObject
->m_fSort
= 0;
437 pRenderObject
->m_ObjFlags
|= FOB_DECAL
| FOB_INSHADOW
;
438 pRenderObject
->m_nSort
= sortPrio
;
440 bool bBending
= pVegetation
&& pVegetation
->IsBending();
444 // transfer decal into object space
446 IStatObj
* pEntObject
= pVegetation
->GetEntityStatObj(0, &objMat
);
447 pRenderObject
->SetMatrix(objMat
, passInfo
);
448 pRenderObject
->m_ObjFlags
|= FOB_TRANS_MASK
;
449 pVegetation
->FillBendingData(pRenderObject
, passInfo
);
454 vPos
= objMat
.TransformPoint(vPos
);
455 right
= objMat
.TransformVector(right
);
456 up
= objMat
.TransformVector(up
);
460 SVF_P3F_C4B_T2F pVerts
[4];
463 // TODO: determine whether this is a decal on opaque or transparent geometry
464 // (put it in the respective renderlist for correct shadowing)
465 // fill general vertex data
466 pVerts
[0].xyz
= (-right
- up
) + vPos
;
467 pVerts
[0].st
= Vec2(0, 1);
468 pVerts
[0].color
.dcolor
= ~0;
470 pVerts
[1].xyz
= (right
- up
) + vPos
;
471 pVerts
[1].st
= Vec2(1, 1);
472 pVerts
[1].color
.dcolor
= ~0;
474 pVerts
[2].xyz
= (right
+ up
) + vPos
;
475 pVerts
[2].st
= Vec2(1, 0);
476 pVerts
[2].color
.dcolor
= ~0;
478 pVerts
[3].xyz
= (-right
+ up
) + vPos
;
479 pVerts
[3].st
= Vec2(0, 0);
480 pVerts
[3].color
.dcolor
= ~0;
482 // prepare tangent space (tangent, bitangent) and fill it in
483 Vec3
rightUnit(right
.GetNormalized());
484 Vec3
upUnit(up
.GetNormalized());
486 SPipTangents pTangents
[4];
488 pTangents
[0] = SPipTangents(rightUnit
, -upUnit
, -1);
489 pTangents
[1] = pTangents
[0];
490 pTangents
[2] = pTangents
[0];
491 pTangents
[3] = pTangents
[0];
493 // fill decals topology (two triangles)
502 SRenderPolygonDescription
poly(pRenderObject
, pMaterial
->GetShaderItem(), 4, pVerts
, pTangents
, pIndices
, 6, EFSLIST_DECAL
, nAfterWater
);
503 passInfo
.GetIRenderView()->AddPolygon(poly
, passInfo
);