1#include "RenderSystem.h"
3#include "Components/Core/MeshRenderComponent.h"
6#include "Components/Core/TransformComponent.h"
7#include "Components/Core/MeshComponent.h"
8#include "Components/Core/NearLimitComponent.h"
9#include "Components/Core/ClipShapeComponent.h"
11#include "Scene/RayPick.h"
12#include "Systems/Core/TransformSystem.h"
13#include "Systems/Core/CameraSystem.h"
14#include "Systems/Core/ClipShapeSystem.h"
16#include "Resources/Mesh.h"
17#include "Resources/MeshManager.h"
19#include "Services/Variables.h"
20#include "Services/TaskManager.h"
22#include "Utilities/Parallel.h"
23#include "Math/RayIntersection.h"
25#include "Scene/GetBounds.h"
28#include "Foundation/Logging/Logger.h"
47 const bool workParallel = context->
engine->workParallel();
57 auto & data = this->getData<MeshRenderData>(&renderComponent);
58 auto & localBounds = getLocalBounds(&renderComponent);
60 if (!data.transformComponent) {
67 if ((data.flags & MeshRenderDataFlags::LocalBoundsOverride) == 0) {
68 auto meshComponent = data.meshComponent.resolveComponent<
MeshComponent>();
70 if (!meshComponent->meshHandle)
return;
74 if (meshComponent->hasChanged() || data.meshBoundsGeneration != mesh->getGeneration() || mesh->boundsDirty()) {
75 if (mesh->boundsDirty() || (isEmpty(mesh->boundingBox) && mesh->getCount())) {
78 if (!isEmpty(mesh->boundingBox) && !mesh->isInitialized()) {
83 if (mesh->boundingBox.min.x <= mesh->boundingBox.max.x) {
84 localBounds = mesh->boundingBox;
89 data.meshBoundsGeneration = (uint8_t)mesh->getGeneration();
90 ++data.localBoundsGeneration;
99 if (data.worldBoundsGeneration != data.localBoundsGeneration || transformSystem->hasChanged(transform)) {
100 data.localToWorld = transformSystem->getLocalToWorld(transform);
102 if (!isEmpty(localBounds)) {
103 getWorldBounds(&renderComponent) = Bounds::getTransformedBounds(localBounds, data.localToWorld);
105 getWorldBounds(&renderComponent) = localBounds;
108 if (data.worldBoundsGeneration != data.localBoundsGeneration) {
109 data.worldBoundsGeneration = data.localBoundsGeneration;
114 data.cullingIndex = NoCullingIndex;
121 CpuInstrumentationScope(SCOPE_SYSTEMS,
"RenderSystem::update");
123 Parallel::processComponents(context, pool,
"RenderSystem::updateComponent", updateComponent, geometryGroup);
127 Serial::processComponents(pool, updateComponent);
142 if (geometryGroup.isValid()) {
152 if (pool.size() == 1u) {
153 assert(picker ==
nullptr);
154 picker = std::make_unique<MeshRenderPicker>(
this);
155 context->rayPicking->addPickable(picker.get());
162 base_type::destroyComponent(component);
164 if (pool.size() == 0u) {
165 context->rayPicking->removePickable(picker.get());
170void Cogs::Core::RenderSystem::initializeCulling(
CullingSource* cullSource)
172 const auto offset = cullSource->count;
173 const auto count = pool.size();
174 const auto total = offset + count;
177 cullSource->count = total;
178 cullSource->bbMinWorld.resize(total);
179 cullSource->bbMaxWorld.resize(total);
182 for (
SizeType i = 0; i < count; ++i) {
183 auto & meshData = this->getData<MeshRenderData>(&pool[i]);
185 meshData.cullingIndex = j;
186 cullSource->bbMinWorld[j] = getWorldBounds(&pool[i]).min;
187 cullSource->bbMaxWorld[j] = getWorldBounds(&pool[i]).max;
191 auto scope = Parallel::forEach(context, count, [
this, offset, cullSource](
size_t i) {
192 auto & meshData = this->getData<MeshRenderData>(&pool[(
SizeType)i]);
194 meshData.cullingIndex = j;
195 cullSource->bbMinWorld[j] = getWorldBounds(&pool[(
SizeType)i]).min;
196 cullSource->bbMaxWorld[j] = getWorldBounds(&pool[(
SizeType)i]).max;
197 },
"MeshRenderSystem::initializeCulling");
203 const glm::mat4& worldPickMatrix,
204 const glm::mat4& rawViewProjection,
205 const glm::mat4& viewMatrix,
209 std::vector<RayPicking::RayPickHit>& hits)
213 const size_t hitsBefore = hits.size();
221 for (
Cogs::SizeType start = 0; start < itemCount; start += batchSize) {
222 const Cogs::SizeType end = std::min(start + batchSize, itemCount);
226 CpuInstrumentationScope(SCOPE_RAYPICK,
"executePickingQueryTask");
228 std::vector<RayPicking::RayPickHit> batchPickResults;
230 batchPickResults.reserve(10);
246 if (!renderData.meshComponent) {
250 const Geometry::BoundingBox& bboxWorld = system->getWorldBounds(&comp);
260 if (isEmpty(bboxWorld)) {
264 if (frustumClassifyBoundingBox(worldPickMatrix, bboxWorld.min, bboxWorld.max) != FrustumPlanes::InsideAll) {
270 glm::mat4 localPickMatrix = worldPickMatrix * renderData.localToWorld;
272 std::vector<RayIntersectionHit> meshHits;
273 std::vector<FrustumPlanes> scratch;
274 if (!intersectMesh(meshHits,
280 static_cast<uint32_t
>(-1))) {
284 if (meshHits.empty()) {
289 const glm::vec4 position = renderData.localToWorld * glm::vec4(meshHit.pos_, 1.f);
292 const ClipShapeData& clipData = context->clipShapeSystem->getData(clipComp);
293 if (clippedByClipComp(clipData, position)) {
298 const glm::vec4 clipPos = rawViewProjection * glm::vec4(position.x, position.y, position.z, 1.f);
300 if ((-clipPos.w < clipPos.z) && (clipPos.z < clipPos.w)) {
302 glm::vec4 viewPos = viewMatrix * position;
303 float viewDist = -viewPos.z;
306 if (viewDist < batchPickResults[0].distance) {
307 glm::vec2 textureCoords = getTextureCoords(texcoordInfo, meshHit, pickingFlags);
308 batchPickResults[0] = {comp, returnChildEntity, position, viewDist, textureCoords};
313 glm::vec2 textureCoords = getTextureCoords(texcoordInfo, meshHit, pickingFlags);
314 batchPickResults.emplace_back(comp, returnChildEntity, position, viewDist, textureCoords);
320 if (!batchPickResults.empty()) {
321 LockGuard guard(batchLock);
324 hits = std::move(batchPickResults);
326 else if (hits[0].distance > batchPickResults[0].distance) {
327 hits[0] = batchPickResults[0];
332 hits.insert(hits.end(),
333 std::make_move_iterator(batchPickResults.begin()),
334 std::make_move_iterator(batchPickResults.end()));
343 std::sort(hits.begin(), hits.end());
345 return hitsBefore != hits.size();
ComponentHandle getComponentHandle() const
Sets up a clipping shape that can be used by multiple entities.
Context * context
Pointer to the Context instance the system lives in.
void postUpdate()
Perform post update logic in the system.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
std::unique_ptr< class Engine > engine
Engine instance.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Renders the contents of a MeshComponent using the given materials.
uint32_t startIndex
Start vertex index to render from.
uint32_t vertexCount
Number of vertexes to draw.
ComponentModel::ComponentHandle clipShapeComponent
Handle to the currently active clip component, if any.
constexpr bool isVisibleInLayer(RenderLayers layerMask) const
Check if the entity should be visible in the given layer mask.
constexpr bool isVisible() const
Check if the entity is visible or not.
constexpr bool isRenderFlagSet(RenderFlags flag) const
Check if the given flag is currently set.
constexpr bool isPickable() const
Check if the entity is pickable or not.
void initialize(Context *context) override
Initialize the system.
ComponentHandle createComponent() override
Create a new component instance.
void cleanup(Context *context) override
Provided for custom cleanup logic in derived systems.
void destroyComponent(ComponentHandle component) override
Destroy the component held by the given handle.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
PicksReturned
* Options for returning picking hits.
@ Closest
Return just the closest hit.
@ AllSorted
Return all hits sorted based on distance from the ray start, closest first.
@ ForcePickable
Ensure component is pickable though it is not rendered.
PickingFlags
Options for COGS picking.
@ ReturnChildEntity
Return ID if sub-entity picked, not set: return root parent entity.
Cogs::Geometry::BoundingBox COGSCORE_DLL_API calculateBounds(Mesh *mesh)
Calculate a bounding box for the given mesh.
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
ComponentIndex SizeType
Type used to track the size of pools.
Handle to a Component instance.
ComponentType * resolveComponent() const
bool pickImpl(Context *context, const glm::mat4 &worldPickMatrix, const glm::mat4 &rawViewProjection, const glm::mat4 &viewMatrix, const RayPicking::RayPickFilter &filter, PickingFlags pickingFlags, PicksReturned returnFlag, std::vector< RayPicking::RayPickHit > &hits) override
Each mesh rendering system should implement this function that goes through all components and calls ...
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
bool isUnwantedType(const ComponentModel::Component &comp) const
Helper function used to determine if a given component belongs to an accepted entity type.
RenderLayers layerMask
Limit picking to the specified render layers. Pick all layers by default.
uint8_t currentLod
The assigned LoD of the current component.
uint8_t selectedLod
The selected LoD of the composite entity.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
Task id struct used to identify unique Task instances.