Cogs.Core
RayIntersection.cpp
1
2#include "Foundation/Logging/Logger.h"
3
4#include "Utilities/FrustumClassification.h"
5
6#include "RayIntersection.h"
7
8#include "Math/RayTriangleIntersection.h"
9#include "Math/RayBoxIntersection.h"
10#include "Resources/Mesh.h"
11#include "Resources/Buffer.h"
12
13#include <glm/gtc/packing.hpp>
14
15namespace {
16 using namespace Cogs::Geometry;
17 using namespace Cogs::Core;
18
19 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RayIntersection");
20
21 struct PosStreamRef
22 {
23 const uint8_t* ptr = nullptr;
24 Cogs::DataFormat format = Cogs::DataFormat::Unknown;
25 uint32_t stride = 0;
26 uint32_t count = 0;
27 };
28
29 struct IxStreamRef
30 {
31 const uint8_t* ptr = nullptr;
32 uint32_t stride = 0;
33 uint32_t count = 0;
34 };
35
36 struct SubMeshStreamRef
37 {
38 const SubMesh* ptr = nullptr;
39 uint32_t stride = 0;
40 uint32_t count = 0;
41 };
42
43 bool intersectThickRayAndPoint(glm::vec3& intersection, const glm::mat4& localPickMatrix, const glm::vec3& l0)
44 {
45 glm::vec4 h0 = localPickMatrix * glm::vec4(l0.x, l0.y, l0.z, 1.f);
46 glm::vec2 p0 = (1.f / h0.w) * glm::vec2(h0.x, h0.y);
47 if (glm::dot(p0, p0) <= 1.f) {
48 intersection = l0;
49 return true;
50 }
51 return false;
52 }
53
54 // Intersects thick ray (specified by the frustum in which vertexPickCoords lie) and a line segment.
55 bool intersectThickRayAndLineSegment(glm::vec3& intersection, glm::vec2 barycentric, const glm::mat4& localPickMatrix, const glm::vec3& pt0, const glm::vec3& pt1)
56 {
57 barycentric = glm::vec2(-1.0f);
58 glm::vec3 l0 = pt0;
59 glm::vec3 l1 = pt1;
60
61 glm::vec4 h0 = localPickMatrix * glm::vec4(l0.x, l0.y, l0.z, 1.f);
62 glm::vec4 h1 = localPickMatrix * glm::vec4(l1.x, l1.y, l1.z, 1.f);
63
64 // clip against the near-plane (to avoid numerical issues wrt projection)
65 if (h0.z < -h0.w && h1.z < -h1.w) {
66 return false; // completely in front of the near plane
67 }
68 else if (h0.z < -h0.w) {
69 // (1-t)z0 + t z1 = -((1-t)w0 + tw1)
70 // z0 - tz0 + tz1 = -w0 + tw0 - tw1
71 // z0 + t(z1-z0) = -w0 + t(w0 - w1)
72 // t(z1-z0 + w1 - w0) = -(w0 + z0)
73 // t = -(w0 + z0)/(z1-z0 + w1 - w0)
74 float t = -(h0.w + h0.z) / (h1.z - h0.z + h1.w - h0.w);
75 h0 = glm::mix(h0, h1, t);
76 l0 = glm::inverse(localPickMatrix) * h0;
77 }
78 else if (h1.z < -h1.w) {
79 float t = -(h0.w + h0.z) / (h1.z - h0.z + h1.w - h0.w);
80 h1 = glm::mix(h0, h1, t);
81 l1 = glm::inverse(localPickMatrix) * h1;
82 }
83
84 // project and solve 2D problem
85 glm::vec2 p0 = (1.f / h0.w) * glm::vec2(h0.x, h0.y);
86 glm::vec2 p1 = (1.f / h1.w) * glm::vec2(h1.x, h1.y);
87 glm::vec2 v01 = p1 - p0;
88 float t;
89 float d2 = glm::dot(v01, v01);
90 if (std::numeric_limits<float>::epsilon() < d2) {
91 // project origin onto v01 and clamp it onto the line segment
92 t = glm::clamp(-glm::dot(p0, v01) / d2, 0.f, 1.f);
93 }
94 else {
95 // otherwise, if v01 is degenerate, we leave t=0.5 and use the midpoint
96 t = 0.5f;
97 }
98
99 // pt is the nearest point on [p0,p1]
100 glm::vec2 pt = glm::mix(p0, p1, t);
101
102 // and check if it is inside the pixel ellipsiod
103 if (glm::dot(pt, pt) <= 1.f) {
104 // do perspective correction
105 glm::vec2 w((1.f - t) / h0.w, t / h1.w);
106 glm::vec2 b = (1.f / (w.x + w.y)) * w;
107 intersection = b.x * l0 + b.y * l1;
108 barycentric = b;
109 return true;
110 }
111 return false;
112 }
113
114 // Simplified line intersection code where the intersection line is the z-axis.
115 bool intersectTriangleBarycentric(glm::vec3& barycentric, const glm::mat4& localPickMatrix, const glm::vec3& l0, const glm::vec3& l1, const glm::vec3& l2)
116 {
117 glm::vec4 h0 = localPickMatrix * glm::vec4(l0.x, l0.y, l0.z, 1.f);
118 glm::vec4 h1 = localPickMatrix * glm::vec4(l1.x, l1.y, l1.z, 1.f);
119 glm::vec4 h2 = localPickMatrix * glm::vec4(l2.x, l2.y, l2.z, 1.f);
120
121 if ((h0.z < -h0.w) && (h1.z < -h1.w) && (h2.z < -h2.w)) {
122 return false; // completely in front of the near plane, reject
123 }
124 else if ((h0.z < -h0.w) || (h1.z < -h1.w) || (h2.z < -h2.w)) {
125 // intersecting the near plane, solve problem in R3.
126 glm::mat4 Q = glm::inverse(localPickMatrix);
127 glm::vec4 R0 = Q * glm::vec4(0.f, 0.f, -1.f, 1.f);
128 glm::vec3 r0 = (1.f / R0.w) * glm::vec3(R0.x, R0.y, R0.z);
129 glm::vec4 R1 = Q * glm::vec4(0.f, 0.f, 1.f, 1.f);
130 glm::vec3 r1 = (1.f / R1.w) * glm::vec3(R1.x, R1.y, R1.z);
131
132 glm::vec3 intersection;
133 bool front;
134 return intersect(l0, l1, l2, r0, r1 - r0, intersection, barycentric, front);
135 }
136
137 glm::vec2 p0 = (1.f / h0.w) * glm::vec2(h0.x, h0.y);
138 glm::vec2 p1 = (1.f / h1.w) * glm::vec2(h1.x, h1.y);
139 glm::vec2 p2 = (1.f / h2.w) * glm::vec2(h2.x, h2.y);
140 glm::vec2 v01 = p1 - p0;
141 glm::vec2 v12 = p2 - p1;
142 glm::vec2 v20 = p0 - p2;
143
144 // signed areas
145 glm::vec4 areas(v12.x * p1.y - p1.x * v12.y, // = 2*area[p1, p2, origin]
146 v20.x * p2.y - p2.x * v20.y, // = 2*area[p2, p0, origin]
147 v01.x * p0.y - p0.x * v01.y, // = 2*area[p0, p1, origin]
148 v01.x * v20.y - v20.x * v01.y); // = 2*area[p0, p1, p2]
149
150 // Assert that the triangle hasn't degenerated to a line or point from the projection
151 if (std::numeric_limits<float>::epsilon() < glm::abs(areas.w)) {
152
153 // check sign of all areas
154 glm::bvec4 signs = glm::lessThan(areas, glm::vec4(0.f));
155
156 // if all signs are equal, the point is inside.
157 if (glm::all(glm::equal(glm::bvec4(signs.w), signs))) {
158 glm::vec3 w = glm::vec3(areas.x / h0.w, areas.y / h1.w, areas.z / h2.w);
159 barycentric = (1.f / (w.x + w.y + w.z)) * w;
160// intersection = b.x * l0 + b.y * l1 + b.z * l2;
161 return true;
162 }
163 }
164
165 return false;
166 }
167
168
169 // Simplified line intersection code where the intersection line is the z-axis.
170 bool intersectTriangle(glm::vec3& intersection, glm::vec3 &barycenric, const glm::mat4& localPickMatrix, const glm::vec3& l0, const glm::vec3& l1, const glm::vec3& l2)
171 {
172 bool result = intersectTriangleBarycentric(barycenric, localPickMatrix, l0, l1, l2);
173 if (result) {
174 intersection = barycenric.x * l0 + barycenric.y * l1 + barycenric.z * l2;
175 }
176 return result;
177 }
178
179 template<typename Fetch>
180 void classify(FrustumPlanes* vertexFlags,
181 const glm::mat4& localPickMatrix,
182 const PosStreamRef& positions)
183 {
184 for (size_t i = 0; i < positions.count; i++) {
185 glm::vec4 h = localPickMatrix * glm::vec4(Fetch::fetch(positions, i), 1.f);
186 vertexFlags[i] = (( h.x <= h.w ? FrustumPlanes::InsidePosX : FrustumPlanes::InsideNone) |
187 (-h.w <= h.x ? FrustumPlanes::InsideNegX : FrustumPlanes::InsideNone) |
188 ( h.y <= h.w ? FrustumPlanes::InsidePosY : FrustumPlanes::InsideNone) |
189 (-h.w <= h.y ? FrustumPlanes::InsideNegY : FrustumPlanes::InsideNone) |
190 ( h.z <= h.w ? FrustumPlanes::InsidePosZ : FrustumPlanes::InsideNone) |
191 (-h.w <= h.z ? FrustumPlanes::InsideNegZ : FrustumPlanes::InsideNone));
192 }
193 }
194
195
196 template<size_t IndexStride, typename Fetch>
197 void intersectPoints(std::vector<RayIntersectionHit>& hits,
198 const glm::mat4& localPickMatrix,
199 const FrustumPlanes* vertexFlags,
200 const PosStreamRef& positions,
201 const IxStreamRef& indices,
202 const size_t a,
203 const size_t b,
204 const float scale)
205 {
206 static_assert(IndexStride == 0 || IndexStride == 2 || IndexStride == 4);
207 for (size_t i = a; i < b; i++) {
208
209 size_t ix0;
210 if constexpr (IndexStride == 2) {
211 ix0 = reinterpret_cast<const uint16_t*>(indices.ptr)[i];
212 if (positions.count <= ix0) continue;
213 }
214 else if constexpr (IndexStride == 4) {
215 ix0 = reinterpret_cast<const uint32_t*>(indices.ptr)[i];
216 if (positions.count <= ix0) continue;
217 }
218 else {
219 ix0 = i;
220 }
221
222 if (vertexFlags[ix0] == FrustumPlanes::InsideAll) { // bbox reject failed
223 glm::vec3 intersection;
224 glm::vec3 barycentric = glm::vec3(1.0f, 0.0f, 0.0f);
225 if (intersectThickRayAndPoint(intersection, localPickMatrix,
226 Fetch::fetch(positions, ix0))) {
227 hits.emplace_back(RayIntersectionHit{ scale * intersection, barycentric, glm::uvec3(ix0, ix0, ix0) });
228 }
229 }
230 }
231 }
232
233
234 template<size_t IndexStride, typename Fetch>
235 void intersectLines(std::vector<RayIntersectionHit>& hits,
236 const glm::mat4& localPickMatrix,
237 const FrustumPlanes* vertexFlags,
238 const PosStreamRef& positions,
239 const IxStreamRef& indices,
240 const size_t a,
241 const size_t b,
242 const size_t indexStep,
243 const float scale)
244 {
245 static_assert(IndexStride == 0 || IndexStride == 2 || IndexStride == 4);
246 for (size_t i = a; i < b; i += indexStep) {
247
248 size_t ix0, ix1;
249 if constexpr (IndexStride == 2) {
250 ix0 = reinterpret_cast<const uint16_t*>(indices.ptr)[i + 0];
251 ix1 = reinterpret_cast<const uint16_t*>(indices.ptr)[i + 1];
252 if (positions.count <= ix0 || positions.count <= ix1) continue;
253 }
254 else if constexpr (IndexStride == 4) {
255 ix0 = reinterpret_cast<const uint32_t*>(indices.ptr)[i + 0];
256 ix1 = reinterpret_cast<const uint32_t*>(indices.ptr)[i + 1];
257 if (positions.count <= ix0 || positions.count <= ix1) continue;
258 }
259 else {
260 ix0 = i + 0;
261 ix1 = i + 1;
262 }
263
264 if ((vertexFlags[ix0] | vertexFlags[ix1]) == FrustumPlanes::InsideAll) { // bbox reject failed
265
266 glm::vec3 intersection;
267 glm::vec2 barycentric;
268 if (intersectThickRayAndLineSegment(intersection, barycentric, localPickMatrix,
269 Fetch::fetch(positions, ix0),
270 Fetch::fetch(positions, ix1))) {
271 hits.emplace_back(RayIntersectionHit{ scale * intersection, glm::vec3(1.f, 0.f, 0.f), glm::uvec3(ix0, ix1, 0) });
272 }
273 }
274 }
275 }
276
277 template<size_t IndexStride, typename Fetch>
278 void intersectTriangles(std::vector<RayIntersectionHit>& hits,
279 const glm::mat4& localPickMatrix,
280 const FrustumPlanes* vertexFlags,
281 const PosStreamRef& positions,
282 const IxStreamRef& indices,
283 const size_t a,
284 const size_t b,
285 const size_t indexStep,
286 const float scale)
287 {
288 static_assert(IndexStride == 0 || IndexStride == 2 || IndexStride == 4);
289 for (size_t i = a; i + 2 < b; i += indexStep) {
290
291 size_t ix0, ix1, ix2;
292 if constexpr (IndexStride == 2) {
293 ix0 = reinterpret_cast<const uint16_t*>(indices.ptr)[i + 0];
294 ix1 = reinterpret_cast<const uint16_t*>(indices.ptr)[i + 1];
295 ix2 = reinterpret_cast<const uint16_t*>(indices.ptr)[i + 2];
296 if (positions.count <= ix0 || positions.count <= ix1 || positions.count <= ix2) continue;
297 }
298 else if constexpr (IndexStride == 4) {
299 ix0 = reinterpret_cast<const uint32_t*>(indices.ptr)[i + 0];
300 ix1 = reinterpret_cast<const uint32_t*>(indices.ptr)[i + 1];
301 ix2 = reinterpret_cast<const uint32_t*>(indices.ptr)[i + 2];
302 if (positions.count <= ix0 || positions.count <= ix1 || positions.count <= ix2) continue;
303 }
304 else {
305 ix0 = i + 0;
306 ix1 = i + 1;
307 ix2 = i + 2;
308 }
309
310 if ((vertexFlags[ix0] | vertexFlags[ix1] | vertexFlags[ix2]) == FrustumPlanes::InsideAll) {
311
312 glm::vec3 intersection;
313 glm::vec3 barycentric;
314 if (intersectTriangle(intersection, barycentric, localPickMatrix,
315 Fetch::fetch(positions, ix0),
316 Fetch::fetch(positions, ix1),
317 Fetch::fetch(positions, ix2))) {
318 hits.emplace_back(RayIntersectionHit{ scale * intersection, barycentric, glm::uvec3(ix0, ix1, ix2) });
319 }
320 }
321 }
322 }
323
324 template<size_t IndexStride, typename Fetch>
325 void intersectSubMesh(std::vector<RayIntersectionHit>& hits,
326 const glm::mat4& localPickMatrix,
327 const FrustumPlanes* vertexFlags,
328 const SubMeshStreamRef& subMeshes,
329 const IxStreamRef& indices,
330 const PosStreamRef& positions,
331 const Mesh* mesh,
332 const float scale = 1.f)
333 {
334 for (size_t i = 0; i < subMeshes.count; i++) {
335 const SubMesh& subMesh = subMeshes.ptr[i];
336
337 size_t a, b;
338 if (subMesh.numIndexes == uint32_t(-1)) {
339 a = 0;
340 b = mesh->getCount();
341 }
342 else {
343 a = subMesh.startIndex;
344 b = a + subMesh.numIndexes;
345 }
346
347 if constexpr (IndexStride == 0) {
348 if (positions.count < a || positions.count < b) {
349 LOG_ERROR_ONCE(logger, "Draw range is out of bounds");
350 continue;
351 }
352 }
353 else {
354 if (indices.count < a || indices.count < b) {
355 LOG_ERROR_ONCE(logger, "Draw range is out of bounds");
356 continue;
357 }
358 }
359
360 switch (subMesh.primitiveType) {
362 intersectPoints<IndexStride, Fetch>(hits, localPickMatrix, vertexFlags, positions, indices, a, b, scale);
363 break;
364
366 intersectLines<IndexStride, Fetch>(hits, localPickMatrix, vertexFlags, positions, indices, a, b, 2, scale);
367 break;
368
370 intersectLines<IndexStride, Fetch>(hits, localPickMatrix, vertexFlags, positions, indices, a, b, 1, scale);
371 break;
372
374 intersectTriangles<IndexStride, Fetch>(hits, localPickMatrix, vertexFlags, positions, indices, a, b, 3, scale);
375 break;
376
378 intersectTriangles<IndexStride, Fetch>(hits, localPickMatrix, vertexFlags, positions, indices, a, b, 1, scale);
379 break;
380
381 default:
382 break;
383 }
384 }
385 }
386
387
388 struct Fetch_R10G10B10_UINT { static glm::vec3 fetch(const PosStreamRef& pos, size_t ix) { return glm::unpackU3x10_1x2(*reinterpret_cast<const uint32_t*>(pos.ptr + pos.stride * ix)); } };
389 struct Fetch_R16G16B16_UINT { static glm::vec3 fetch(const PosStreamRef& pos, size_t ix) { return *reinterpret_cast<const glm::u16vec3*>(pos.ptr + pos.stride * ix); } };
390 struct Fetch_R16G16B16_FLOAT { static glm::vec3 fetch(const PosStreamRef& pos, size_t ix) { return glm::unpackHalf4x16(*reinterpret_cast<const uint64_t*>(pos.ptr + pos.stride * ix)); } };
391 struct Fetch_R32G32B32_FLOAT { static glm::vec3 fetch(const PosStreamRef& pos, size_t ix) { return *reinterpret_cast<const glm::vec3*>(pos.ptr + pos.stride * ix); } };
392
393
394}
395
396
397bool Cogs::Core::intersectMesh(std::vector<RayIntersectionHit>& hits,
398 std::vector<FrustumPlanes>& scratch,
399 const glm::mat4& pickMatrix,
400 const Mesh& mesh,
401 uint32_t startIndex,
402 uint32_t vertexCount,
403 uint32_t subMeshIndex)
404{
405
406 // Transform all coordinates into pick frustum, and do the frustum-
407 // bound half-plane tests and store results in a bitmask. Combining
408 // these bitmasks allows us to do frustum culling of the convex hull
409 // of any subset of the points.
410 //
411 // Note: This is a likely hotspot (in particular for large meshes), so if
412 // there are issues with performance, make sure that the following loop
413 // is appropriately optimized and parallelized.
414
415
416 // Get position stream
417 PosStreamRef positions;
418 for (size_t i = 0; i < VertexDataType::LastVertexType; ++i) {
420 if (mesh.hasStream(vertexType)) {
421 const DataStream& stream = mesh.streams[mesh.streamIndexes[vertexType]];
422 const VertexFormat* vertexFormat = Cogs::VertexFormats::getVertexFormat(stream.format);
423 for (const VertexElement& element : vertexFormat->elements) {
424 if (element.semantic == ElementSemantic::Position && element.semanticIndex == 0) {
425 positions.ptr = static_cast<const uint8_t*>(stream.buffer->data()) + stream.offset + element.offset;
426 positions.format = element.format;
427 positions.stride = stream.stride;
428 positions.count = stream.numElements;
429 goto found_position;
430 break;
431 }
432 }
433 }
434 }
435 LOG_ERROR_ONCE(logger, "Mesh has no position data");
436 return false;
437
438found_position:
439 assert(positions.ptr);
440
441 // Get index stream
442 IxStreamRef indices;
443 if (mesh.hasStream(VertexDataType::Indexes)) {
444 const DataStream& stream = mesh.streams[mesh.streamIndexes[VertexDataType::Indexes]];
445 indices.ptr = static_cast<const uint8_t*>(stream.buffer->data());
446 indices.stride = stream.stride;
447 indices.count = stream.numElements;
448 }
449
450 // Submesh stream
451 SubMesh noSubMesh;
452 SubMeshStreamRef submeshes;
453 if (mesh.hasStream(VertexDataType::SubMeshes)) {
454 const DataStream& stream = mesh.streams[mesh.streamIndexes[VertexDataType::SubMeshes]];
455 if (stream.numElements) {
456 submeshes.ptr = static_cast<const SubMesh*>(stream.buffer->data());
457 submeshes.count = stream.numElements;
458 goto found_submeshes;
459 }
460 }
461 noSubMesh.startIndex = startIndex;
462 noSubMesh.numIndexes = vertexCount;
463 noSubMesh.primitiveType = mesh.primitiveType;
464 submeshes.ptr = &noSubMesh;
465 submeshes.count = 1;
466
467found_submeshes:
468 assert(submeshes.ptr && submeshes.count);
469
470 if (subMeshIndex != ~0u) {
471 if (submeshes.count <= subMeshIndex) {
472 LOG_ERROR_ONCE(logger, "Illegal submesh index %u", subMeshIndex);
473 return false;
474 }
475 submeshes.ptr += subMeshIndex;
476 submeshes.count = 1;
477 }
478
479 constexpr float scale10u = 1.f / 0x3FFu;
480 constexpr float scale16u = 1.f / 0xFFFFu;
481 scratch.resize(positions.count);
482 switch (positions.format) {
483
484 case DataFormat::R10G10B10A2_UNORM: {
485 glm::mat4 M = pickMatrix * glm::mat4(scale10u, 0.f, 0.f, 0.f,
486 0.f, scale10u, 0.f, 0.f,
487 0.f, 0.f, scale10u, 0.f,
488 0.f, 0.f, 0.f, 1.f);
489 classify<Fetch_R10G10B10_UINT>(scratch.data(), M, positions);
490 switch (indices.stride) {
491 case 0: intersectSubMesh<0, Fetch_R10G10B10_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale10u); break;
492 case 2: intersectSubMesh<2, Fetch_R10G10B10_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale10u); break;
493 case 4: intersectSubMesh<4, Fetch_R10G10B10_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale10u); break;
494 default: assert(false); break;
495 }
496 break;
497 }
498
499 case DataFormat::R16G16B16_UNORM: {
500 glm::mat4 M = pickMatrix * glm::mat4(scale16u, 0.f, 0.f, 0.f,
501 0.f, scale16u, 0.f, 0.f,
502 0.f, 0.f, scale16u, 0.f,
503 0.f, 0.f, 0.f, 1.f);
504 classify<Fetch_R16G16B16_UINT>(scratch.data(), M, positions);
505 switch (indices.stride) {
506 case 0: intersectSubMesh<0, Fetch_R16G16B16_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale16u); break;
507 case 2: intersectSubMesh<2, Fetch_R16G16B16_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale16u); break;
508 case 4: intersectSubMesh<4, Fetch_R16G16B16_UINT>(hits, M, scratch.data(), submeshes, indices, positions, &mesh, scale16u); break;
509 default: assert(false); break;
510 }
511 break;
512 }
513
514 case DataFormat::R16G16B16_FLOAT:
515 classify<Fetch_R16G16B16_FLOAT>(scratch.data(), pickMatrix, positions);
516 switch (indices.stride) {
517 case 0: intersectSubMesh<0, Fetch_R16G16B16_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
518 case 2: intersectSubMesh<2, Fetch_R16G16B16_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
519 case 4: intersectSubMesh<4, Fetch_R16G16B16_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
520 default: assert(false); break;
521 }
522 break;
523
524 case DataFormat::R32G32B32_FLOAT:
525 classify<Fetch_R32G32B32_FLOAT>(scratch.data(), pickMatrix, positions);
526 switch (indices.stride) {
527 case 0: intersectSubMesh<0, Fetch_R32G32B32_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
528 case 2: intersectSubMesh<2, Fetch_R32G32B32_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
529 case 4: intersectSubMesh<4, Fetch_R32G32B32_FLOAT>(hits, pickMatrix, scratch.data(), submeshes, indices, positions, &mesh); break;
530 default: assert(false); break;
531 }
532 break;
533
534 default: {
535 const FormatInfo* info = getFormatInfo(positions.format);
536 LOG_ERROR_ONCE(logger, "Unsupported vertex format %s ", info ? info->vName : "null");
537 return false;
538 }
539 }
540
541 return true;
542}
543
544
545bool Cogs::Core::frustumClassifyVertex(FrustumPlanes* dstPtr, const glm::mat4& matrix, const glm::vec3* positions, const size_t count)
546{
547 classify<Fetch_R32G32B32_FLOAT>(dstPtr, matrix, PosStreamRef{ .ptr = (const uint8_t*)positions, .stride = sizeof(glm::vec3), .count = uint32_t(count) });
548 return true;
549}
Log implementation class.
Definition: LogManager.h:139
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
void * data()
Get a pointer to the buffer data.
Definition: Buffer.h:74
Contains a stream of data used by Mesh resources.
Definition: Mesh.h:80
uint32_t numElements
Number of elements of the type given by format contained in data.
Definition: Mesh.h:108
uint32_t offset
Byte offset from the start of the buffer.
Definition: Mesh.h:102
VertexFormatHandle format
A pointer to the format describing the contents of the byte buffer.
Definition: Mesh.h:99
uint32_t stride
Element stride.
Definition: Mesh.h:105
Cogs::Core::ResourceBufferHandle buffer
Data buffer.
Definition: Mesh.h:96
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
bool hasStream(VertexDataType::EVertexDataType type) const
Check if the Mesh has a DataStream for the given type.
Definition: Mesh.h:933
uint32_t getCount() const
Get the vertex count of the mesh.
Definition: Mesh.h:1012
Defines a sub-mesh of a Mesh resource.
Definition: Mesh.h:249
PrimitiveType::EPrimitiveType primitiveType
Primitive type to use when drawing the sub-mesh.
Definition: Mesh.h:257
uint32_t startIndex
Start index of the sub-mesh in the index array of the Mesh.
Definition: Mesh.h:251
uint32_t numIndexes
Number of indexes to draw for the sub-mesh.
Definition: Mesh.h:254
EVertexDataType
Contains data types.
Definition: Mesh.h:26
const char * vName
Name as a vertex format (using XYZW as channels).
Definition: DataFormat.h:261
@ LineStrip
Line strip.
Definition: Common.h:122
@ LineList
List of lines.
Definition: Common.h:120
@ TriangleStrip
Triangle strip.
Definition: Common.h:118
@ PointList
List of points.
Definition: Common.h:124
@ TriangleList
List of triangles.
Definition: Common.h:116
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38
DataFormat format
Format of the element.
Definition: VertexFormat.h:40
uint16_t offset
Offset in bytes from the vertex position in memory.
Definition: VertexFormat.h:39
uint16_t semanticIndex
Index for the semantic mapping.
Definition: VertexFormat.h:42
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).
Definition: VertexFormat.h:41
Vertex format structure used to describe a single vertex for the input assembler.
Definition: VertexFormat.h:60
std::vector< VertexElement > elements
Vector containing all vertex elements of this format.
Definition: VertexFormat.h:62