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);
167 pickables.erase(std::remove(pickables.begin(), pickables.end(), pickable), pickables.end());
171Cogs::Core::RayPicking::RayPickHit::RayPickHit(
const ComponentModel::Component& comp,
bool returnChildEntity,
const glm::vec3& pos,
float dist,
const glm::vec2& texCoords)
173 , textureCoords(texCoords)
176 if (returnChildEntity) {
178 root = getRootEntityId(&comp);
181 entity = getRootEntityId(&comp);
189 return entityTypeHash != RayPicking::NoPickEntityType &&
196 const glm::vec2& normPosition,
202 std::vector<RayPicking::RayPickHit>& hits)
204 const CameraData& cameraData = context->cameraSystem->getData(&camera);
206 const glm::mat4 rawViewProjection = cameraData.rawViewProjection;
208 const float sx = cameraData.viewportSize.x / radius;
209 const float sy = cameraData.viewportSize.y / radius;
210 const glm::mat4 worldPickMatrix = glm::mat4(sx, 0.f, 0.f, 0.f,
213 -normPosition.x * sx, -normPosition.y * sy, 0.f, 1.f) * rawViewProjection;
216 const glm::mat4 viewMatrix = cameraData.viewMatrix;
217 return pickImpl(context, worldPickMatrix, rawViewProjection, viewMatrix, filter, pickingFlags, returnFlag, hits);
222 const glm::vec3& startPos,
223 const glm::quat& rot,
229 std::vector<RayPicking::RayPickHit>& hits)
231 const float right = radius;
233 const float top = radius;
236 const float fFar = rayLength;
239 const glm::mat4 projectionMatrix(
246 const glm::mat4 worldViewMatrix = glm::toMat4(glm::conjugate(rot)) * glm::translate(glm::mat4(1.f), -startPos);
247 const glm::mat4 worldPickMatrix = projectionMatrix * worldViewMatrix;
249 return pickImpl(context, worldPickMatrix, worldPickMatrix, worldViewMatrix, filter, pickingFlags, returnFlag, hits);
254 Cogs::Core::MeshRayPickableBase::getTextureCoordinateInfo(
const Cogs::Core::Mesh& mesh)
256 TextureCoordinateInfo info{};
257 for (
size_t vertTypeI = 0; vertTypeI < VertexDataType::LastVertexType; ++vertTypeI) {
260 const DataStream& stream = mesh.streams[mesh.streamIndexes[vertexType]];
265 info.format = element.
format;
266 info.stride = stream.
stride;
277 case Cogs::Format::R16_UINT:
278 info.idOffset = *
reinterpret_cast<const uint16_t*
>(ptr);
279 info.hasIdOffset =
true;
281 case Cogs::Format::R32_UINT:
282 info.idOffset = *
reinterpret_cast<const uint32_t*
>(ptr);
283 info.hasIdOffset =
true;
285 case Cogs::Format::R32_FLOAT:
286 info.idOffset =
static_cast<uint32_t
>(std::round(*
reinterpret_cast<const float*
>(ptr)));
287 info.hasIdOffset =
true;
299bool Cogs::Core::MeshRayPickableBase::clippedByClipComp(
const ClipShapeData& clipData,
const glm::vec4& position)
301 switch (clipData.shape) {
303 if (glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
304 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
305 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position))) < 0.f) {
311 if (0.f <= glm::min(glm::min(glm::min(dot(clipData.
planes[0], position), dot(clipData.
planes[1], position)),
312 glm::min(dot(clipData.
planes[2], position), dot(clipData.
planes[3], position))),
313 glm::min(dot(clipData.
planes[4], position), dot(clipData.
planes[5], position)))) {
325glm::vec2 Cogs::Core::MeshRayPickableBase::getTextureCoords(
const TextureCoordinateInfo& textureInfo,
const RayIntersectionHit& hit,
const PickingFlags pickingFlags)
330 glm::vec2 t0, t1, t2;
331 switch (textureInfo.format) {
332 case Cogs::DataFormat::R32_FLOAT:
333 t0 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
334 if (!flatInterpolation) {
335 t1 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
336 t2 = glm::vec2(*
reinterpret_cast<const float*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
339 case Cogs::DataFormat::R32G32_FLOAT:
340 t0 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.x);
341 if (!flatInterpolation) {
342 t1 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.y);
343 t2 = *
reinterpret_cast<const glm::vec2*
>(textureInfo.ptr + textureInfo.stride * hit.index.z);
346 case Cogs::DataFormat::R8_UINT:
347 t0 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
348 if (!flatInterpolation) {
349 t1 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
350 t2 = glm::vec2(*
reinterpret_cast<const uint8_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
353 case Cogs::DataFormat::R16_UINT:
354 t0 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x));
355 if (!flatInterpolation) {
356 t1 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y));
357 t2 = glm::vec2(*
reinterpret_cast<const uint16_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z));
360 case Cogs::DataFormat::R32_UINT:
361 t0 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.x)));
362 if (!flatInterpolation) {
363 t1 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.y)));
364 t2 = glm::vec2(
static_cast<float>(*
reinterpret_cast<const uint32_t*
>(textureInfo.ptr + textureInfo.stride * hit.index.z)));
367 case Cogs::DataFormat::Unknown:
368 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
370 return glm::vec2(
static_cast<float>(textureInfo.idOffset));
374 LOG_WARNING_ONCE(logger,
"Unhandled texcoord format 0x%x",
static_cast<uint32_t
>(textureInfo.format));
380 if (flatInterpolation) {
384 rv = hit.bary.x * t0 + hit.bary.y * t1 + hit.bary.z * t2;
387 if (addInstanceTexcoords && textureInfo.hasIdOffset) {
388 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...).