45 #ifndef OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
46 #define OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
48 #include <openvdb/Types.h>
49 #include <openvdb/math/BBox.h>
50 #include <openvdb/math/Ray.h>
51 #include <openvdb/math/Math.h>
52 #include <openvdb/tools/RayIntersector.h>
53 #include <openvdb/tools/Interpolation.h>
54 #include <boost/scoped_ptr.hpp>
55 #include <boost/scoped_array.hpp>
58 #ifdef OPENVDB_TOOLS_RAYTRACER_USE_EXR
59 #include <OpenEXR/ImfPixelType.h>
60 #include <OpenEXR/ImfChannelList.h>
61 #include <OpenEXR/ImfOutputFile.h>
62 #include <OpenEXR/ImfHeader.h>
63 #include <OpenEXR/ImfFrameBuffer.h>
76 template<
typename Gr
idT>
80 size_t pixelSamples = 1,
81 unsigned int seed = 0,
82 bool threaded =
true);
85 template<
typename Gr
idT,
typename IntersectorT>
90 size_t pixelSamples = 1,
91 unsigned int seed = 0,
92 bool threaded =
true);
99 template<
typename Gr
idT,
typename IntersectorT = tools::LevelSetRayIntersector<Gr
idT> >
105 typedef typename IntersectorT::RayType
RayType;
111 size_t pixelSamples = 1,
112 unsigned int seed = 0);
119 size_t pixelSamples = 1,
120 unsigned int seed = 0);
129 void setGrid(
const GridT& grid);
133 void setIntersector(
const IntersectorT& inter);
151 void setPixelSamples(
size_t pixelSamples,
unsigned int seed = 0);
154 void render(
bool threaded =
true)
const;
158 void operator()(
const tbb::blocked_range<size_t>& range)
const;
161 const bool mIsMaster;
164 boost::scoped_ptr<const BaseShader> mShader;
176 template <
typename IntersectorT,
typename SamplerT = tools::BoxSampler>
182 typedef typename IntersectorT::RayType
RayType;
186 BOOST_STATIC_ASSERT(boost::is_floating_point<ValueType>::value);
195 void render(
bool threaded=
true)
const;
202 void setIntersector(
const IntersectorT& inter);
234 void print(std::ostream& os = std::cout,
int verboseLevel = 1);
238 void operator()(
const tbb::blocked_range<size_t>& range)
const;
242 AccessorType mAccessor;
244 boost::scoped_ptr<IntersectorT> mPrimary, mShadow;
245 Real mPrimaryStep, mShadowStep, mCutOff, mLightGain;
246 Vec3R mLightDir, mLightColor, mAbsorption, mScattering;
262 RGBA() : r(0), g(0), b(0), a(1) {}
263 explicit RGBA(
ValueT intensity) : r(intensity), g(intensity), b(intensity), a(1) {}
273 const float s = rhs.
a*(1.0f-a);
284 Film(
size_t width,
size_t height)
285 : mWidth(width), mHeight(height), mSize(width*height), mPixels(new
RGBA[mSize])
289 : mWidth(width), mHeight(height), mSize(width*height), mPixels(new
RGBA[mSize])
298 return mPixels[w + h*mWidth];
305 return mPixels[w + h*mWidth];
308 void fill(
const RGBA& rgb=
RGBA(0)) {
for (
size_t i=0; i<mSize; ++i) mPixels[i] = rgb; }
311 RGBA *p = mPixels.get();
312 for (
size_t j = 0; j < mHeight; ++j) {
313 for (
size_t i = 0; i < mWidth; ++i, ++p) {
314 *p = ((i & size) ^ (j & size)) ? c1 : c2;
321 std::string name(fileName +
".ppm");
322 boost::scoped_array<unsigned char> buffer(
new unsigned char[3*mSize]);
323 unsigned char *tmp = buffer.get(), *q = tmp;
324 RGBA* p = mPixels.get();
327 *q++ =
static_cast<unsigned char>(255.0f*(*p ).r);
328 *q++ =
static_cast<unsigned char>(255.0f*(*p ).g);
329 *q++ =
static_cast<unsigned char>(255.0f*(*p++).b);
332 std::ofstream os(name.c_str(), std::ios_base::binary);
334 std::cerr <<
"Error opening PPM file \"" << name <<
"\"" << std::endl;
338 os <<
"P6\n" << mWidth <<
" " << mHeight <<
"\n255\n";
339 os.write((
const char *)&(*tmp), 3*mSize*
sizeof(
unsigned char));
342 #ifdef OPENVDB_TOOLS_RAYTRACER_USE_EXR
343 void saveEXR(
const std::string& fileName,
size_t compression = 2,
size_t threads = 8)
345 std::string name(fileName +
".exr");
347 if (threads>0) Imf::setGlobalThreadCount(threads);
348 Imf::Header header(mWidth, mHeight);
349 if (compression==0) header.compression() = Imf::NO_COMPRESSION;
350 if (compression==1) header.compression() = Imf::RLE_COMPRESSION;
351 if (compression>=2) header.compression() = Imf::ZIP_COMPRESSION;
352 header.channels().insert(
"R", Imf::Channel(Imf::FLOAT));
353 header.channels().insert(
"G", Imf::Channel(Imf::FLOAT));
354 header.channels().insert(
"B", Imf::Channel(Imf::FLOAT));
355 header.channels().insert(
"A", Imf::Channel(Imf::FLOAT));
357 Imf::FrameBuffer framebuffer;
358 framebuffer.insert(
"R", Imf::Slice( Imf::FLOAT, (
char *) &(mPixels[0].r),
359 sizeof (RGBA),
sizeof (RGBA) * mWidth));
360 framebuffer.insert(
"G", Imf::Slice( Imf::FLOAT, (
char *) &(mPixels[0].g),
361 sizeof (RGBA),
sizeof (RGBA) * mWidth));
362 framebuffer.insert(
"B", Imf::Slice( Imf::FLOAT, (
char *) &(mPixels[0].b),
363 sizeof (RGBA),
sizeof (RGBA) * mWidth));
364 framebuffer.insert(
"A", Imf::Slice( Imf::FLOAT, (
char *) &(mPixels[0].a),
365 sizeof (RGBA),
sizeof (RGBA) * mWidth));
367 Imf::OutputFile file(name.c_str(), header);
368 file.setFrameBuffer(framebuffer);
369 file.writePixels(mHeight);
373 size_t width()
const {
return mWidth; }
374 size_t height()
const {
return mHeight; }
379 size_t mWidth, mHeight, mSize;
380 boost::scoped_array<RGBA> mPixels;
391 double frameWidth,
double nearPlane,
double farPlane)
393 , mScaleWidth(frameWidth)
394 , mScaleHeight(frameWidth*film.height()/double(film.width()))
396 assert(nearPlane > 0 && farPlane > nearPlane);
397 mScreenToWorld.accumPostRotation(
math::X_AXIS, rotation[0] * M_PI / 180.0);
398 mScreenToWorld.accumPostRotation(
math::Y_AXIS, rotation[1] * M_PI / 180.0);
399 mScreenToWorld.accumPostRotation(
math::Z_AXIS, rotation[2] * M_PI / 180.0);
400 mScreenToWorld.accumPostTranslation(translation);
401 this->initRay(nearPlane, farPlane);
408 size_t width()
const {
return mFilm->width(); }
409 size_t height()
const {
return mFilm->height(); }
417 const Vec3R orig = mScreenToWorld.applyMap(
Vec3R(0.0));
418 const Vec3R dir = orig - xyz;
420 Mat4d xform = math::aim<Mat4d>(dir, up);
423 this->initRay(mRay.t0(), mRay.t1());
429 return Vec3R( (2 * i / mFilm->width() - 1) * mScaleWidth,
430 (1 - 2 * j / mFilm->height()) * mScaleHeight, z );
437 size_t i,
size_t j,
double iOffset = 0.5,
double jOffset = 0.5)
const = 0;
442 mRay.setTimes(t0, t1);
443 mRay.setEye(mScreenToWorld.applyMap(
Vec3R(0.0)));
444 mRay.setDir(mScreenToWorld.applyJacobian(
Vec3R(0.0, 0.0, -1.0)));
475 double focalLength = 50.0,
476 double aperture = 41.2136,
477 double nearPlane = 1e-3,
479 :
BaseCamera(film,
rotation, translation, 0.5*aperture/focalLength, nearPlane, farPlane)
489 size_t i,
size_t j,
double iOffset = 0.5,
double jOffset = 0.5)
const
492 Vec3R dir = BaseCamera::rasterToScreen(i + iOffset, j + jOffset, -1.0);
493 dir = BaseCamera::mScreenToWorld.applyJacobian(dir);
504 return 360.0 / M_PI * atan(aperture/(2.0*length));
510 return aperture/(2.0*(tan(fov * M_PI / 360.0)));
533 double frameWidth = 1.0,
534 double nearPlane = 1e-3,
542 size_t i,
size_t j,
double iOffset = 0.5,
double jOffset = 0.5)
const
545 Vec3R eye = BaseCamera::rasterToScreen(i + iOffset, j + jOffset, 0.0);
546 ray.
setEye(BaseCamera::mScreenToWorld.applyMap(eye));
596 return mRGBA*
Film::RGBA(normal[0]+1.0f, normal[1]+1.0f, normal[2]+1.0f);
611 : mMin(bbox.
min()), mInvDim(1.0/bbox.extents()), mRGBA(c) {}
615 const Vec3R rgb = (xyz - mMin)*mInvDim;
616 return mRGBA*
Film::RGBA(rgb[0], rgb[1], rgb[2]);
621 const Vec3R mMin, mInvDim;
656 template<
typename Gr
idT>
665 tracer(grid, shader, camera, pixelSamples, seed);
670 template<
typename Gr
idT,
typename IntersectorT>
672 const IntersectorT& inter,
687 template<
typename Gr
idT,
typename IntersectorT>
688 inline LevelSetRayTracer<GridT, IntersectorT>::
689 LevelSetRayTracer(
const GridT& grid,
697 mShader(shader.copy()),
703 template<
typename Gr
idT,
typename IntersectorT>
713 mShader(shader.copy()),
719 template<
typename Gr
idT,
typename IntersectorT>
724 mInter(other.mInter),
725 mShader(other.mShader->copy()),
726 mCamera(other.mCamera),
727 mSubPixels(other.mSubPixels)
731 template<
typename Gr
idT,
typename IntersectorT>
735 if (mIsMaster)
delete [] mRand;
738 template<
typename Gr
idT,
typename IntersectorT>
743 mInter = IntersectorT(grid);
746 template<
typename Gr
idT,
typename IntersectorT>
754 template<
typename Gr
idT,
typename IntersectorT>
759 mShader.reset(shader.
copy());
762 template<
typename Gr
idT,
typename IntersectorT>
770 template<
typename Gr
idT,
typename IntersectorT>
775 if (pixelSamples == 0) {
778 mSubPixels = pixelSamples - 1;
780 if (mSubPixels > 0) {
781 mRand =
new double[16];
783 for (
size_t i=0; i<16; ++i) mRand[i] = rand();
789 template<
typename Gr
idT,
typename IntersectorT>
793 tbb::blocked_range<size_t> range(0, mCamera->height());
794 threaded ? tbb::parallel_for(range, *
this) : (*this)(range);
797 template<
typename Gr
idT,
typename IntersectorT>
803 const float frac = 1.0f / (1.0f + mSubPixels);
804 for (
size_t j=range.begin(), n=0, je = range.end(); j<je; ++j) {
805 for (
size_t i=0, ie = mCamera->width(); i<ie; ++i) {
807 RayType ray = mCamera->getRay(i, j);
808 Film::RGBA c = mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg;
809 for (
size_t k=0; k<mSubPixels; ++k, n +=2 ) {
810 ray = mCamera->getRay(i, j, mRand[n & 15], mRand[(n+1) & 15]);
811 c += mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg;
820 template<
typename IntersectorT,
typename SampleT>
823 : mAccessor(inter.grid().getConstAccessor())
825 , mPrimary(new IntersectorT(inter))
826 , mShadow(new IntersectorT(inter))
832 , mLightColor(0.7, 0.7, 0.7)
838 template<
typename IntersectorT,
typename SampleT>
841 : mAccessor(other.mAccessor)
842 , mCamera(other.mCamera)
843 , mPrimary(new IntersectorT(*(other.mPrimary)))
844 , mShadow(new IntersectorT(*(other.mShadow)))
845 , mPrimaryStep(other.mPrimaryStep)
846 , mShadowStep(other.mShadowStep)
847 , mCutOff(other.mCutOff)
848 , mLightGain(other.mLightGain)
849 , mLightDir(other.mLightDir)
850 , mLightColor(other.mLightColor)
851 , mAbsorption(other.mAbsorption)
852 , mScattering(other.mScattering)
856 template<
typename IntersectorT,
typename SampleT>
858 print(std::ostream& os,
int verboseLevel)
860 if (verboseLevel>0) {
861 os <<
"\nPrimary step: " << mPrimaryStep
862 <<
"\nShadow step: " << mShadowStep
863 <<
"\nCutoff: " << mCutOff
864 <<
"\nLightGain: " << mLightGain
865 <<
"\nLightDir: " << mLightDir
866 <<
"\nLightColor: " << mLightColor
867 <<
"\nAbsorption: " << mAbsorption
868 <<
"\nScattering: " << mScattering << std::endl;
870 mPrimary->print(os, verboseLevel);
873 template<
typename IntersectorT,
typename SampleT>
877 mPrimary.reset(
new IntersectorT(inter));
878 mShadow.reset(
new IntersectorT(inter));
881 template<
typename IntersectorT,
typename SampleT>
885 tbb::blocked_range<size_t> range(0, mCamera->height());
886 threaded ? tbb::parallel_for(range, *
this) : (*this)(range);
889 template<
typename IntersectorT,
typename SampleT>
893 SamplerType sampler(mAccessor, mShadow->grid().transform());
896 const Vec3R extinction = -mScattering-mAbsorption, One(1.0);
897 const Vec3R albedo = mLightColor*mScattering/(mScattering+mAbsorption);
898 const Real sGain = mLightGain;
899 const Real pStep = mPrimaryStep;
900 const Real sStep = mShadowStep;
901 const Real cutoff = mCutOff;
910 std::vector<typename RayType::TimeSpan> pTS, sTS;
914 for (
size_t j=range.begin(), je = range.end(); j<je; ++j) {
915 for (
size_t i=0, ie = mCamera->width(); i<ie; ++i) {
917 bg.
a = bg.
r = bg.
g = bg.
b = 0;
918 RayType pRay = mCamera->getRay(i, j);
919 if( !mPrimary->setWorldRay(pRay))
continue;
920 Vec3R pTrans(1.0), pLumi(0.0);
923 while (mPrimary->march(pT0, pT1)) {
924 for (
Real pT = pStep*ceil(pT0/pStep); pT <= pT1; pT += pStep) {
927 for (
size_t k=0; k<pTS.size(); ++k) {
928 Real pT = pStep*ceil(pTS[k].t0/pStep), pT1=pTS[k].t1;
929 for (; pT <= pT1; pT += pStep) {
931 Vec3R pPos = mPrimary->getWorldPos(pT);
932 const Real density = sampler.wsSample(pPos);
933 if (density < cutoff)
continue;
937 if( !mShadow->setWorldRay(sRay))
continue;
940 while (mShadow->march(sT0, sT1)) {
941 for (
Real sT = sStep*ceil(sT0/sStep); sT <= sT1; sT+= sStep) {
944 for (
size_t l=0; l<sTS.size(); ++l) {
945 Real sT = sStep*ceil(sTS[l].t0/sStep), sT1=sTS[l].t1;
946 for (; sT <= sT1; sT+= sStep) {
948 const Real d = sampler.wsSample(mShadow->getWorldPos(sT));
949 if (d < cutoff)
continue;
950 sTrans *=
math::Exp(extinction * d * sStep/(1.0+sT*sGain));
951 if (sTrans.
lengthSqr()<cutoff)
goto Luminance;
955 pLumi += albedo * sTrans * pTrans * (One-dT);
957 if (pTrans.lengthSqr()<cutoff)
goto Pixel;
964 bg.
a = 1.0f - pTrans.sum()/3.0f;
973 #endif // OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
OPENVDB_API Hermite min(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
Type Exp(const Type &x)
Return .
Definition: Math.h:620
math::Vec3< Real > Vec3R
Definition: Types.h:75
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition: Vec3.h:344
const Vec3T & dir() const
Definition: Ray.h:121
void setEye(const Vec3Type &eye)
Definition: Ray.h:88
int32_t Abs(int32_t i)
Return the absolute value of the given quantity.
Definition: Math.h:244
T lengthSqr() const
Definition: Vec3.h:219
Definition: Exceptions.h:88
void scaleTimes(RealT scale)
Definition: Ray.h:107
#define OPENVDB_VERSION_NAME
Definition: version.h:45
MatType rotation(const Quat< typename MatType::value_type > &q, typename MatType::value_type eps=1.0e-8)
Return the rotation matrix specified by the given quaternion.
Definition: Mat.h:153
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:199
OPENVDB_API Hermite max(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
Simple generator of random numbers over the range [0, 1)
Definition: Math.h:134
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:593
void postTranslate(const Vec3< T0 > &tr)
Right multiplies by the specified translation matrix, i.e. (*this) * Trans.
Definition: Mat4.h:726
Mat3< typename promote< T0, T1 >::type > operator*(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Matrix multiplication.
Definition: Mat3.h:608
double Real
Definition: Types.h:63
Vec3< T > unit(T eps=0) const
return normalized this, throws if null vector
Definition: Vec3.h:356
A general linear transform using homogeneous coordinates to perform rotation, scaling, shear and translation.
Definition: Maps.h:323
void setDir(const Vec3Type &dir)
Definition: Ray.h:90
Vec3< typename promote< T, typename Coord::ValueType >::type > operator+(const Vec3< T > &v0, const Coord &v1)
Allow a Coord to be added to or subtracted from a Vec3.
Definition: Coord.h:382
MatType unit(const MatType &mat, typename MatType::value_type eps=1.0e-8)
Return a copy of the given matrix with its upper 3x3 rows normalized.
Definition: Mat.h:626
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:67
Axis-aligned bounding box.
Definition: BBox.h:47