Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpUnitRenderer.cpp
/* Copyright (C) 2020 Wildfire Games. | /* Copyright (C) 2021 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 22 Lines | |||||
#include "graphics/ModelAbstract.h" | #include "graphics/ModelAbstract.h" | ||||
#include "graphics/ObjectEntry.h" | #include "graphics/ObjectEntry.h" | ||||
#include "graphics/Overlay.h" | #include "graphics/Overlay.h" | ||||
#include "graphics/Unit.h" | #include "graphics/Unit.h" | ||||
#include "maths/BoundingSphere.h" | #include "maths/BoundingSphere.h" | ||||
#include "maths/Matrix3D.h" | #include "maths/Matrix3D.h" | ||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "renderer/Renderer.h" | |||||
#include "renderer/RenderingOptions.h" | #include "renderer/RenderingOptions.h" | ||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
#include "tools/atlas/GameInterface/GameLoop.h" | #include "tools/atlas/GameInterface/GameLoop.h" | ||||
/** | /** | ||||
* Efficiently(ish) renders all the units in the world. | * Efficiently(ish) renders all the units in the world. | ||||
* | * | ||||
Show All 17 Lines | |||||
{ | { | ||||
public: | public: | ||||
struct SUnit | struct SUnit | ||||
{ | { | ||||
CEntityHandle entity; | CEntityHandle entity; | ||||
CUnit* actor; | CUnit* actor; | ||||
int flags; | int flags; | ||||
vladislavbelov: What does the `LOD` name mean? It's not obvious from the name. | |||||
/** | /** | ||||
* m_FrameNumber from when the model's transform was last updated. | * m_FrameNumber from when the model's transform was last updated. | ||||
* This is used to avoid recomputing it multiple times per frame | * This is used to avoid recomputing it multiple times per frame | ||||
* if a model is visible in multiple cull groups. | * if a model is visible in multiple cull groups. | ||||
*/ | */ | ||||
int lastTransformFrame; | int lastTransformFrame; | ||||
▲ Show 20 Lines • Show All 331 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < m_Units.size(); ++i) | ||||
if (!g_AtlasGameLoop->running && (unit.flags & VISIBLE_IN_ATLAS_ONLY)) | if (!g_AtlasGameLoop->running && (unit.flags & VISIBLE_IN_ATLAS_ONLY)) | ||||
continue; | continue; | ||||
if (culling && !frustum.IsSphereVisible(unit.sweptBounds.GetCenter(), unit.sweptBounds.GetRadius())) | if (culling && !frustum.IsSphereVisible(unit.sweptBounds.GetCenter(), unit.sweptBounds.GetRadius())) | ||||
continue; | continue; | ||||
unit.culled = false; | unit.culled = false; | ||||
CmpPtr<ICmpVisual> cmpVisual(unit.entity); | |||||
if (cmpVisual && cmpVisual->HasLevelsOfDetail()) | |||||
{ | |||||
float maxZoom = 200.0f; | |||||
// ToDo: Get Value from config | |||||
// CFG_GET_VAL("view.zoom.max", maxZoom); | |||||
const float step = maxZoom / (cmpVisual->GetMaxLevelOfDetail() + 1.0f); | |||||
const float stepSQ = step * step; | |||||
CmpPtr<ICmpPosition> cmpPosition(unit.entity); | |||||
if (!cmpPosition->IsInWorld()) | |||||
continue; | |||||
CVector3D origin = CRenderer::GetSingleton().GetViewCamera().m_Orientation.GetTranslation(); | |||||
float dist = (CVector3D(cmpPosition->GetPosition()) - (origin)).LengthSquared(); | |||||
for (u8 newLod = 0; newLod <= cmpVisual->GetMaxLevelOfDetail(); ++newLod) | |||||
{ | |||||
if (dist >= stepSQ * newLod && dist <= stepSQ * (newLod + 1.0f)) | |||||
{ | |||||
cmpVisual->SetLevelOfDetail(newLod); | |||||
// Disable Lods if some are missing, else it will spam error messages | |||||
// and eventually crash. | |||||
if (!cmpVisual->GetUnit()) | |||||
{ | |||||
cmpVisual->SetLevelOfDetail(0); | |||||
cmpVisual->SetMaxLevelOfDetail(0); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
for (size_t i = 0; i < m_Units.size(); ++i) | |||||
{ | |||||
SUnit& unit = m_Units[i]; | |||||
if (unit.culled) | |||||
continue; | |||||
CModelAbstract& unitModel = unit.actor->GetModel(); | CModelAbstract& unitModel = unit.actor->GetModel(); | ||||
if (unit.lastTransformFrame != m_FrameNumber) | if (unit.lastTransformFrame != m_FrameNumber) | ||||
{ | { | ||||
CmpPtr<ICmpPosition> cmpPosition(unit.entity); | CmpPtr<ICmpPosition> cmpPosition(unit.entity); | ||||
if (!cmpPosition) | if (!cmpPosition) | ||||
continue; | continue; | ||||
CMatrix3D transform(cmpPosition->GetInterpolatedTransform(m_FrameOffset)); | CMatrix3D transform(cmpPosition->GetInterpolatedTransform(m_FrameOffset)); | ||||
unitModel.SetTransform(transform); | unitModel.SetTransform(transform); | ||||
unit.lastTransformFrame = m_FrameNumber; | unit.lastTransformFrame = m_FrameNumber; | ||||
} | } | ||||
if (culling && !frustum.IsBoxVisible(unitModel.GetWorldBoundsRec())) | if (culling && !frustum.IsBoxVisible(unitModel.GetWorldBoundsRec())) | ||||
continue; | continue; | ||||
collector.SubmitRecursive(&unitModel); | collector.SubmitRecursive(&unitModel); | ||||
} | } | ||||
for (size_t i = 0; i < m_DebugSpheres.size(); ++i) | for (size_t i = 0; i < m_DebugSpheres.size(); ++i) | ||||
collector.Submit(&m_DebugSpheres[i]); | collector.Submit(&m_DebugSpheres[i]); | ||||
} | } | ||||
Done Inline ActionsDon't implement "behind the camera" culling. Since you don't actually account for the entity BB, you'll fail occasionally and units will "pop-in". Further, culling is already handled, so this is just double-work. wraitii: Don't implement "behind the camera" culling.
Since you don't actually account for the entity… | |||||
void CCmpUnitRenderer::UpdateVisibility(SUnit& unit) const | void CCmpUnitRenderer::UpdateVisibility(SUnit& unit) const | ||||
{ | { | ||||
if (unit.inWorld) | if (unit.inWorld) | ||||
{ | { | ||||
// The 'always visible' flag means we should always render the unit | // The 'always visible' flag means we should always render the unit | ||||
// (regardless of whether the LOS system thinks it's visible) | // (regardless of whether the LOS system thinks it's visible) | ||||
CmpPtr<ICmpVisibility> cmpVisibility(unit.entity); | CmpPtr<ICmpVisibility> cmpVisibility(unit.entity); | ||||
if (cmpVisibility && cmpVisibility->GetAlwaysVisible()) | if (cmpVisibility && cmpVisibility->GetAlwaysVisible()) | ||||
Show All 20 Lines |
Wildfire Games · Phabricator
What does the LOD name mean? It's not obvious from the name.