1#include "Systems/Core/RenderSystem.h"
2#include "Systems/Core/ClipShapeSystem.h"
4#include "Components/Core/MeshComponent.h"
6#include "Services/TaskManager.h"
8#include "Utilities/FrustumClassification.h"
10#include "Resources/Mesh.h"
12#include "Math/RayIntersection.h"
14#include "Foundation/Logging/Logger.h"
15#include "Foundation/Platform/Threads.h"
16#include "Foundation/Geometry/BoundingBox.hpp"
20#include "TwinCadModelSystem.h"
28Cogs::Core::TwinCadModelRayPickExtension::TwinCadModelRayPickExtension(RenderSystem* renderSystem, TwinCadModelSystem* cadModelSystem)
29: renderSystem(renderSystem),
30 cadModelSystem(cadModelSystem)
35 const glm::mat4& worldPickMatrix,
36 const glm::mat4& rawViewProjection,
37 const glm::mat4& viewMatrix,
41 std::vector<RayPicking::RayPickHit>& hits)
46 const size_t hitsBefore = hits.size();
54 for (
Cogs::SizeType start = 0; start < itemCount; start += batchSize) {
59 CpuInstrumentationScope(SCOPE_RAYPICK,
"executePickingQueryTask");
61 std::vector<RayPicking::RayPickHit> batchPickResults;
63 batchPickResults.reserve(10);
73 if (cadModelComp ==
nullptr)
continue;
75 const TwinCadModelData& cadModelData = cadModelSystem->getData(cadModelComp);
90 if (!renderData.meshComponent) {
94 Geometry::BoundingBox bboxWorld = renderSystem->getWorldBounds(&comp);
101 if (cadModelComp->allowClipping) {
102 bboxWorld.min = glm::max(bboxWorld.min, cadModelComp->minClipping);
103 bboxWorld.max = glm::min(bboxWorld.max, cadModelComp->maxClipping);
109 if (Geometry::isEmpty(bboxWorld)) {
113 if (frustumClassifyBoundingBox(worldPickMatrix, bboxWorld.min, bboxWorld.max) != FrustumPlanes::InsideAll) {
119 glm::mat4 localPickMatrix = worldPickMatrix * renderData.localToWorld;
121 std::vector<RayIntersectionHit> meshHits;
122 std::vector<FrustumPlanes> scratch;
123 if (!intersectMesh(meshHits,
129 static_cast<uint32_t
>(-1))) {
133 if (meshHits.empty()) {
139 uint32_t objectId = 0;
140 switch (texcoordInfo.format) {
141 case Cogs::DataFormat::R32_FLOAT:
142 objectId =
static_cast<uint32_t
>( *
reinterpret_cast<const float*
>(texcoordInfo.ptr + texcoordInfo.stride * meshHit.index.x));
144 case Cogs::DataFormat::R32G32_FLOAT:
145 objectId =
static_cast<uint32_t
>( *
reinterpret_cast<const float*
>(texcoordInfo.ptr + texcoordInfo.stride * meshHit.index.x));
147 case Cogs::DataFormat::R8_UINT:
148 objectId = *
reinterpret_cast<const uint8_t *
>(texcoordInfo.ptr + texcoordInfo.stride * meshHit.index.x);
150 case Cogs::DataFormat::R16_UINT:
151 objectId = *
reinterpret_cast<const uint16_t *
>(texcoordInfo.ptr + texcoordInfo.stride * meshHit.index.x);
153 case Cogs::DataFormat::R32_UINT:
154 objectId = *
reinterpret_cast<const uint32_t *
>(texcoordInfo.ptr + texcoordInfo.stride * meshHit.index.x);
156 case Cogs::DataFormat::Unknown:
159 LOG_WARNING_ONCE(logger,
"Unhandled texcoord format 0x%x",
static_cast<uint32_t
>(texcoordInfo.format));
162 if (addInstanceTexcoords && texcoordInfo.hasIdOffset) {
163 objectId += texcoordInfo.idOffset;
167 size_t objectIdIx = 4 * objectId + 3;
168 if ((cadModelData.attributeMapData.size() >= objectIdIx) && ((cadModelData.attributeMapData[objectIdIx] >> 2u) == 3u)) {
172 const glm::vec4 position = renderData.localToWorld * glm::vec4(meshHit.pos_, 1.f);
174 if (cadModelComp->allowClipping) {
176 const glm::vec3 minClipping = cadModelComp->minClipping;
177 const glm::vec3 maxClipping = cadModelComp->maxClipping;
178 if ((position.x < minClipping.x) || (maxClipping.x < position.x) ||
179 (position.y < minClipping.y) || (maxClipping.y < position.y) ||
180 (position.z < minClipping.z) || (maxClipping.z < position.z))
187 const ClipShapeData& clipData = context->clipShapeSystem->getData(clipComp);
188 if (clippedByClipComp(clipData, position)) {
193 const glm::vec4 clipPos = rawViewProjection * glm::vec4(position.x, position.y, position.z, 1.f);
195 if ((-clipPos.w < clipPos.z) && (clipPos.z < clipPos.w)) {
197 glm::vec4 viewPos = viewMatrix * position;
198 float viewDist = -viewPos.z;
201 if (batchPickResults[0].isBehind(ordinal, viewDist)) {
202 batchPickResults[0] = {comp, returnChildEntity, position, ordinal, viewDist, glm::vec2(objectId, objectId)};
207 batchPickResults.emplace_back(comp, returnChildEntity, position, ordinal, viewDist, glm::vec2(objectId, objectId));
213 if (!batchPickResults.empty()) {
214 LockGuard guard(batchLock);
217 hits = std::move(batchPickResults);
219 else if (batchPickResults[0] < hits[0]) {
220 hits[0] = batchPickResults[0];
225 hits.insert(hits.end(),
226 std::make_move_iterator(batchPickResults.begin()),
227 std::make_move_iterator(batchPickResults.end()));
235 return hitsBefore != hits.size();
Sets up a clipping shape that can be used by multiple entities.
T & getData(const ComponentType *component)
Get the data stored for the given component from the data pool storing objects of the specified templ...
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
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.
ComponentModel::ComponentHandle customRayPickHandling
Handle to the component that manages custom raypicking.
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.
Log implementation class.
PicksReturned
* Options for returning picking hits.
@ Closest
Return just the closest hit.
@ 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.
@ AddInstanceTexcoords
If mesh has an offset to IDs encoded in a per-instance texcoords stream, add this to the result.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
ComponentIndex SizeType
Type used to track the size of pools.
ComponentType * resolveComponent() const
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.
Task id struct used to identify unique Task instances.
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 ...