1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "../common/ray.h"
7#include "../common/scene_grid_mesh.h"
8#include "../bvh/bvh.h"
9
10namespace embree
11{
12 /* Stores M quads from an indexed face set */
13 struct SubGrid
14 {
15 /* Virtual interface to query information about the quad type */
16 struct Type : public PrimitiveType
17 {
18 const char* name() const;
19 size_t sizeActive(const char* This) const;
20 size_t sizeTotal(const char* This) const;
21 size_t getBytes(const char* This) const;
22 };
23 static Type type;
24
25 public:
26
27 /* primitive supports multiple time segments */
28 static const bool singleTimeSegment = false;
29
30 /* Returns maximum number of stored quads */
31 static __forceinline size_t max_size() { return 1; }
32
33 /* Returns required number of primitive blocks for N primitives */
34 static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
35
36 public:
37
38 /* Default constructor */
39 __forceinline SubGrid() { }
40
41 /* Construction from vertices and IDs */
42 __forceinline SubGrid(const unsigned int x,
43 const unsigned int y,
44 const unsigned int geomID,
45 const unsigned int primID)
46 : _x(x), _y(y), _geomID(geomID), _primID(primID)
47 {
48 }
49
50 __forceinline bool invalid3x3X() const { return (unsigned int)_x & (1<<15); }
51 __forceinline bool invalid3x3Y() const { return (unsigned int)_y & (1<<15); }
52
53 /* Gather the quads */
54 __forceinline void gather(Vec3vf4& p0,
55 Vec3vf4& p1,
56 Vec3vf4& p2,
57 Vec3vf4& p3,
58 const GridMesh* const mesh,
59 const GridMesh::Grid &g) const
60 {
61 /* first quad always valid */
62 const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
63 const size_t vtxID01 = vtxID00 + 1;
64 const vfloat4 vtx00 = vfloat4::loadu(mesh->vertexPtr(vtxID00));
65 const vfloat4 vtx01 = vfloat4::loadu(mesh->vertexPtr(vtxID01));
66 const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
67 const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
68 const vfloat4 vtx10 = vfloat4::loadu(mesh->vertexPtr(vtxID10));
69 const vfloat4 vtx11 = vfloat4::loadu(mesh->vertexPtr(vtxID11));
70
71 /* deltaX => vtx02, vtx12 */
72 const size_t deltaX = invalid3x3X() ? 0 : 1;
73 const size_t vtxID02 = vtxID01 + deltaX;
74 const vfloat4 vtx02 = vfloat4::loadu(mesh->vertexPtr(vtxID02));
75 const size_t vtxID12 = vtxID11 + deltaX;
76 const vfloat4 vtx12 = vfloat4::loadu(mesh->vertexPtr(vtxID12));
77
78 /* deltaY => vtx20, vtx21 */
79 const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
80 const size_t vtxID20 = vtxID10 + deltaY;
81 const size_t vtxID21 = vtxID11 + deltaY;
82 const vfloat4 vtx20 = vfloat4::loadu(mesh->vertexPtr(vtxID20));
83 const vfloat4 vtx21 = vfloat4::loadu(mesh->vertexPtr(vtxID21));
84
85 /* deltaX/deltaY => vtx22 */
86 const size_t vtxID22 = vtxID11 + deltaX + deltaY;
87 const vfloat4 vtx22 = vfloat4::loadu(mesh->vertexPtr(vtxID22));
88
89 transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
90 transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
91 transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
92 transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
93 }
94
95 template<typename T>
96 __forceinline vfloat4 getVertexMB(const GridMesh* const mesh, const size_t offset, const size_t itime, const float ftime) const
97 {
98 const T v0 = T::loadu(mesh->vertexPtr(offset,itime+0));
99 const T v1 = T::loadu(mesh->vertexPtr(offset,itime+1));
100 return lerp(v0,v1,ftime);
101 }
102
103 /* Gather the quads */
104 __forceinline void gatherMB(Vec3vf4& p0,
105 Vec3vf4& p1,
106 Vec3vf4& p2,
107 Vec3vf4& p3,
108 const GridMesh* const mesh,
109 const GridMesh::Grid &g,
110 const size_t itime,
111 const float ftime) const
112 {
113 /* first quad always valid */
114 const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
115 const size_t vtxID01 = vtxID00 + 1;
116 const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
117 const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
118 const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
119 const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
120 const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
121 const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
122
123 /* deltaX => vtx02, vtx12 */
124 const size_t deltaX = invalid3x3X() ? 0 : 1;
125 const size_t vtxID02 = vtxID01 + deltaX;
126 const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
127 const size_t vtxID12 = vtxID11 + deltaX;
128 const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
129
130 /* deltaY => vtx20, vtx21 */
131 const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
132 const size_t vtxID20 = vtxID10 + deltaY;
133 const size_t vtxID21 = vtxID11 + deltaY;
134 const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
135 const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
136
137 /* deltaX/deltaY => vtx22 */
138 const size_t vtxID22 = vtxID11 + deltaX + deltaY;
139 const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
140
141 transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
142 transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
143 transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
144 transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
145 }
146
147
148
149 /* Gather the quads */
150 __forceinline void gather(Vec3vf4& p0,
151 Vec3vf4& p1,
152 Vec3vf4& p2,
153 Vec3vf4& p3,
154 const Scene *const scene) const
155 {
156 const GridMesh* const mesh = scene->get<GridMesh>(geomID());
157 const GridMesh::Grid &g = mesh->grid(primID());
158 gather(p0,p1,p2,p3,mesh,g);
159 }
160
161 /* Gather the quads in the motion blur case */
162 __forceinline void gatherMB(Vec3vf4& p0,
163 Vec3vf4& p1,
164 Vec3vf4& p2,
165 Vec3vf4& p3,
166 const Scene *const scene,
167 const size_t itime,
168 const float ftime) const
169 {
170 const GridMesh* const mesh = scene->get<GridMesh>(geomID());
171 const GridMesh::Grid &g = mesh->grid(primID());
172 gatherMB(p0,p1,p2,p3,mesh,g,itime,ftime);
173 }
174
175 /* Gather the quads */
176 __forceinline void gather(Vec3fa vtx[16], const Scene *const scene) const
177 {
178 const GridMesh* mesh = scene->get<GridMesh>(geomID());
179 const GridMesh::Grid &g = mesh->grid(primID());
180
181 /* first quad always valid */
182 const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
183 const size_t vtxID01 = vtxID00 + 1;
184 const Vec3fa vtx00 = Vec3fa::loadu(mesh->vertexPtr(vtxID00));
185 const Vec3fa vtx01 = Vec3fa::loadu(mesh->vertexPtr(vtxID01));
186 const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
187 const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
188 const Vec3fa vtx10 = Vec3fa::loadu(mesh->vertexPtr(vtxID10));
189 const Vec3fa vtx11 = Vec3fa::loadu(mesh->vertexPtr(vtxID11));
190
191 /* deltaX => vtx02, vtx12 */
192 const size_t deltaX = invalid3x3X() ? 0 : 1;
193 const size_t vtxID02 = vtxID01 + deltaX;
194 const Vec3fa vtx02 = Vec3fa::loadu(mesh->vertexPtr(vtxID02));
195 const size_t vtxID12 = vtxID11 + deltaX;
196 const Vec3fa vtx12 = Vec3fa::loadu(mesh->vertexPtr(vtxID12));
197
198 /* deltaY => vtx20, vtx21 */
199 const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
200 const size_t vtxID20 = vtxID10 + deltaY;
201 const size_t vtxID21 = vtxID11 + deltaY;
202 const Vec3fa vtx20 = Vec3fa::loadu(mesh->vertexPtr(vtxID20));
203 const Vec3fa vtx21 = Vec3fa::loadu(mesh->vertexPtr(vtxID21));
204
205 /* deltaX/deltaY => vtx22 */
206 const size_t vtxID22 = vtxID11 + deltaX + deltaY;
207 const Vec3fa vtx22 = Vec3fa::loadu(mesh->vertexPtr(vtxID22));
208
209 vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
210 vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
211 vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
212 vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
213 }
214
215 /* Gather the quads */
216 __forceinline void gatherMB(vfloat4 vtx[16], const Scene *const scene, const size_t itime, const float ftime) const
217 {
218 const GridMesh* mesh = scene->get<GridMesh>(geomID());
219 const GridMesh::Grid &g = mesh->grid(primID());
220
221 /* first quad always valid */
222 const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
223 const size_t vtxID01 = vtxID00 + 1;
224 const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
225 const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
226 const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
227 const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
228 const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
229 const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
230
231 /* deltaX => vtx02, vtx12 */
232 const size_t deltaX = invalid3x3X() ? 0 : 1;
233 const size_t vtxID02 = vtxID01 + deltaX;
234 const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
235 const size_t vtxID12 = vtxID11 + deltaX;
236 const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
237
238 /* deltaY => vtx20, vtx21 */
239 const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
240 const size_t vtxID20 = vtxID10 + deltaY;
241 const size_t vtxID21 = vtxID11 + deltaY;
242 const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
243 const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
244
245 /* deltaX/deltaY => vtx22 */
246 const size_t vtxID22 = vtxID11 + deltaX + deltaY;
247 const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
248
249 vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
250 vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
251 vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
252 vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
253 }
254
255
256 /* Calculate the bounds of the subgrid */
257 __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
258 {
259 BBox3fa bounds = empty;
260 FATAL("not implemented yet");
261 return bounds;
262 }
263
264 /* Calculate the linear bounds of the primitive */
265 __forceinline LBBox3fa linearBounds(const Scene* const scene, const size_t itime)
266 {
267 return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
268 }
269
270 __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
271 {
272 LBBox3fa allBounds = empty;
273 FATAL("not implemented yet");
274 return allBounds;
275 }
276
277 __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
278 {
279 LBBox3fa allBounds = empty;
280 FATAL("not implemented yet");
281 return allBounds;
282 }
283
284
285 friend embree_ostream operator<<(embree_ostream cout, const SubGrid& sg) {
286 return cout << "SubGrid " << " ( x " << sg.x() << ", y = " << sg.y() << ", geomID = " << sg.geomID() << ", primID = " << sg.primID() << " )";
287 }
288
289 __forceinline unsigned int geomID() const { return _geomID; }
290 __forceinline unsigned int primID() const { return _primID; }
291 __forceinline unsigned int x() const { return (unsigned int)_x & 0x7fff; }
292 __forceinline unsigned int y() const { return (unsigned int)_y & 0x7fff; }
293
294 private:
295 unsigned short _x;
296 unsigned short _y;
297 unsigned int _geomID; // geometry ID of mesh
298 unsigned int _primID; // primitive ID of primitive inside mesh
299 };
300
301 struct SubGridID {
302 unsigned short x;
303 unsigned short y;
304 unsigned int primID;
305
306 __forceinline SubGridID() {}
307 __forceinline SubGridID(const unsigned int x, const unsigned int y, const unsigned int primID) :
308 x(x), y(y), primID(primID) {}
309 };
310
311 /* QuantizedBaseNode as large subgrid leaf */
312 template<int N>
313 struct SubGridQBVHN
314 {
315 /* Virtual interface to query information about the quad type */
316 struct Type : public PrimitiveType
317 {
318 const char* name() const;
319 size_t sizeActive(const char* This) const;
320 size_t sizeTotal(const char* This) const;
321 size_t getBytes(const char* This) const;
322 };
323 static Type type;
324
325 public:
326
327 __forceinline size_t size() const
328 {
329 for (size_t i=0;i<N;i++)
330 if (primID(i) == -1) return i;
331 return N;
332 }
333
334 __forceinline void clear() {
335 for (size_t i=0;i<N;i++)
336 subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
337 qnode.clear();
338 }
339
340 /* Default constructor */
341 __forceinline SubGridQBVHN() { }
342
343 /* Construction from vertices and IDs */
344 __forceinline SubGridQBVHN(const unsigned int x[N],
345 const unsigned int y[N],
346 const unsigned int primID[N],
347 const BBox3fa * const subGridBounds,
348 const unsigned int geomID,
349 const unsigned int items)
350 {
351 clear();
352 _geomID = geomID;
353
354 __aligned(64) typename BVHN<N>::AABBNode node;
355 node.clear();
356 for (size_t i=0;i<items;i++)
357 {
358 subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
359 node.setBounds(i,subGridBounds[i]);
360 }
361 qnode.init_dim(node);
362 }
363
364 __forceinline unsigned int geomID() const { return _geomID; }
365 __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
366 __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
367 __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
368
369 __forceinline SubGrid subgrid(const size_t i) const {
370 assert(i < N);
371 assert(primID(i) != -1);
372 return SubGrid(x(i),y(i),geomID(),primID(i));
373 }
374
375 public:
376 SubGridID subgridIDs[N];
377
378 typename BVHN<N>::QuantizedBaseNode qnode;
379
380 unsigned int _geomID; // geometry ID of mesh
381
382
383 friend embree_ostream operator<<(embree_ostream cout, const SubGridQBVHN& sg) {
384 cout << "SubGridQBVHN " << embree_endl;
385 for (size_t i=0;i<N;i++)
386 cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
387 cout << "geomID " << sg._geomID << embree_endl;
388 cout << "lowerX " << sg.qnode.dequantizeLowerX() << embree_endl;
389 cout << "upperX " << sg.qnode.dequantizeUpperX() << embree_endl;
390 cout << "lowerY " << sg.qnode.dequantizeLowerY() << embree_endl;
391 cout << "upperY " << sg.qnode.dequantizeUpperY() << embree_endl;
392 cout << "lowerZ " << sg.qnode.dequantizeLowerZ() << embree_endl;
393 cout << "upperZ " << sg.qnode.dequantizeUpperZ() << embree_endl;
394 return cout;
395 }
396
397 };
398
399 template<int N>
400 typename SubGridQBVHN<N>::Type SubGridQBVHN<N>::type;
401
402 typedef SubGridQBVHN<4> SubGridQBVH4;
403 typedef SubGridQBVHN<8> SubGridQBVH8;
404
405
406 /* QuantizedBaseNode as large subgrid leaf */
407 template<int N>
408 struct SubGridMBQBVHN
409 {
410 /* Virtual interface to query information about the quad type */
411 struct Type : public PrimitiveType
412 {
413 const char* name() const;
414 size_t sizeActive(const char* This) const;
415 size_t sizeTotal(const char* This) const;
416 size_t getBytes(const char* This) const;
417 };
418 static Type type;
419
420 public:
421
422 __forceinline size_t size() const
423 {
424 for (size_t i=0;i<N;i++)
425 if (primID(i) == -1) return i;
426 return N;
427 }
428
429 __forceinline void clear() {
430 for (size_t i=0;i<N;i++)
431 subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
432 qnode.clear();
433 }
434
435 /* Default constructor */
436 __forceinline SubGridMBQBVHN() { }
437
438 /* Construction from vertices and IDs */
439 __forceinline SubGridMBQBVHN(const unsigned int x[N],
440 const unsigned int y[N],
441 const unsigned int primID[N],
442 const BBox3fa * const subGridBounds0,
443 const BBox3fa * const subGridBounds1,
444 const unsigned int geomID,
445 const float toffset,
446 const float tscale,
447 const unsigned int items)
448 {
449 clear();
450 _geomID = geomID;
451 time_offset = toffset;
452 time_scale = tscale;
453
454 __aligned(64) typename BVHN<N>::AABBNode node0,node1;
455 node0.clear();
456 node1.clear();
457 for (size_t i=0;i<items;i++)
458 {
459 subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
460 node0.setBounds(i,subGridBounds0[i]);
461 node1.setBounds(i,subGridBounds1[i]);
462 }
463 qnode.node0.init_dim(node0);
464 qnode.node1.init_dim(node1);
465 }
466
467 __forceinline unsigned int geomID() const { return _geomID; }
468 __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
469 __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
470 __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
471
472 __forceinline SubGrid subgrid(const size_t i) const {
473 assert(i < N);
474 assert(primID(i) != -1);
475 return SubGrid(x(i),y(i),geomID(),primID(i));
476 }
477
478 __forceinline float adjustTime(const float t) const { return time_scale * (t-time_offset); }
479
480 template<int K>
481 __forceinline vfloat<K> adjustTime(const vfloat<K> &t) const { return time_scale * (t-time_offset); }
482
483 public:
484 SubGridID subgridIDs[N];
485
486 typename BVHN<N>::QuantizedBaseNodeMB qnode;
487
488 float time_offset;
489 float time_scale;
490 unsigned int _geomID; // geometry ID of mesh
491
492
493 friend embree_ostream operator<<(embree_ostream cout, const SubGridMBQBVHN& sg) {
494 cout << "SubGridMBQBVHN " << embree_endl;
495 for (size_t i=0;i<N;i++)
496 cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
497 cout << "geomID " << sg._geomID << embree_endl;
498 cout << "time_offset " << sg.time_offset << embree_endl;
499 cout << "time_scale " << sg.time_scale << embree_endl;
500 cout << "lowerX " << sg.qnode.node0.dequantizeLowerX() << embree_endl;
501 cout << "upperX " << sg.qnode.node0.dequantizeUpperX() << embree_endl;
502 cout << "lowerY " << sg.qnode.node0.dequantizeLowerY() << embree_endl;
503 cout << "upperY " << sg.qnode.node0.dequantizeUpperY() << embree_endl;
504 cout << "lowerZ " << sg.qnode.node0.dequantizeLowerZ() << embree_endl;
505 cout << "upperZ " << sg.qnode.node0.dequantizeUpperZ() << embree_endl;
506 cout << "lowerX " << sg.qnode.node1.dequantizeLowerX() << embree_endl;
507 cout << "upperX " << sg.qnode.node1.dequantizeUpperX() << embree_endl;
508 cout << "lowerY " << sg.qnode.node1.dequantizeLowerY() << embree_endl;
509 cout << "upperY " << sg.qnode.node1.dequantizeUpperY() << embree_endl;
510 cout << "lowerZ " << sg.qnode.node1.dequantizeLowerZ() << embree_endl;
511 cout << "upperZ " << sg.qnode.node1.dequantizeUpperZ() << embree_endl;
512 return cout;
513 }
514
515 };
516
517}
518