5#include "Components/Core/CameraComponent.h"
6#include "Components/Core/TransformComponent.h"
8#include "Systems/Core/CameraSystem.h"
9#include "Systems/Core/ClipShapeSystem.h"
11#include "Services/Variables.h"
13#include "Platform/Instrumentation.h"
15#include "Resources/Mesh.h"
16#include "Resources/Buffer.h"
18#include "Math/RayIntersection.h"
20#include "Foundation/ComponentModel/Entity.h"
21#include "Foundation/Logging/Logger.h"
42 if (transformComponent) {
44 return getRootEntityId(parentTransform);
47 return container->
getId();
53 void filterHits(std::vector<RayPicking::RayPickHit>& hits,
float rayLength,
const glm::vec3& rayStartPos,
PickingFlags pickingFlags)
55 const float rayLengthSq = rayLength * rayLength;
56 for (
auto it = hits.begin(); it != hits.end();) {
60 if (glm::distance2(it->position, rayStartPos) > rayLengthSq) {
64 else if ((pickingFlags & PickingFlags::RemoveDuplicateEntities) == PickingFlags::RemoveDuplicateEntities) {
65 erase = std::find_if(std::next(it), hits.end(),
67 return it->entity == otherHit.entity;
71 else if ((pickingFlags & PickingFlags::RemoveDuplicates) == PickingFlags::RemoveDuplicates) {
72 erase = std::find_if(std::next(it), hits.end(),
74 return it->entity == otherHit.entity && it->textureCoords == otherHit.textureCoords;
79 std::swap(*it, hits.back());
91 const glm::vec2& cameraPosition,
97 std::vector<RayPicking::RayPickHit>& hits)
99 CpuInstrumentationScope(SCOPE_RAYPICK,
"pickCamera");
102 LOG_WARNING(logger,
"Camera picking is not enabled.");
105 const CameraData& cameraData = context->cameraSystem->getData(&camera);
107 glm::vec2 normPos = 2.f * (cameraPosition + 0.5f) / cameraData.viewportSize - 1.f;
111 bool hitSomething =
false;
113 hitSomething |= pickable->pickCamera(context, camera, normPos, rayLength, radius, pickingFlags, retFlag, filter, hits);
118 const glm::vec3 cameraPos = glm::vec3(cameraData.inverseViewMatrix[3]);
119 filterHits(hits, rayLength, cameraPos, pickingFlags);
122 std::sort(hits.begin(), hits.end());
130 const glm::vec3 & position,
131 const glm::quat & rotation,
137 std::vector<RayPicking::RayPickHit>& hits)
139 CpuInstrumentationScope(SCOPE_RAYPICK,
"pickRay");
144 bool hitSomething =
false;
146 pickable->pickRay(context, position, rotation, rayLength, radius, pickingFlags, retFlag, filter, hits);
150 filterHits(hits, rayLength, position, pickingFlags);
153 std::sort(hits.begin(), hits.end());
162 pickables.push_back(pickable);
163 std::sort(pickables.begin(), pickables.end(), [](
const IRayPickable* a,
const IRayPickable* b) { return a->order < b->order; });
168 pickables.erase(std::remove(pickables.begin(), pickables.end(), pickable), pickables.end());
171Cogs::Core::RayPicking::RayPickFilter::RayPickFilter(std::span<const RenderLayers> ordering_,
RenderLayers layerMask,
size_t entityTypeHash)
172: layerMask(layerMask),
173 entityTypeHash(entityTypeHash)
175 size_t m = std::min(std::size(ordering), ordering_.size());
176 for (
size_t i = 0; i < m; i++) {
177 ordering[i] = ordering_[i];
179 for (
size_t i = m; i < std::size(ordering); i++) {
180 ordering[i] = RenderLayers::All;
185Cogs::Core::RayPicking::RayPickHit::RayPickHit(
const RenderComponent& comp,
bool returnChildEntity,
const glm::vec3& pos,
Ordinal ordinal,
float dist,
const glm::vec2& texCoords)
187 , textureCoords(texCoords)
191 if (returnChildEntity) {
193 root = getRootEntityId(&comp);
196 entity = getRootEntityId(&comp);
204 return entityTypeHash != RayPicking::NoPickEntityType &&
211 const glm::vec2& normPosition,
217 std::vector<RayPicking::RayPickHit>& hits)
219 const CameraData& cameraData = context->cameraSystem->getData(&camera);
221 const glm::mat4 rawViewProjection = cameraData.rawViewProjection;
223 const float sx = cameraData.viewportSize.x / radius;
224 const float sy = cameraData.viewportSize.y / radius;
225 const glm::mat4 worldPickMatrix = glm::mat4(sx, 0.f, 0.f, 0.f,
228 -normPosition.x * sx, -normPosition.y * sy, 0.f, 1.f) * rawViewProjection;
231 const glm::mat4 viewMatrix = cameraData.viewMatrix;
232 return pickImpl(context, worldPickMatrix, rawViewProjection, viewMatrix, filter, pickingFlags, returnFlag, hits);
237 const glm::vec3& startPos,
238 const glm::quat& rot,
244 std::vector<RayPicking::RayPickHit>& hits)
246 const float right = radius;
248 const float top = radius;
251 const float fFar = rayLength;
254 const glm::mat4 projectionMatrix(
261 const glm::mat4 worldViewMatrix = glm::toMat4(glm::conjugate(rot)) * glm::translate(glm::mat4(1.f), -startPos);
262 const glm::mat4 worldPickMatrix = projectionMatrix * worldViewMatrix;
264 return pickImpl(context, worldPickMatrix, worldPickMatrix, worldViewMatrix, filter, pickingFlags, returnFlag, hits);
269 Cogs::Core::MeshRayPickableBase::getTextureCoordinateInfo(
const Cogs::Core::Mesh& mesh)
271 TextureCoordinateInfo info{};
272 for (
size_t vertTypeI = 0; vertTypeI < VertexDataType::LastVertexType; ++vertTypeI) {
275 const DataStream& stream = mesh.streams[mesh.streamIndexes[vertexType]];
280 info.format = element.
format;
281 info.stride = stream.
stride;
292 case Cogs::Format::R16_UINT:
293 info.idOffset = *
reinterpret_cast<const uint16_t*
>(ptr);
294 info.hasIdOffset =
true;
296 case Cogs::Format::R32_UINT:
297 info.idOffset = *
reinterpret_cast<const uint32_t*
>(ptr);
298 info.hasIdOffset =
true;
300 case Cogs::Format::R32_FLOAT:
301 info.idOffset =
static_cast<uint32_t
>(std::round(*
reinterpret_cast<const float*
>(ptr)));
302 info.hasIdOffset =
true;
314bool Cogs::Core::MeshRayPickableBase::clippedByClipComp(
const ClipShapeData& clipData,
const glm::vec4& position)
316 switch (clipData.shape) {
318 if (glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
319 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
320 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position))) < 0.f) {
326 if (0.f <= glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
327 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
328 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position)))) {
340glm::vec2 Cogs::Core::MeshRayPickableBase::getTextureCoords(
const TextureCoordinateInfo& textureInfo,
const RayIntersectionHit& hit,
const PickingFlags pickingFlags)
345 glm::vec2 t0, t1, t2;
346 switch (textureInfo.format) {
347 case Cogs::DataFormat::R32_FLOAT:
348 t0 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
349 if (!flatInterpolation) {
350 t1 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
351 t2 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
354 case Cogs::DataFormat::R32G32_FLOAT:
355 t0 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.x);
356 if (!flatInterpolation) {
357 t1 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.y);
358 t2 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.z);
361 case Cogs::DataFormat::R8_UINT:
362 t0 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
363 if (!flatInterpolation) {
364 t1 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
365 t2 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
368 case Cogs::DataFormat::R16_UINT:
369 t0 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
370 if (!flatInterpolation) {
371 t1 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
372 t2 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
375 case Cogs::DataFormat::R32_UINT:
376 t0 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x)));
377 if (!flatInterpolation) {
378 t1 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y)));
379 t2 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z)));
382 case Cogs::DataFormat::Unknown:
383 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
385 return glm::vec2(
static_cast<float>(textureInfo.idOffset));
389 LOG_WARNING_ONCE(logger,
"Unhandled texcoord format 0x%x",
static_cast<uint32_t
>(textureInfo.format));
395 if (flatInterpolation) {
399 rv = hit.bary.x * t0 + hit.bary.y * t1 + hit.bary.z * t2;
402 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
403 rv.x = float(uint32_t(rv.x) + textureInfo.idOffset);
Base class for Component instances.
class Entity * getContainer() const
Get the container currently owning this component instance.
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
constexpr size_t getId() const noexcept
Get the unique identifier of this entity.
constexpr void * getUserData() const noexcept
Get user data.
CameraFlags flags
Camera behavior flags.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Interface for modules implementing custom picking.
COGSCORE_DLL_API bool pickCamera(Context *context, const CameraComponent &camera, const glm::vec2 &normPosition, float, float radius, PickingFlags pickingFlags, PicksReturned returnFlag, const RayPicking::RayPickFilter &filter, std::vector< RayPicking::RayPickHit > &hits) override
Do a ray pick from a normalized screen space position in the camera direction and return all hits.
COGSCORE_DLL_API bool pickRay(Context *context, const glm::vec3 &startPos, const glm::quat &rot, float rayLength, float radius, PickingFlags pickingFlags, PicksReturned returnFlag, const RayPicking::RayPickFilter &filter, std::vector< RayPicking::RayPickHit > &hits) override
Do a ray pick from a position and orientation in world space and return all hits.
COGSCORE_DLL_API bool pickRay(Context *context, const glm::vec3 &position, const glm::quat &rotation, float rayLength, float radius, PickingFlags pickingFlags, PicksReturned returnFlag, const RayPicking::RayPickFilter &filter, std::vector< RayPicking::RayPickHit > &hits)
RayPicking using defined ray starting from pos.
COGSCORE_DLL_API void addPickable(IRayPickable *pickable)
Add Component / System for custom picking.
COGSCORE_DLL_API bool pickCamera(Context *context, const CameraComponent &camera, const glm::vec2 &cameraPosition, float rayLength, float radius, PickingFlags pickingFlags, PicksReturned returnFlag, const RayPicking::RayPickFilter &filter, std::vector< RayPicking::RayPickHit > &hits)
RayPicking using ray from camera position along camera viewing direction.
COGSCORE_DLL_API void removePickable(IRayPickable *pickable)
Remove Component / System from custom picking.
std::vector< IRayPickable * > pickables
Storage for registered pick extensions (addPickable)
static constexpr glm::vec2 NoPickTextureCoords
Marks no match in texture.
Base component for all rendering content.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ InvertedCube
Clip the inside of a cube.
@ Cube
Clip the outside of a cube,.
PicksReturned
* Options for returning picking hits.
@ AllUnsorted
Return all hits in no specific order.
@ AllSorted
Return all hits sorted based on distance from the ray start, closest first.
@ EnablePicking
Supports picking.
PickingFlags
Options for COGS picking.
@ FlatTexcoordInterpolation
Do not interpolate texture coordinates. Needed if integer IDs are encoded as texture coordinates.
@ AddInstanceTexcoords
If mesh has an offset to IDs encoded in a per-instance texcoords stream, add this to the result.
RenderLayers
Contains common render layers.
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
@ InstanceData
Per instance data.
@ TextureCoordinate
Texture coordinate semantic.
COGSFOUNDATION_API class Component * resolve() const
Resolve the handle, returning a pointer to the held Component instance.
void * data()
Get a pointer to the buffer data.
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
glm::vec4 planes[6]
Clipping planes in world space.
Contains a stream of data used by Mesh resources.
uint32_t numElements
Number of elements of the type given by format contained in data.
uint32_t offset
Byte offset from the start of the buffer.
VertexFormatHandle format
A pointer to the format describing the contents of the byte buffer.
uint32_t stride
Element stride.
Cogs::Core::ResourceBufferHandle buffer
Data buffer.
Holds extra housekeeping data for an Entity instance.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
bool hasStream(VertexDataType::EVertexDataType type) const
Check if the Mesh has a DataStream for the given type.
bool isUnwantedType(const ComponentModel::Component &comp) const
Helper function used to determine if a given component belongs to an accepted entity type.
EntityId entity
The EntityId picked.
EVertexDataType
Contains data types.
Vertex element structure used to describe a single data element in a vertex for the input assembler.
InputType inputType
Input type of the element, vertex or instance data.
DataFormat format
Format of the element.
uint16_t offset
Offset in bytes from the vertex position in memory.
uint16_t semanticIndex
Index for the semantic mapping.
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).