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/Cry3DEngine/CloudRenderNode.cpp

281 lines
8.8 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 "Cry3DEngine_precompiled.h"
#include "CloudRenderNode.h"
#include "CloudsManager.h"
#include "VisAreas.h"
#include "ObjMan.h"
#include "Environment/OceanEnvironmentBus.h"
//////////////////////////////////////////////////////////////////////////
CCloudRenderNode::CCloudRenderNode()
{
m_bounds.min = Vec3(-1, -1, -1);
m_bounds.max = Vec3(1, 1, 1);
m_fScale = 1.0f;
m_offsetedMatrix.SetIdentity();
m_matrix.SetIdentity();
m_vOffset.Set(0, 0, 0);
m_alpha = 1.f;
m_pCloudRenderElement = (CREBaseCloud*)GetRenderer()->EF_CreateRE(eDATA_Cloud);
m_pREImposter = (CREImposter*) GetRenderer()->EF_CreateRE(eDATA_Imposter);
GetCloudsManager()->AddCloudRenderNode(this);
m_origin = Vec3(0, 0, 0);
m_moveProps.m_autoMove = false;
m_moveProps.m_speed = Vec3(0, 0, 0);
m_moveProps.m_spaceLoopBox = Vec3(2000.0f, 2000.0f, 2000.0f);
m_moveProps.m_fadeDistance = 0;
}
//////////////////////////////////////////////////////////////////////////
CCloudRenderNode::~CCloudRenderNode()
{
GetCloudsManager()->RemoveCloudRenderNode(this);
m_pCloudRenderElement->Release(false);
m_pREImposter->Release(false);
Get3DEngine()->FreeRenderNodeState(this);
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::LoadCloudFromXml(XmlNodeRef root)
{
m_pCloudDesc = new SCloudDescription;
GetCloudsManager()->ParseCloudFromXml(root, m_pCloudDesc);
SetCloudDesc(m_pCloudDesc);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::LoadCloud(const char* sCloudFilename)
{
m_bounds.min = Vec3(-1, -1, -1);
m_bounds.max = Vec3(1, 1, 1);
SetCloudDesc(GetCloudsManager()->LoadCloud(sCloudFilename));
return m_pCloudDesc != 0;
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMovementProperties(const SCloudMovementProperties& properties)
{
m_moveProps = properties;
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetCloudDesc(SCloudDescription* pCloud)
{
m_pCloudDesc = pCloud;
if (m_pCloudDesc != NULL && m_pCloudDesc->m_particles.size() > 0)
{
m_vOffset = m_pCloudDesc->m_offset;
m_bounds.min = m_pCloudDesc->m_bounds.min - m_pCloudDesc->m_offset;
m_bounds.max = m_pCloudDesc->m_bounds.max - m_pCloudDesc->m_offset;
if (m_pCloudDesc->m_pMaterial)
{
m_pMaterial = m_pCloudDesc->m_pMaterial;
}
m_pCloudRenderElement->SetParticles(&m_pCloudDesc->m_particles[0], m_pCloudDesc->m_particles.size());
m_WSBBox.SetTransformedAABB(m_matrix, m_bounds);
m_fScale = m_matrix.GetColumn(0).GetLength();
// Offset matrix by the cloud bounds offset.
m_offsetedMatrix = m_matrix * Matrix34::CreateTranslationMat(-m_vOffset);
}
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMatrix(const Matrix34& mat)
{
SetMatrixInternal(mat, true);
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMatrixInternal(const Matrix34& mat, bool updateOrigin)
{
m_dwRndFlags |= ERF_OUTDOORONLY;
if (updateOrigin)
{
m_origin = mat.GetTranslation();
}
m_matrix = mat;
m_pos = mat.GetTranslation();
// m_WSBBox.SetTransformedAABB( m_matrix,m_bounds );
m_fScale = mat.GetColumn(0).GetLength();
m_WSBBox.SetTransformedAABB(Matrix34::CreateTranslationMat(m_pos), AABB(m_bounds.min * m_fScale, m_bounds.max * m_fScale));
// Offset matrix by the cloud bounds offset.
// m_offsetedMatrix = m_matrix * Matrix34::CreateTranslationMat(-m_vOffset);
m_offsetedMatrix = Matrix34::CreateTranslationMat(m_pos - m_vOffset * m_fScale);
m_offsetedMatrix.ScaleColumn(Vec3(m_fScale, m_fScale, m_fScale));
Get3DEngine()->RegisterEntity(this);
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::MoveCloud()
{
FUNCTION_PROFILER_3DENGINE;
Vec3 pos(m_matrix.GetTranslation());
ITimer* pTimer(gEnv->pTimer);
if (m_moveProps.m_autoMove)
{
// update position
float deltaTime = pTimer->GetFrameTime();
assert(deltaTime >= 0);
pos += deltaTime * m_moveProps.m_speed;
// constrain movement to specified loop box
Vec3 loopBoxMin(m_origin - m_moveProps.m_spaceLoopBox);
Vec3 loopBoxMax(m_origin + m_moveProps.m_spaceLoopBox);
if (pos.x < loopBoxMin.x)
{
pos.x = loopBoxMax.x;
}
if (pos.y < loopBoxMin.y)
{
pos.y = loopBoxMax.y;
}
if (pos.z < loopBoxMin.z)
{
pos.z = loopBoxMax.z;
}
if (pos.x > loopBoxMax.x)
{
pos.x = loopBoxMin.x;
}
if (pos.y > loopBoxMax.y)
{
pos.y = loopBoxMin.y;
}
if (pos.z > loopBoxMax.z)
{
pos.z = loopBoxMin.z;
}
// set new position
Matrix34 mat(m_matrix);
mat.SetTranslation(pos);
SetMatrixInternal(mat, false);
// fade out clouds at the borders of the loop box
if (m_moveProps.m_fadeDistance > 0)
{
Vec3 fade(max(m_moveProps.m_spaceLoopBox.x, m_moveProps.m_fadeDistance),
max(m_moveProps.m_spaceLoopBox.y, m_moveProps.m_fadeDistance),
max(m_moveProps.m_spaceLoopBox.z, m_moveProps.m_fadeDistance));
fade -= Vec3(fabs(pos.x - m_origin.x), fabs(pos.y - m_origin.y), fabs(pos.z - m_origin.z));
m_alpha = clamp_tpl(min(min(fade.x, fade.y), fade.z) / m_moveProps.m_fadeDistance, 0.0f, 1.0f);
}
}
else
{
if ((m_origin - pos).GetLengthSquared() > 1e-4f)
{
Matrix34 mat(m_matrix);
mat.SetTranslation(m_origin);
SetMatrixInternal(mat, false);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::Render(const SRendParams& rParams, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
if (!m_pMaterial || !passInfo.RenderClouds())
{
return;
}
IRenderer* pRenderer(GetRenderer());
// get render objects
CRenderObject* pRO = pRenderer->EF_GetObject_Temp(passInfo.ThreadID());
if (!pRO)
{
return;
}
SShaderItem& shaderItem = (rParams.pMaterial) ? rParams.pMaterial->GetShaderItem(0) : m_pMaterial->GetShaderItem(0);
pRO->m_II.m_Matrix = m_offsetedMatrix;
SRenderObjData* pOD = pRenderer->EF_GetObjData(pRO, true, passInfo.ThreadID());
pOD->m_fTempVars[0] = m_fScale;
pRO->m_fSort = 0;
pRO->m_fDistance = rParams.fDistance;
int nAfterWater = GetObjManager()->IsAfterWater(m_offsetedMatrix.GetTranslation(), passInfo) ? 1 : 0;
pRO->m_II.m_AmbColor = rParams.AmbientColor;
pRO->m_fAlpha = rParams.fAlpha * m_alpha;
float mvd(GetMaxViewDist());
float d((passInfo.GetCamera().GetPosition() - m_offsetedMatrix.GetTranslation()).GetLength());
if (d > 0.9f * mvd)
{
float s(clamp_tpl(1.0f - (d - 0.9f * mvd) / (0.1f * mvd), 0.0f, 1.0f));
pRO->m_fAlpha *= s;
}
pRenderer->EF_AddEf(m_pCloudRenderElement, shaderItem, pRO, passInfo, EFSLIST_TRANSP, nAfterWater, SRendItemSorter(rParams.rendItemSorter));
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::CheckIntersection(const Vec3& p1, const Vec3& p2)
{
if (p1 == p2)
{
return false;
}
if (m_pCloudDesc && m_pCloudDesc->m_pCloudTree)
{
Vec3 outp;
if (Intersect::Lineseg_AABB(Lineseg(p1, p2), m_WSBBox, outp))
{
Matrix34 pInv = m_offsetedMatrix.GetInverted();
return m_pCloudDesc->m_pCloudTree->CheckIntersection(pInv * p1, pInv * p2);
}
}
return false;
}
void CCloudRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData)
{
m_pRNTmpData->OffsetPosition(delta);
}
m_pos += delta;
m_origin += delta;
m_matrix.SetTranslation(m_matrix.GetTranslation() + delta);
m_offsetedMatrix.SetTranslation(m_offsetedMatrix.GetTranslation() + delta);
m_WSBBox.Move(delta);
}