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