1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "geometry.h"
7#include "accel.h"
8
9namespace embree
10{
11 struct MotionDerivativeCoefficients;
12
13 /*! Instanced acceleration structure */
14 struct Instance : public Geometry
15 {
16 ALIGNED_STRUCT_(16);
17 static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE;
18
19 public:
20 Instance (Device* device, Accel* object = nullptr, unsigned int numTimeSteps = 1);
21 ~Instance();
22
23 private:
24 Instance (const Instance& other) DELETED; // do not implement
25 Instance& operator= (const Instance& other) DELETED; // do not implement
26
27 private:
28 LBBox3fa nonlinearBounds(const BBox1f& time_range_in,
29 const BBox1f& geom_time_range,
30 float geom_time_segments) const;
31
32 BBox3fa boundSegment(size_t itime,
33 BBox3fa const& obbox0, BBox3fa const& obbox1,
34 BBox3fa const& bbox0, BBox3fa const& bbox1,
35 float t_min, float t_max) const;
36
37 /* calculates the (correct) interpolated bounds */
38 __forceinline BBox3fa bounds(size_t itime0, size_t itime1, float f) const
39 {
40 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
41 return xfmBounds(slerp(local2world[itime0], local2world[itime1], f),
42 lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
43 return xfmBounds(lerp(local2world[itime0], local2world[itime1], f),
44 lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
45 }
46
47 public:
48 virtual void setNumTimeSteps (unsigned int numTimeSteps) override;
49 virtual void setInstancedScene(const Ref<Scene>& scene) override;
50 virtual void setTransform(const AffineSpace3fa& local2world, unsigned int timeStep) override;
51 virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) override;
52 virtual AffineSpace3fa getTransform(float time) override;
53 virtual void setMask (unsigned mask) override;
54 virtual void build() {}
55 virtual void addElementsToCount (GeometryCounts & counts) const override;
56 virtual void commit() override;
57
58 public:
59
60 /*! calculates the bounds of instance */
61 __forceinline BBox3fa bounds(size_t i) const {
62 assert(i == 0);
63 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
64 return xfmBounds(quaternionDecompositionToAffineSpace(local2world[0]),object->bounds.bounds());
65 return xfmBounds(local2world[0],object->bounds.bounds());
66 }
67
68 /*! gets the bounds of the instanced scene */
69 __forceinline BBox3fa getObjectBounds(size_t itime) const {
70 return object->getBounds(timeStep(itime));
71 }
72
73 /*! calculates the bounds of instance */
74 __forceinline BBox3fa bounds(size_t i, size_t itime) const {
75 assert(i == 0);
76 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
77 return xfmBounds(quaternionDecompositionToAffineSpace(local2world[itime]),getObjectBounds(itime));
78 return xfmBounds(local2world[itime],getObjectBounds(itime));
79 }
80
81 /*! calculates the linear bounds of the i'th primitive for the specified time range */
82 __forceinline LBBox3fa linearBounds(size_t i, const BBox1f& dt) const {
83 assert(i == 0);
84 LBBox3fa lbbox = nonlinearBounds(dt, time_range, fnumTimeSegments);
85 return lbbox;
86 }
87
88 /*! calculates the build bounds of the i'th item, if it's valid */
89 __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
90 {
91 assert(i==0);
92 const BBox3fa b = bounds(i);
93 if (bbox) *bbox = b;
94 return isvalid(b);
95 }
96
97 /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
98 __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
99 {
100 assert(i==0);
101 const LBBox3fa bounds = linearBounds(i,itime);
102 bbox = bounds.bounds ();
103 return isvalid(bounds);
104 }
105
106 /* gets version info of topology */
107 unsigned int getTopologyVersion() const {
108 return numPrimitives;
109 }
110
111 /* returns true if topology changed */
112 bool topologyChanged(unsigned int otherVersion) const {
113 return numPrimitives != otherVersion;
114 }
115
116 /*! check if the i'th primitive is valid between the specified time range */
117 __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
118 {
119 assert(i == 0);
120 for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
121 if (!isvalid(bounds(i,itime))) return false;
122
123 return true;
124 }
125
126 __forceinline AffineSpace3fa getLocal2World() const
127 {
128 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
129 return quaternionDecompositionToAffineSpace(local2world[0]);
130 return local2world[0];
131 }
132
133 __forceinline AffineSpace3fa getLocal2World(float t) const
134 {
135 float ftime; const unsigned int itime = timeSegment(t, ftime);
136 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
137 return slerp(local2world[itime+0],local2world[itime+1],ftime);
138 return lerp(local2world[itime+0],local2world[itime+1],ftime);
139 }
140
141 __forceinline AffineSpace3fa getWorld2Local() const {
142 return world2local0;
143 }
144
145 __forceinline AffineSpace3fa getWorld2Local(float t) const {
146 return rcp(getLocal2World(t));
147 }
148
149 template<int K>
150 __forceinline AffineSpace3vf<K> getWorld2Local(const vbool<K>& valid, const vfloat<K>& t) const
151 {
152 if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
153 return getWorld2LocalSlerp<K>(valid, t);
154 return getWorld2LocalLerp<K>(valid, t);
155 }
156
157 private:
158
159 template<int K>
160 __forceinline AffineSpace3vf<K> getWorld2LocalSlerp(const vbool<K>& valid, const vfloat<K>& t) const
161 {
162 vfloat<K> ftime;
163 const vint<K> itime_k = timeSegment<K>(t, ftime);
164 assert(any(valid));
165 const size_t index = bsf(movemask(valid));
166 const int itime = itime_k[index];
167 if (likely(all(valid, itime_k == vint<K>(itime)))) {
168 return rcp(slerp(AffineSpace3vff<K>(local2world[itime+0]),
169 AffineSpace3vff<K>(local2world[itime+1]),
170 ftime));
171 }
172 else {
173 AffineSpace3vff<K> space0,space1;
174 vbool<K> valid1 = valid;
175 while (any(valid1)) {
176 vbool<K> valid2;
177 const int itime = next_unique(valid1, itime_k, valid2);
178 space0 = select(valid2, AffineSpace3vff<K>(local2world[itime+0]), space0);
179 space1 = select(valid2, AffineSpace3vff<K>(local2world[itime+1]), space1);
180 }
181 return rcp(slerp(space0, space1, ftime));
182 }
183 }
184
185 template<int K>
186 __forceinline AffineSpace3vf<K> getWorld2LocalLerp(const vbool<K>& valid, const vfloat<K>& t) const
187 {
188 vfloat<K> ftime;
189 const vint<K> itime_k = timeSegment<K>(t, ftime);
190 assert(any(valid));
191 const size_t index = bsf(movemask(valid));
192 const int itime = itime_k[index];
193 if (likely(all(valid, itime_k == vint<K>(itime)))) {
194 return rcp(lerp(AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]),
195 AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]),
196 ftime));
197 } else {
198 AffineSpace3vf<K> space0,space1;
199 vbool<K> valid1 = valid;
200 while (any(valid1)) {
201 vbool<K> valid2;
202 const int itime = next_unique(valid1, itime_k, valid2);
203 space0 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]), space0);
204 space1 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]), space1);
205 }
206 return rcp(lerp(space0, space1, ftime));
207 }
208 }
209
210 public:
211 Accel* object; //!< pointer to instanced acceleration structure
212 AffineSpace3ff* local2world; //!< transformation from local space to world space for each timestep (either normal matrix or quaternion decomposition)
213 AffineSpace3fa world2local0; //!< transformation from world space to local space for timestep 0
214 };
215
216 namespace isa
217 {
218 struct InstanceISA : public Instance
219 {
220 InstanceISA (Device* device)
221 : Instance(device) {}
222
223 PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
224 {
225 assert(r.begin() == 0);
226 assert(r.end() == 1);
227
228 PrimInfo pinfo(empty);
229 BBox3fa b = empty;
230 if (!buildBounds(0,&b)) return pinfo;
231 // const BBox3fa b = bounds(0);
232 // if (!isvalid(b)) return pinfo;
233
234 const PrimRef prim(b,geomID,unsigned(0));
235 pinfo.add_center2(prim);
236 prims[k++] = prim;
237 return pinfo;
238 }
239
240 PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
241 {
242 assert(r.begin() == 0);
243 assert(r.end() == 1);
244
245 PrimInfo pinfo(empty);
246 BBox3fa b = empty;
247 if (!buildBounds(0,&b)) return pinfo;
248 // if (!valid(0,range<size_t>(itime))) return pinfo;
249 // const PrimRef prim(linearBounds(0,itime).bounds(),geomID,unsigned(0));
250 const PrimRef prim(b,geomID,unsigned(0));
251 pinfo.add_center2(prim);
252 prims[k++] = prim;
253 return pinfo;
254 }
255
256 PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
257 {
258 assert(r.begin() == 0);
259 assert(r.end() == 1);
260
261 PrimInfoMB pinfo(empty);
262 if (!valid(0, timeSegmentRange(t0t1))) return pinfo;
263 const PrimRefMB prim(linearBounds(0,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(0));
264 pinfo.add_primref(prim);
265 prims[k++] = prim;
266 return pinfo;
267 }
268 };
269 }
270
271 DECLARE_ISA_FUNCTION(Instance*, createInstance, Device*);
272}
273