Cogs.Core
RayPickExtension.cpp
1
2#include "Foundation/Logging/Logger.h"
3
4#include "Utilities/Math.h"
5#include "Systems/Core/CameraSystem.h"
6#include "Systems/Core/TransformSystem.h"
7
8#include "Image360System.h"
9
10namespace {
11 using namespace Cogs::Core;
12 using namespace Cogs::Core::Image360;
13
15
16 void cubemapDecode(int& f, glm::vec2& uv, const glm::vec3& d)
17 {
18 glm::vec3 m = abs(d);
19 if (m.x > m.y && m.x > m.z) {
20 f = 0.f <= d.x ? 0 : 1; // 0 for +X face, 1 for -X face.
21 uv.x = -d.z / d.x; // -Z for +X face, Z for -X face.
22 uv.y = d.y / m.x; // Y for both +X and -X faces.
23 }
24 else if (m.y > m.z) {
25 f = 0.f <= d.y ? 2 : 3; // 2 for +Y face, 3 for -Y face.
26 uv.x = d.x / m.y; // X for both +Y and -Y faces.
27 uv.y = -d.z / d.y; // -Z for +Y face, Z for -Y face.
28 }
29 else {
30 f = 0.f <= d.z ? 4 : 5; // 4 for +Z face, 5 for -Z face.
31 uv.x = d.x / d.z; // X for +Z face, -X for -Z face.
32 uv.y = d.y / m.z; // Y for both +Z and -Z faces.
33 }
34 uv = 0.5f * (uv + glm::vec2(1.0));
35 }
36
37 bool lookupDistance(float& dist, const RendererExtensionData& rendererData, const DynamicLodTree& lodTree, const Config& conf, const glm::vec3 dir)
38 {
39 int f;
40 glm::vec2 uv_;
41 cubemapDecode(f, uv_, dir);
42
43 glm::vec2 uv = uv_;
44 int ix = lodTree.data[f];
45 for (size_t l = 0; ix < -1 && l <= conf.treeMaxSize; l++) {
46 uv = 2.f * uv;
47 glm::vec2 o = glm::floor(uv);
48 uv = uv - o;
49 ix = -ix + 2 * int(o.y) + int(o.x);
50 ix = lodTree.data[ix];
51 }
52
53 if (ix < 0) { // base level should always have data
54 ix = f;
55 uv = uv_;
56 }
57 else {
58 if ((ix & 4) != 0) {
59 uv = 0.5f * (uv + glm::vec2(ix & 1, (ix >> 1) & 1));
60 }
61 ix = ix >> 3;
62 }
63
64 assert(0 <= ix);
65 if (size_t(ix) < rendererData.depth.tilesData.size()) {
66 const Cogs::Memory::MemoryBuffer* buffer = rendererData.depth.tilesData[ix].get();
67 if (buffer) {
68 assert(buffer->size() == sizeof(uint16_t) * conf.baseSize * conf.baseSize);
69 glm::ivec2 loc = glm::clamp(glm::ivec2(glm::vec2(float(conf.baseSize)) * uv), glm::ivec2(0), glm::ivec2(conf.baseSize-1));
70
71 uint16_t value = ((const uint16_t*)buffer->data())[loc.y * conf.baseSize + loc.x];
72 if (value == rendererData.noDataDepth) {
73 return false;
74 }
75 dist = rendererData.depth.scale * float(value) + rendererData.depth.bias;
76 return true;
77 }
78 }
79 return false;
80 }
81
82}
83
84
85Cogs::Core::Image360::RayPickExtension::RayPickExtension(Image360System* im360System) : im360System(im360System) {}
86
88 const CameraComponent& camera,
89 const glm::vec2& normPosition,
90 float /*rayLength*/,
91 float /*radius*/,
92 PickingFlags pickingFlags,
93 PicksReturned returnFlag,
94 const RayPicking::RayPickFilter& filter,
95 std::vector<RayPicking::RayPickHit>& hits)
96{
97 const CameraData& cameraData = context->cameraSystem->getData(&camera);
98 const float clipSpaceNearPlane = context->variables->get("renderer.reverseDepth", false) ? 1.f : -1.f;
99
100 const bool returnChildEntity = (pickingFlags & PickingFlags::ReturnChildEntity) == PickingFlags::ReturnChildEntity;
101
102 bool hitSomething = false;
103 for (Image360Component& comp : im360System->pool) {
104 if (!comp.isPickable() || filter.isUnwantedType(comp)) { continue; }
105
106 const RenderComponent* renderComp = comp.getComponent<RenderComponent>();
107 if (renderComp && !renderComp->isVisibleInLayer(filter.layerMask)) { continue; }
108
109 const Image360Data& data = im360System->getData(&comp);
110 if (data.state != Image360Data::State::Running) { continue; }
111 if (!data.config.hasDepth) { continue; }
112 if (data.rendererData.depth.tilesData.empty()) { continue; }
113
114 const glm::mat3 localFromView = data.rendererData.localFromWorld * glm::mat3(cameraData.inverseViewMatrix);
115 const glm::mat3 viewFromLocal = glm::mat3(cameraData.viewMatrix) * data.rendererData.worldFromLocal;
116
117 const glm::mat4 localFromClip = glm::mat4(localFromView) * cameraData.inverseProjectionMatrix;
118 const glm::vec3 dir = glm::normalize(euclidean(localFromClip * glm::vec4(normPosition, clipSpaceNearPlane, 1)));
119
120 float dist = 0.0;
121 if (lookupDistance(dist, data.rendererData, data.lodTree, data.config, dir)) {
122
123 // Transform from 360 image frame to view frame. These frame must have the same
124 // origin so there is no translation.
125 glm::vec3 posView = viewFromLocal * (dist * dir);
126 glm::vec4 posClip = cameraData.rawProjectionMatrix * glm::vec4(posView, 1.f);
127
128 glm::vec4 posWorld_h = cameraData.inverseViewMatrix * glm::vec4(posView, 1.f);
129 float depth = -posView.z;
130 if (0 <= depth) {
131 if (returnFlag == PicksReturned::Closest && !hits.empty()) {
132 if (depth < hits[0].distance) {
133 hits[0] = {comp, returnChildEntity, euclidean(posWorld_h), depth};
134 hitSomething = true;
135 }
136 // else, the intersection we found is further, so don't do anything
137 }
138 else {
139 hits.emplace_back(comp, returnChildEntity, euclidean(posWorld_h), depth);
140 hitSomething = true;
141 }
142 }
143 }
144 }
145
146 // Sort hits based on distance
147 if (returnFlag == PicksReturned::AllSorted) {
148 std::sort(hits.begin(), hits.end());
149 }
150
151 return hitSomething;
152}
ComponentType * getComponent() const
Definition: Component.h:159
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.
Definition: Context.h:83
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
Base component for all rendering content.
constexpr bool isVisibleInLayer(RenderLayers layerMask) const
Check if the entity should be visible in the given layer mask.
constexpr bool isPickable() const
Check if the entity is pickable or not.
Log implementation class.
Definition: LogManager.h:139
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
PicksReturned
  * Options for returning picking hits.
Definition: PickingFlags.h:40
@ Closest
Return just the closest hit.
@ AllSorted
Return all hits sorted based on distance from the ray start, closest first.
PickingFlags
Options for COGS picking.
Definition: PickingFlags.h:12
@ ReturnChildEntity
Return ID if sub-entity picked, not set: return root parent entity.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
Definition: CameraSystem.h:67
glm::mat4 rawProjectionMatrix
Projection matrix that has not been adjusted by the renderer, and is thus appropriate for direct scre...
Definition: CameraSystem.h:129
uint32_t baseSize
Base image size of a cached tile. From json.
Definition: Image360.h:46
bool pickCamera(Context *context, const CameraComponent &camera, const glm::vec2 &normPosition, float, float, 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 isUnwantedType(const ComponentModel::Component &comp) const
Helper function used to determine if a given component belongs to an accepted entity type.
Definition: RayPick.cpp:187
RenderLayers layerMask
Limit picking to the specified render layers. Pick all layers by default.
Definition: RayPick.h:70