Path: blob/master/thirdparty/embree/kernels/common/scene_instance_array.h
9905 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "geometry.h"6#include "accel.h"78namespace embree9{10struct MotionDerivativeCoefficients;1112/*! Instanced acceleration structure */13struct InstanceArray : public Geometry14{15static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE_ARRAY;1617public:18InstanceArray (Device* device, unsigned int numTimeSteps = 1);19~InstanceArray();2021private:22InstanceArray (const InstanceArray& other) DELETED; // do not implement23InstanceArray& operator= (const InstanceArray& other) DELETED; // do not implement2425private:26LBBox3fa nonlinearBounds(size_t i,27const BBox1f& time_range_in,28const BBox1f& geom_time_range,29float geom_time_segments) const;3031BBox3fa boundSegment(size_t i, size_t itime,32BBox3fa const& obbox0, BBox3fa const& obbox1,33BBox3fa const& bbox0, BBox3fa const& bbox1,34float t_min, float t_max) const;3536/* calculates the (correct) interpolated bounds */37__forceinline BBox3fa bounds(size_t i, size_t itime0, size_t itime1, float f) const38{39if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))40return xfmBounds(slerp(l2w(i, itime0), l2w(i, itime1), f),41lerp(getObjectBounds(i, itime0), getObjectBounds(i, itime1), f));42return xfmBounds(lerp(l2w(i, itime0), l2w(i, itime1), f),43lerp(getObjectBounds(i, itime0), getObjectBounds(i, itime1), f));44}4546public:4748virtual void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num) override;49virtual void* getBufferData(RTCBufferType type, unsigned int slot, BufferDataPointerType pointerType) override;50virtual void updateBuffer(RTCBufferType type, unsigned int slot) override;5152virtual void setNumTimeSteps (unsigned int numTimeSteps) override;53virtual void setInstancedScene(const Ref<Scene>& scene) override;54virtual void setInstancedScenes(const RTCScene* scenes, size_t numScenes) override;55virtual AffineSpace3fa getTransform(size_t, float time) override;56virtual void setMask (unsigned mask) override;57virtual void build() {}58virtual void addElementsToCount (GeometryCounts & counts) const override;59virtual void commit() override;60size_t getGeometryDataDeviceByteSize() const override;61void convertToDeviceRepresentation(size_t offset, char* data_host, char* data_device) const override;6263public:6465/*! calculates the bounds of instance */66__forceinline BBox3fa bounds(size_t i) const {67if (!valid(i))68return BBox3fa();6970if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))71return xfmBounds(quaternionDecompositionToAffineSpace(l2w(i, 0)),getObject(i)->bounds.bounds());72return xfmBounds(l2w(i, 0),getObject(i)->bounds.bounds());73}7475/*! gets the bounds of the instanced scene */76__forceinline BBox3fa getObjectBounds(size_t i, size_t itime) const {77if (!valid(i))78return BBox3fa();7980return getObject(i)->getBounds(timeStep(itime));81}8283/*! calculates the bounds of instance */84__forceinline BBox3fa bounds(size_t i, size_t itime) const {85if (!valid(i))86return BBox3fa();8788if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))89return xfmBounds(quaternionDecompositionToAffineSpace(l2w(i, itime)),getObjectBounds(i, itime));90return xfmBounds(l2w(i, itime),getObjectBounds(i, itime));91}9293/*! calculates the linear bounds of the i'th primitive for the specified time range */94__forceinline LBBox3fa linearBounds(size_t i, const BBox1f& dt) const {95if (!valid(i))96return LBBox3fa();9798LBBox3fa lbbox = nonlinearBounds(i, dt, time_range, fnumTimeSegments);99return lbbox;100}101102/*! calculates the build bounds of the i'th item, if it's valid */103__forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const104{105if (!valid(i))106return false;107108const BBox3fa b = bounds(i);109if (bbox) *bbox = b;110return isvalid(b);111}112113/*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */114__forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const115{116if (!valid(i))117return false;118119const LBBox3fa bounds = linearBounds(i,itime);120bbox = bounds.bounds ();121return isvalid(bounds);122}123124/* gets version info of topology */125unsigned int getTopologyVersion() const {126return numPrimitives;127}128129/* returns true if topology changed */130bool topologyChanged(unsigned int otherVersion) const {131return numPrimitives != otherVersion;132}133134/*! check if the i'th primitive is valid between the specified time range */135__forceinline bool valid(size_t i) const136{137if (object) return true;138return (object_ids[i] != (unsigned int)(-1));139}140141/*! check if the i'th primitive is valid between the specified time range */142__forceinline bool valid(size_t i, const range<size_t>& itime_range) const143{144for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)145if (!isvalid(bounds(i,itime))) return false;146147return true;148}149150__forceinline AffineSpace3fa getLocal2World(size_t i) const151{152if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))153return quaternionDecompositionToAffineSpace(l2w(i,0));154return l2w(i, 0);155}156157__forceinline AffineSpace3fa getLocal2World(size_t i, float t) const158{159if (numTimeSegments() > 0) {160float ftime; const unsigned int itime = timeSegment(t, ftime);161if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))162return slerp(l2w(i, itime+0),l2w(i, itime+1),ftime);163return lerp(l2w(i, itime+0),l2w(i, itime+1),ftime);164}165return getLocal2World(i);166}167168__forceinline AffineSpace3fa getWorld2Local(size_t i) const {169return rcp(getLocal2World(i));170}171172__forceinline AffineSpace3fa getWorld2Local(size_t i, float t) const {173return rcp(getLocal2World(i, t));174}175176template<int K>177__forceinline AffineSpace3vf<K> getWorld2Local(size_t i, const vbool<K>& valid, const vfloat<K>& t) const178{179if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))180return getWorld2LocalSlerp<K>(i, valid, t);181return getWorld2LocalLerp<K>(i, valid, t);182}183184__forceinline float projectedPrimitiveArea(const size_t i) const {185return area(bounds(i));186}187188inline Accel* getObject(size_t i) const {189if (object) {190return object;191}192193assert(objects);194assert(i < numPrimitives);195if (object_ids[i] == (unsigned int)(-1))196return nullptr;197198assert(object_ids[i] < numObjects);199return objects[object_ids[i]];200}201202private:203204template<int K>205__forceinline AffineSpace3vf<K> getWorld2LocalSlerp(size_t i, const vbool<K>& valid, const vfloat<K>& t) const206{207vfloat<K> ftime;208const vint<K> itime_k = timeSegment<K>(t, ftime);209assert(any(valid));210const size_t index = bsf(movemask(valid));211const int itime = itime_k[index];212if (likely(all(valid, itime_k == vint<K>(itime)))) {213return rcp(slerp(AffineSpace3vff<K>(l2w(i, itime+0)),214AffineSpace3vff<K>(l2w(i, itime+1)),215ftime));216}217else {218AffineSpace3vff<K> space0,space1;219vbool<K> valid1 = valid;220while (any(valid1)) {221vbool<K> valid2;222const int itime = next_unique(valid1, itime_k, valid2);223space0 = select(valid2, AffineSpace3vff<K>(l2w(i, itime+0)), space0);224space1 = select(valid2, AffineSpace3vff<K>(l2w(i, itime+1)), space1);225}226return rcp(slerp(space0, space1, ftime));227}228}229230template<int K>231__forceinline AffineSpace3vf<K> getWorld2LocalLerp(size_t i, const vbool<K>& valid, const vfloat<K>& t) const232{233vfloat<K> ftime;234const vint<K> itime_k = timeSegment<K>(t, ftime);235assert(any(valid));236const size_t index = bsf(movemask(valid));237const int itime = itime_k[index];238if (likely(all(valid, itime_k == vint<K>(itime)))) {239return rcp(lerp(AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+0)),240AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+1)),241ftime));242} else {243AffineSpace3vf<K> space0,space1;244vbool<K> valid1 = valid;245while (any(valid1)) {246vbool<K> valid2;247const int itime = next_unique(valid1, itime_k, valid2);248space0 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+0)), space0);249space1 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+1)), space1);250}251return rcp(lerp(space0, space1, ftime));252}253}254255private:256257__forceinline AffineSpace3ff l2w(size_t i, size_t itime) const {258if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR) {259return *(AffineSpace3ff*)(l2w_buf[itime].getPtr(i));260}261else if(l2w_buf[itime].getFormat() == RTC_FORMAT_QUATERNION_DECOMPOSITION) {262AffineSpace3ff transform;263QuaternionDecomposition* qd = (QuaternionDecomposition*)l2w_buf[itime].getPtr(i);264transform.l.vx.x = qd->scale_x;265transform.l.vy.y = qd->scale_y;266transform.l.vz.z = qd->scale_z;267transform.l.vy.x = qd->skew_xy;268transform.l.vz.x = qd->skew_xz;269transform.l.vz.y = qd->skew_yz;270transform.l.vx.y = qd->translation_x;271transform.l.vx.z = qd->translation_y;272transform.l.vy.z = qd->translation_z;273transform.p.x = qd->shift_x;274transform.p.y = qd->shift_y;275transform.p.z = qd->shift_z;276// normalize quaternion277Quaternion3f q(qd->quaternion_r, qd->quaternion_i, qd->quaternion_j, qd->quaternion_k);278q = normalize(q);279transform.l.vx.w = q.i;280transform.l.vy.w = q.j;281transform.l.vz.w = q.k;282transform.p.w = q.r;283return transform;284}285else if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR) {286AffineSpace3f* l2w = reinterpret_cast<AffineSpace3f*>(l2w_buf[itime].getPtr(i));287return AffineSpace3ff(*l2w);288}289else if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT3X4_ROW_MAJOR) {290float* data = reinterpret_cast<float*>(l2w_buf[itime].getPtr(i));291AffineSpace3f l2w;292l2w.l.vx.x = data[0]; l2w.l.vy.x = data[1]; l2w.l.vz.x = data[2]; l2w.p.x = data[3];293l2w.l.vx.y = data[4]; l2w.l.vy.y = data[5]; l2w.l.vz.y = data[6]; l2w.p.y = data[7];294l2w.l.vx.z = data[8]; l2w.l.vy.z = data[9]; l2w.l.vz.z = data[10]; l2w.p.z = data[11];295return l2w;296}297assert(false);298return AffineSpace3ff();299}300301inline AffineSpace3ff l2w(size_t i) const {302return l2w(i, 0);303}304305private:306Accel* object; //!< fast path if only one scene is instanced307Accel** objects;308uint32_t numObjects;309Device::vector<RawBufferView> l2w_buf = device; //!< transformation from local space to world space for each timestep (either normal matrix or quaternion decomposition)310BufferView<uint32_t> object_ids; //!< array of scene ids per instance array primitive311};312313namespace isa314{315struct InstanceArrayISA : public InstanceArray316{317InstanceArrayISA (Device* device)318: InstanceArray(device) {}319320LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const {321return linearBounds(primID,time_range);322}323324PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const325{326PrimInfo pinfo(empty);327for (size_t j = r.begin(); j < r.end(); j++) {328BBox3fa bounds = empty;329if (!buildBounds(j, &bounds) || !valid(j))330continue;331const PrimRef prim(bounds, geomID, unsigned(j));332pinfo.add_center2(prim);333prims[k++] = prim;334}335return pinfo;336}337338PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const339{340PrimInfo pinfo(empty);341for (size_t j = r.begin(); j < r.end(); j++) {342BBox3fa bounds = empty;343if (!buildBounds(j, itime, bounds))344continue;345const PrimRef prim(bounds, geomID, unsigned(j));346pinfo.add_center2(prim);347prims[k++] = prim;348}349return pinfo;350}351352PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const353{354PrimInfo pinfo(empty);355const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range);356if (t0t1.empty()) return pinfo;357358for (size_t j = r.begin(); j < r.end(); j++) {359LBBox3fa lbounds = linearBounds(j, t0t1);360if (!isvalid(lbounds.bounds()))361continue;362const PrimRef prim(lbounds.bounds(), geomID, unsigned(j));363pinfo.add_center2(prim);364prims[k++] = prim;365}366return pinfo;367}368369PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const370{371PrimInfoMB pinfo(empty);372for (size_t j = r.begin(); j < r.end(); j++) {373if (!valid(j, timeSegmentRange(t0t1)))374continue;375const PrimRefMB prim(linearBounds(j, t0t1), this->numTimeSegments(), this->time_range, this->numTimeSegments(), geomID, unsigned(j));376pinfo.add_primref(prim);377prims[k++] = prim;378}379return pinfo;380}381};382}383384DECLARE_ISA_FUNCTION(InstanceArray*, createInstanceArray, Device*);385}386387388