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());
172Cogs::Core::RayPicking::RayPickHit::RayPickHit(
const ComponentModel::Component& comp,
bool returnChildEntity,
const glm::vec3& pos,
float dist,
const glm::vec2& texCoords)
174 , textureCoords(texCoords)
177 if (returnChildEntity) {
179 root = getRootEntityId(&comp);
182 entity = getRootEntityId(&comp);
190 return entityTypeHash != RayPicking::NoPickEntityType &&
197 const glm::vec2& normPosition,
203 std::vector<RayPicking::RayPickHit>& hits)
205 const CameraData& cameraData = context->cameraSystem->getData(&camera);
207 const glm::mat4 rawViewProjection = cameraData.rawViewProjection;
209 const float sx = cameraData.viewportSize.x / radius;
210 const float sy = cameraData.viewportSize.y / radius;
211 const glm::mat4 worldPickMatrix = glm::mat4(sx, 0.f, 0.f, 0.f,
214 -normPosition.x * sx, -normPosition.y * sy, 0.f, 1.f) * rawViewProjection;
217 const glm::mat4 viewMatrix = cameraData.viewMatrix;
218 return pickImpl(context, worldPickMatrix, rawViewProjection, viewMatrix, filter, pickingFlags, returnFlag, hits);
223 const glm::vec3& startPos,
224 const glm::quat& rot,
230 std::vector<RayPicking::RayPickHit>& hits)
232 const float right = radius;
234 const float top = radius;
237 const float fFar = rayLength;
240 const glm::mat4 projectionMatrix(
247 const glm::mat4 worldViewMatrix = glm::toMat4(glm::conjugate(rot)) * glm::translate(glm::mat4(1.f), -startPos);
248 const glm::mat4 worldPickMatrix = projectionMatrix * worldViewMatrix;
250 return pickImpl(context, worldPickMatrix, worldPickMatrix, worldViewMatrix, filter, pickingFlags, returnFlag, hits);
255 Cogs::Core::MeshRayPickableBase::getTextureCoordinateInfo(
const Cogs::Core::Mesh& mesh)
257 TextureCoordinateInfo info{};
258 for (
size_t vertTypeI = 0; vertTypeI < VertexDataType::LastVertexType; ++vertTypeI) {
261 const DataStream& stream = mesh.streams[mesh.streamIndexes[vertexType]];
266 info.format = element.
format;
267 info.stride = stream.
stride;
278 case Cogs::Format::R16_UINT:
279 info.idOffset = *
reinterpret_cast<const uint16_t*
>(ptr);
280 info.hasIdOffset =
true;
282 case Cogs::Format::R32_UINT:
283 info.idOffset = *
reinterpret_cast<const uint32_t*
>(ptr);
284 info.hasIdOffset =
true;
286 case Cogs::Format::R32_FLOAT:
287 info.idOffset =
static_cast<uint32_t
>(std::round(*
reinterpret_cast<const float*
>(ptr)));
288 info.hasIdOffset =
true;
300bool Cogs::Core::MeshRayPickableBase::clippedByClipComp(
const ClipShapeData& clipData,
const glm::vec4& position)
302 switch (clipData.shape) {
304 if (glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
305 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
306 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position))) < 0.f) {
312 if (0.f <= glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
313 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
314 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position)))) {
326glm::vec2 Cogs::Core::MeshRayPickableBase::getTextureCoords(
const TextureCoordinateInfo& textureInfo,
const RayIntersectionHit& hit,
const PickingFlags pickingFlags)
331 glm::vec2 t0, t1, t2;
332 switch (textureInfo.format) {
333 case Cogs::DataFormat::R32_FLOAT:
334 t0 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
335 if (!flatInterpolation) {
336 t1 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
337 t2 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
340 case Cogs::DataFormat::R32G32_FLOAT:
341 t0 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.x);
342 if (!flatInterpolation) {
343 t1 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.y);
344 t2 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.z);
347 case Cogs::DataFormat::R8_UINT:
348 t0 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
349 if (!flatInterpolation) {
350 t1 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
351 t2 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
354 case Cogs::DataFormat::R16_UINT:
355 t0 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
356 if (!flatInterpolation) {
357 t1 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
358 t2 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
361 case Cogs::DataFormat::R32_UINT:
362 t0 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x)));
363 if (!flatInterpolation) {
364 t1 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y)));
365 t2 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z)));
368 case Cogs::DataFormat::Unknown:
369 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
371 return glm::vec2(
static_cast<float>(textureInfo.idOffset));
375 LOG_WARNING_ONCE(logger,
"Unhandled texcoord format 0x%x",
static_cast<uint32_t
>(textureInfo.format));
381 if (flatInterpolation) {
385 rv = hit.bary.x * t0 + hit.bary.y * t1 + hit.bary.z * t2;
388 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
389 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.
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.
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.
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.
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...).