OpenVDB 13.0.1
Loading...
Searching...
No Matches
RayTracer.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @file RayTracer.h
5///
6/// @author Ken Museth
7///
8/// @brief Defines two simple but multithreaded renders, a level-set
9/// ray tracer and a volume render. To support these renders we also define
10/// perspective and orthographic cameras (both designed to mimic a Houdini camera),
11/// a Film class and some rather naive shaders.
12///
13/// @note These classes are included mainly as reference implementations for
14/// ray-tracing of OpenVDB volumes. In other words they are not intended for
15/// production-quality rendering, but could be used for fast pre-visualization
16/// or as a starting point for a more serious render.
17
18#ifndef OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
19#define OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
20
21#include <openvdb/Types.h>
22#include <openvdb/math/BBox.h>
23#include <openvdb/math/Ray.h>
24#include <openvdb/math/Math.h>
27#include <openvdb/util/Assert.h>
28#include <openvdb/openvdb.h>
29#include <deque>
30#include <iostream>
31#include <fstream>
32#include <limits>
33#include <memory>
34#include <string>
35#include <type_traits>
36#include <vector>
37
38namespace openvdb {
40namespace OPENVDB_VERSION_NAME {
41namespace tools {
42
43// Forward declarations
44class BaseCamera;
45class BaseShader;
46
47/// @brief Ray-trace a volume.
48template<typename GridT>
49void rayTrace(const GridT&,
50 const BaseShader&,
51 BaseCamera&,
52 size_t pixelSamples = 1,
53 unsigned int seed = 0,
54 bool threaded = true);
55
56/// @brief Ray-trace a volume using a given ray intersector.
57template<typename GridT, typename IntersectorT>
58void rayTrace(const GridT&,
59 const IntersectorT&,
60 const BaseShader&,
61 BaseCamera&,
62 size_t pixelSamples = 1,
63 unsigned int seed = 0,
64 bool threaded = true);
65
66
67///////////////////////////////LEVEL SET RAY TRACER ///////////////////////////////////////
68
69/// @brief A (very) simple multithreaded ray tracer specifically for narrow-band level sets.
70/// @details Included primarily as a reference implementation.
71template<typename GridT, typename IntersectorT = tools::LevelSetRayIntersector<GridT> >
73{
74public:
75 using GridType = GridT;
76 using Vec3Type = typename IntersectorT::Vec3Type;
77 using RayType = typename IntersectorT::RayType;
78
79 /// @brief Constructor based on an instance of the grid to be rendered.
80 LevelSetRayTracer(const GridT& grid,
81 const BaseShader& shader,
82 BaseCamera& camera,
83 size_t pixelSamples = 1,
84 unsigned int seed = 0);
85
86 /// @brief Constructor based on an instance of the intersector
87 /// performing the ray-intersections.
88 LevelSetRayTracer(const IntersectorT& inter,
89 const BaseShader& shader,
90 BaseCamera& camera,
91 size_t pixelSamples = 1,
92 unsigned int seed = 0);
93
94 /// @brief Copy constructor
96
97 /// @brief Destructor
99
100 /// @brief Set the level set grid to be ray-traced
101 void setGrid(const GridT& grid);
102
103 /// @brief Set the intersector that performs the actual
104 /// intersection of the rays against the narrow-band level set.
105 void setIntersector(const IntersectorT& inter);
106
107 /// @brief Set the shader derived from the abstract BaseShader class.
108 ///
109 /// @note The shader is not assumed to be thread-safe so each
110 /// thread will get its only deep copy. For instance it could
111 /// contains a ValueAccessor into another grid with auxiliary
112 /// shading information. Thus, make sure it is relatively
113 /// light-weight and efficient to copy (which is the case for ValueAccesors).
114 void setShader(const BaseShader& shader);
115
116 /// @brief Set the camera derived from the abstract BaseCamera class.
117 void setCamera(BaseCamera& camera);
118
119 /// @brief Set the number of pixel samples and the seed for
120 /// jittered sub-rays. A value larger than one implies
121 /// anti-aliasing by jittered super-sampling.
122 /// @throw ValueError if pixelSamples is equal to zero.
123 void setPixelSamples(size_t pixelSamples, unsigned int seed = 0);
124
125 /// @brief Perform the actual (potentially multithreaded) ray-tracing.
126 void render(bool threaded = true) const;
127
128 /// @brief Public method required by tbb::parallel_for.
129 /// @warning Never call it directly.
130 void operator()(const tbb::blocked_range<size_t>& range) const;
131
132private:
133 const bool mIsMaster;
134 double* mRand;
135 IntersectorT mInter;
136 std::unique_ptr<const BaseShader> mShader;
137 BaseCamera* mCamera;
138 size_t mSubPixels;
139};// LevelSetRayTracer
140
141
142///////////////////////////////VOLUME RENDER ///////////////////////////////////////
143
144/// @brief A (very) simple multithreaded volume render specifically for scalar density.
145/// @details Included primarily as a reference implementation.
146/// @note It will only compile if the IntersectorT is templated on a Grid with a
147/// floating-point voxel type.
148template <typename IntersectorT, typename SamplerT = tools::BoxSampler>
150{
151public:
152
153 using GridType = typename IntersectorT::GridType;
154 using RayType = typename IntersectorT::RayType;
155 using ValueType = typename GridType::ValueType;
156 using AccessorType = typename GridType::ConstAccessor;
158 static_assert(std::is_floating_point<ValueType>::value,
159 "VolumeRender requires a floating-point-valued grid");
160
161 /// @brief Constructor taking an intersector and a base camera.
162 VolumeRender(const IntersectorT& inter, BaseCamera& camera);
163
164 /// @brief Copy constructor which creates a thread-safe clone
165 VolumeRender(const VolumeRender& other);
166
167 /// @brief Perform the actual (potentially multithreaded) volume rendering.
168 void render(bool threaded=true) const;
169
170 /// @brief Set the camera derived from the abstract BaseCamera class.
171 void setCamera(BaseCamera& camera) { mCamera = &camera; }
172
173 /// @brief Set the intersector that performs the actual
174 /// intersection of the rays against the volume.
175 void setIntersector(const IntersectorT& inter);
176
177 /// @brief Set the vector components of a directional light source
178 /// @throw ArithmeticError if input is a null vector.
179 void setLightDir(Real x, Real y, Real z) { mLightDir = Vec3R(x,y,z).unit(); }
180
181 /// @brief Set the color of the directional light source.
182 void setLightColor(Real r, Real g, Real b) { mLightColor = Vec3R(r,g,b); }
183
184 /// @brief Set the integration step-size in voxel units for the primay ray.
185 void setPrimaryStep(Real primaryStep) { mPrimaryStep = primaryStep; }
186
187 /// @brief Set the integration step-size in voxel units for the primay ray.
188 void setShadowStep(Real shadowStep) { mShadowStep = shadowStep; }
189
190 /// @brief Set Scattering coefficients.
191 void setScattering(Real x, Real y, Real z) { mScattering = Vec3R(x,y,z); }
192
193 /// @brief Set absorption coefficients.
194 void setAbsorption(Real x, Real y, Real z) { mAbsorption = Vec3R(x,y,z); }
195
196 /// @brief Set parameter that imitates multi-scattering. A value
197 /// of zero implies no multi-scattering.
198 void setLightGain(Real gain) { mLightGain = gain; }
199
200 /// @brief Set the cut-off value for density and transmittance.
201 void setCutOff(Real cutOff) { mCutOff = cutOff; }
202
203 /// @brief Print parameters, statistics, memory usage and other information.
204 /// @param os a stream to which to write textual information
205 /// @param verboseLevel 1: print parameters only; 2: include grid
206 /// statistics; 3: include memory usage
207 void print(std::ostream& os = std::cout, int verboseLevel = 1);
208
209 /// @brief Public method required by tbb::parallel_for.
210 /// @warning Never call it directly.
211 void operator()(const tbb::blocked_range<size_t>& range) const;
212
213private:
214
215 AccessorType mAccessor;
216 BaseCamera* mCamera;
217 std::unique_ptr<IntersectorT> mPrimary, mShadow;
218 Real mPrimaryStep, mShadowStep, mCutOff, mLightGain;
219 Vec3R mLightDir, mLightColor, mAbsorption, mScattering;
220};//VolumeRender
221
222//////////////////////////////////////// FILM ////////////////////////////////////////
223
224/// @brief A simple class that allows for concurrent writes to pixels in an image,
225/// background initialization of the image, and PPM file output.
226class Film
227{
228public:
229 /// @brief Floating-point RGBA components in the range [0, 1].
230 /// @details This is our preferred representation for color processing.
231 struct RGBA
232 {
233 using ValueT = float;
234
235 RGBA() : r(0), g(0), b(0), a(1) {}
236 explicit RGBA(ValueT intensity) : r(intensity), g(intensity), b(intensity), a(1) {}
237 RGBA(ValueT _r, ValueT _g, ValueT _b, ValueT _a = static_cast<ValueT>(1.0)):
238 r(_r), g(_g), b(_b), a(_a)
239 {}
240 RGBA(double _r, double _g, double _b, double _a = 1.0)
241 : r(static_cast<ValueT>(_r))
242 , g(static_cast<ValueT>(_g))
243 , b(static_cast<ValueT>(_b))
244 , a(static_cast<ValueT>(_a))
245 {}
246
247 RGBA operator* (ValueT scale) const { return RGBA(r*scale, g*scale, b*scale);}
248 RGBA operator+ (const RGBA& rhs) const { return RGBA(r+rhs.r, g+rhs.g, b+rhs.b);}
249 RGBA operator* (const RGBA& rhs) const { return RGBA(r*rhs.r, g*rhs.g, b*rhs.b);}
250 RGBA& operator+=(const RGBA& rhs) { r+=rhs.r; g+=rhs.g; b+=rhs.b; a+=rhs.a; return *this;}
251
252 void over(const RGBA& rhs)
253 {
254 const float s = rhs.a*(1.0f-a);
255 r = a*r+s*rhs.r;
256 g = a*g+s*rhs.g;
257 b = a*b+s*rhs.b;
258 a = a + s;
259 }
260
262 };
263
264
265 Film(size_t width, size_t height)
266 : mWidth(width), mHeight(height), mSize(width*height), mPixels(new RGBA[mSize])
267 {
268 }
269 Film(size_t width, size_t height, const RGBA& bg)
270 : mWidth(width), mHeight(height), mSize(width*height), mPixels(new RGBA[mSize])
271 {
272 this->fill(bg);
273 }
274
275 const RGBA& pixel(size_t w, size_t h) const
276 {
277 OPENVDB_ASSERT(w < mWidth);
278 OPENVDB_ASSERT(h < mHeight);
279 return mPixels[w + h*mWidth];
280 }
281
282 RGBA& pixel(size_t w, size_t h)
283 {
284 OPENVDB_ASSERT(w < mWidth);
285 OPENVDB_ASSERT(h < mHeight);
286 return mPixels[w + h*mWidth];
287 }
288
289 void fill(const RGBA& rgb=RGBA(0)) { for (size_t i=0; i<mSize; ++i) mPixels[i] = rgb; }
290 void checkerboard(const RGBA& c1=RGBA(0.3f), const RGBA& c2=RGBA(0.6f), size_t size=32)
291 {
292 RGBA *p = mPixels.get();
293 for (size_t j = 0; j < mHeight; ++j) {
294 for (size_t i = 0; i < mWidth; ++i, ++p) {
295 *p = ((i & size) ^ (j & size)) ? c1 : c2;
296 }
297 }
298 }
299
300 template <typename Type = unsigned char>
301 std::unique_ptr<Type[]> convertToBitBuffer(const bool alpha = true) const
302 {
303 const size_t totalSize = mSize * (alpha ? 4 : 3);
304 std::unique_ptr<Type[]> buffer(new Type[totalSize]);
305 Type *q = buffer.get();
306 const RGBA* p = this->pixels();
307 size_t n = mSize;
308 while (n--) {
309 *q++ = static_cast<Type>(255.0f*(*p).r);
310 *q++ = static_cast<Type>(255.0f*(*p).g);
311 *q++ = static_cast<Type>(255.0f*(*p).b);
312 if(alpha)
313 *q++ = static_cast<Type>(255.0f*(*p).a);
314 ++p;
315 }
316 return buffer;
317 }
318
319 void savePPM(const std::string& fileName)
320 {
321 std::string name(fileName);
322 if (name.find_last_of(".") == std::string::npos) name.append(".ppm");
323
324 std::ofstream os(name.c_str(), std::ios_base::binary);
325 if (!os.is_open()) {
326 std::cerr << "Error opening PPM file \"" << name << "\"" << std::endl;
327 return;
328 }
329
330 auto buf = this->convertToBitBuffer<unsigned char>(/*alpha=*/false);
331 unsigned char* tmp = buf.get();
332
333 os << "P6\n" << mWidth << " " << mHeight << "\n255\n";
334 os.write(reinterpret_cast<const char*>(&(*tmp)), 3 * mSize * sizeof(unsigned char));
335 }
336
337 size_t width() const { return mWidth; }
338 size_t height() const { return mHeight; }
339 size_t numPixels() const { return mSize; }
340 const RGBA* pixels() const { return mPixels.get(); }
341
342private:
343 size_t mWidth, mHeight, mSize;
344 std::unique_ptr<RGBA[]> mPixels;
345};// Film
346
347
348//////////////////////////////////////// CAMERAS ////////////////////////////////////////
349
350/// Abstract base class for the perspective and orthographic cameras
352{
353public:
354 BaseCamera(Film& film, const Vec3R& rotation, const Vec3R& translation,
355 double frameWidth, double nearPlane, double farPlane)
356 : mFilm(&film)
357 , mScaleWidth(frameWidth)
358 , mScaleHeight(frameWidth * double(film.height()) / double(film.width()))
359 {
360 OPENVDB_ASSERT(nearPlane > 0 && farPlane > nearPlane);
361 mScreenToWorld.accumPostRotation(math::X_AXIS, rotation[0] * math::pi<double>() / 180.0);
362 mScreenToWorld.accumPostRotation(math::Y_AXIS, rotation[1] * math::pi<double>() / 180.0);
363 mScreenToWorld.accumPostRotation(math::Z_AXIS, rotation[2] * math::pi<double>() / 180.0);
364 mScreenToWorld.accumPostTranslation(translation);
365 this->initRay(nearPlane, farPlane);
366 }
367
368 virtual ~BaseCamera() {}
369
370 Film::RGBA& pixel(size_t i, size_t j) { return mFilm->pixel(i, j); }
371
372 size_t width() const { return mFilm->width(); }
373 size_t height() const { return mFilm->height(); }
374
375 /// Rotate the camera so its negative z-axis points at xyz and its
376 /// y axis is in the plane of the xyz and up vectors. In other
377 /// words the camera will look at xyz and use up as the
378 /// horizontal direction.
379 void lookAt(const Vec3R& xyz, const Vec3R& up = Vec3R(0.0, 1.0, 0.0))
380 {
381 const Vec3R orig = mScreenToWorld.applyMap(Vec3R(0.0));
382 const Vec3R dir = orig - xyz;
383 try {
384 Mat4d xform = math::aim<Mat4d>(dir, up);
385 xform.postTranslate(orig);
387 this->initRay(mRay.t0(), mRay.t1());
388 } catch (...) {}
389 }
390
391 Vec3R rasterToScreen(double i, double j, double z) const
392 {
393 return Vec3R( (2 * i / double(mFilm->width()) - 1) * mScaleWidth,
394 (1 - 2 * j / double(mFilm->height())) * mScaleHeight, z );
395 }
396
397 /// @brief Return a Ray in world space given the pixel indices and
398 /// optional offsets in the range [0, 1]. An offset of 0.5 corresponds
399 /// to the center of the pixel.
401 size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const = 0;
402
403protected:
404 void initRay(double t0, double t1)
405 {
406 mRay.setTimes(t0, t1);
407 mRay.setEye(mScreenToWorld.applyMap(Vec3R(0.0)));
408 mRay.setDir(mScreenToWorld.applyJacobian(Vec3R(0.0, 0.0, -1.0)));
409 }
410
415};// BaseCamera
416
417
419{
420 public:
421 /// @brief Constructor
422 /// @param film film (i.e. image) defining the pixel resolution
423 /// @param rotation rotation in degrees of the camera in world space
424 /// (applied in x, y, z order)
425 /// @param translation translation of the camera in world-space units,
426 /// applied after rotation
427 /// @param focalLength focal length of the camera in mm
428 /// (the default of 50mm corresponds to Houdini's default camera)
429 /// @param aperture width in mm of the frame, i.e., the visible field
430 /// (the default 41.2136 mm corresponds to Houdini's default camera)
431 /// @param nearPlane depth of the near clipping plane in world-space units
432 /// @param farPlane depth of the far clipping plane in world-space units
433 ///
434 /// @details If no rotation or translation is provided, the camera is placed
435 /// at (0,0,0) in world space and points in the direction of the negative z axis.
437 const Vec3R& rotation = Vec3R(0.0),
438 const Vec3R& translation = Vec3R(0.0),
439 double focalLength = 50.0,
440 double aperture = 41.2136,
441 double nearPlane = 1e-3,
442 double farPlane = std::numeric_limits<double>::max())
443 : BaseCamera(film, rotation, translation, 0.5*aperture/focalLength, nearPlane, farPlane)
444 {
445 }
446
447 ~PerspectiveCamera() override = default;
448
449 /// @brief Return a Ray in world space given the pixel indices and
450 /// optional offsets in the range [0,1]. An offset of 0.5 corresponds
451 /// to the center of the pixel.
453 size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const override
454 {
456 Vec3R dir = BaseCamera::rasterToScreen(Real(i) + iOffset, Real(j) + jOffset, -1.0);
457 dir = BaseCamera::mScreenToWorld.applyJacobian(dir);
458 dir.normalize();
459 ray.scaleTimes(1.0/dir.dot(ray.dir()));
460 ray.setDir(dir);
461 return ray;
462 }
463
464 /// @brief Return the horizontal field of view in degrees given a
465 /// focal lenth in mm and the specified aperture in mm.
466 static double focalLengthToFieldOfView(double length, double aperture)
467 {
468 return 360.0 / math::pi<double>() * atan(aperture/(2.0*length));
469 }
470 /// @brief Return the focal length in mm given a horizontal field of
471 /// view in degrees and the specified aperture in mm.
472 static double fieldOfViewToFocalLength(double fov, double aperture)
473 {
474 return aperture/(2.0*(tan(fov * math::pi<double>() / 360.0)));
475 }
476};// PerspectiveCamera
477
478
480{
481public:
482 /// @brief Constructor
483 /// @param film film (i.e. image) defining the pixel resolution
484 /// @param rotation rotation in degrees of the camera in world space
485 /// (applied in x, y, z order)
486 /// @param translation translation of the camera in world-space units,
487 /// applied after rotation
488 /// @param frameWidth width in of the frame in world-space units
489 /// @param nearPlane depth of the near clipping plane in world-space units
490 /// @param farPlane depth of the far clipping plane in world-space units
491 ///
492 /// @details If no rotation or translation is provided, the camera is placed
493 /// at (0,0,0) in world space and points in the direction of the negative z axis.
495 const Vec3R& rotation = Vec3R(0.0),
496 const Vec3R& translation = Vec3R(0.0),
497 double frameWidth = 1.0,
498 double nearPlane = 1e-3,
499 double farPlane = std::numeric_limits<double>::max())
500 : BaseCamera(film, rotation, translation, 0.5*frameWidth, nearPlane, farPlane)
501 {
502 }
503 ~OrthographicCamera() override = default;
504
506 size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const override
507 {
509 Vec3R eye = BaseCamera::rasterToScreen(Real(i) + iOffset, Real(j) + jOffset, 0.0);
510 ray.setEye(BaseCamera::mScreenToWorld.applyMap(eye));
511 return ray;
512 }
513};// OrthographicCamera
514
515
516//////////////////////////////////////// SHADERS ////////////////////////////////////////
517
518
519/// Abstract base class for the shaders
521{
522public:
525 BaseShader(const BaseShader&) = default;
526 virtual ~BaseShader() = default;
527 /// @brief Defines the interface of the virtual function that returns a RGB color.
528 /// @param xyz World position of the intersection point.
529 /// @param nml Normal in world space at the intersection point.
530 /// @param dir Direction of the ray in world space.
531 virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R& nml, const Vec3R& dir) const = 0;
532 virtual BaseShader* copy() const = 0;
533};
534
535
536/// @brief Shader that produces a simple matte.
537///
538/// @details The color can either be constant (if GridT =
539/// Film::RGBA which is the default) or defined in a separate Vec3
540/// color grid. Use SamplerType to define the order of interpolation
541/// (default is zero order, i.e. closes-point).
542template<typename GridT = Film::RGBA,
543 typename SamplerType = tools::PointSampler>
545{
546public:
547 MatteShader(const GridT& grid) : mAcc(grid.getAccessor()), mXform(&grid.transform()) {}
548 MatteShader(const MatteShader&) = default;
549 ~MatteShader() override = default;
550 /// @brief Sample the color grid at @c xyz; surface normal and ray direction are unused.
551 Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const override
552 {
553 typename GridT::ValueType v = zeroVal<typename GridT::ValueType>();
554 SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v);
555 return Film::RGBA(v[0], v[1], v[2]);
556 }
557 BaseShader* copy() const override { return new MatteShader<GridT, SamplerType>(*this); }
558
559private:
560 typename GridT::ConstAccessor mAcc;
561 const math::Transform* mXform;
562};
563
564// Template specialization using a constant color of the material.
565template<typename SamplerType>
566class MatteShader<Film::RGBA, SamplerType>: public BaseShader
567{
568public:
569 MatteShader(const Film::RGBA& c = Film::RGBA(1.0f)): mRGBA(c) {}
570 MatteShader(const MatteShader&) = default;
571 ~MatteShader() override = default;
572 /// @brief Return the constant matte color; all shading inputs are unused.
573 Film::RGBA operator()(const Vec3R&, const Vec3R&, const Vec3R&) const override
574 {
575 return mRGBA;
576 }
577 BaseShader* copy() const override { return new MatteShader<Film::RGBA, SamplerType>(*this); }
578
579private:
580 const Film::RGBA mRGBA;
581};
582
583
584/// @brief Color shader that treats the surface normal (x, y, z) as an
585/// RGB color.
586///
587/// @details The color can either be constant (if GridT =
588/// Film::RGBA which is the default) or defined in a separate Vec3
589/// color grid. Use SamplerType to define the order of interpolation
590/// (default is zero order, i.e. closes-point).
591template<typename GridT = Film::RGBA,
592 typename SamplerType = tools::PointSampler>
594{
595public:
596 NormalShader(const GridT& grid) : mAcc(grid.getAccessor()), mXform(&grid.transform()) {}
597 NormalShader(const NormalShader&) = default;
598 ~NormalShader() override = default;
599 /// @brief Sample the color grid at @c xyz and modulate by the surface normal; ray direction is unused.
600 Film::RGBA operator()(const Vec3R& xyz, const Vec3R& normal, const Vec3R&) const override
601 {
602 typename GridT::ValueType v = zeroVal<typename GridT::ValueType>();
603 SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v);
604 return Film::RGBA(v[0]*(normal[0]+1.0), v[1]*(normal[1]+1.0), v[2]*(normal[2]+1.0));
605 }
606 BaseShader* copy() const override { return new NormalShader<GridT, SamplerType>(*this); }
607
608private:
609 typename GridT::ConstAccessor mAcc;
610 const math::Transform* mXform;
611};
612
613// Template specialization using a constant color of the material.
614template<typename SamplerType>
615class NormalShader<Film::RGBA, SamplerType>: public BaseShader
616{
617public:
618 NormalShader(const Film::RGBA& c = Film::RGBA(1.0f)) : mRGBA(c*0.5f) {}
619 NormalShader(const NormalShader&) = default;
620 ~NormalShader() override = default;
621 /// @brief Return the constant color modulated by the surface normal; position and ray direction are unused.
622 Film::RGBA operator()(const Vec3R&, const Vec3R& normal, const Vec3R&) const override
623 {
624 return mRGBA * Film::RGBA(normal[0] + 1.0, normal[1] + 1.0, normal[2] + 1.0);
625 }
626 BaseShader* copy() const override { return new NormalShader<Film::RGBA, SamplerType>(*this); }
627
628private:
629 const Film::RGBA mRGBA;
630};
631
632
633/// @brief Color shader that treats position (x, y, z) as an RGB color in a
634/// cube defined from an axis-aligned bounding box in world space.
635///
636/// @details The color can either be constant (if GridT =
637/// Film::RGBA which is the default) or defined in a separate Vec3
638/// color grid. Use SamplerType to define the order of interpolation
639/// (default is zero order, i.e. closes-point).
640template<typename GridT = Film::RGBA,
641 typename SamplerType = tools::PointSampler>
643{
644public:
645 PositionShader(const math::BBox<Vec3R>& bbox, const GridT& grid)
646 : mMin(bbox.min())
647 , mInvDim(1.0/bbox.extents())
648 , mAcc(grid.getAccessor())
649 , mXform(&grid.transform())
650 {
651 }
653 ~PositionShader() override = default;
654 /// @brief Sample the color grid at @c xyz and modulate by the normalized position within the bbox; surface normal and ray direction are unused.
655 Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const override
656 {
657 typename GridT::ValueType v = zeroVal<typename GridT::ValueType>();
658 SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v);
659 const Vec3R rgb = (xyz - mMin) * mInvDim;
660 return Film::RGBA(v[0],v[1],v[2]) * Film::RGBA(rgb[0], rgb[1], rgb[2]);
661 }
662 BaseShader* copy() const override { return new PositionShader<GridT, SamplerType>(*this); }
663
664private:
665 const Vec3R mMin, mInvDim;
666 typename GridT::ConstAccessor mAcc;
667 const math::Transform* mXform;
668};
669
670// Template specialization using a constant color of the material.
671template<typename SamplerType>
672class PositionShader<Film::RGBA, SamplerType>: public BaseShader
673{
674public:
676 : mMin(bbox.min()), mInvDim(1.0/bbox.extents()), mRGBA(c) {}
678 ~PositionShader() override = default;
679 /// @brief Return the constant color modulated by the normalized position of @c xyz within the bbox; surface normal and ray direction are unused.
680 Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const override
681 {
682 const Vec3R rgb = (xyz - mMin)*mInvDim;
683 return mRGBA*Film::RGBA(rgb[0], rgb[1], rgb[2]);
684 }
685 BaseShader* copy() const override { return new PositionShader<Film::RGBA, SamplerType>(*this); }
686
687private:
688 const Vec3R mMin, mInvDim;
689 const Film::RGBA mRGBA;
690};
691
692
693/// @brief Simple diffuse Lambertian surface shader.
694///
695/// @details The diffuse color can either be constant (if GridT =
696/// Film::RGBA which is the default) or defined in a separate Vec3
697/// color grid. Lambertian implies that the (radiant) intensity is
698/// directly proportional to the cosine of the angle between the
699/// surface normal and the direction of the light source. Use
700/// SamplerType to define the order of interpolation (default is
701/// zero order, i.e. closes-point).
702template<typename GridT = Film::RGBA,
703 typename SamplerType = tools::PointSampler>
705{
706public:
707 DiffuseShader(const GridT& grid): mAcc(grid.getAccessor()), mXform(&grid.transform()) {}
708 DiffuseShader(const DiffuseShader&) = default;
709 ~DiffuseShader() override = default;
710 /// @brief Sample the color grid at @c xyz and apply Lambertian shading based on the surface normal and ray direction.
711 Film::RGBA operator()(const Vec3R& xyz, const Vec3R& normal, const Vec3R& rayDir) const override
712 {
713 typename GridT::ValueType v = zeroVal<typename GridT::ValueType>();
714 SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v);
715 // We take the abs of the dot product corresponding to having
716 // light sources at +/- rayDir, i.e., two-sided shading.
717 return Film::RGBA(v[0],v[1],v[2])
718 * static_cast<Film::RGBA::ValueT>(math::Abs(normal.dot(rayDir)));
719 }
720 BaseShader* copy() const override { return new DiffuseShader<GridT, SamplerType>(*this); }
721
722private:
723 typename GridT::ConstAccessor mAcc;
724 const math::Transform* mXform;
725};
726
727// Template specialization using a constant color of the material.
728template <typename SamplerType>
729class DiffuseShader<Film::RGBA, SamplerType>: public BaseShader
730{
731public:
732 DiffuseShader(const Film::RGBA& d = Film::RGBA(1.0f)): mRGBA(d) {}
733 DiffuseShader(const DiffuseShader&) = default;
734 ~DiffuseShader() override = default;
735 /// @brief Apply Lambertian shading using the constant material color, the surface normal and the ray direction; position is unused.
736 Film::RGBA operator()(const Vec3R&, const Vec3R& normal, const Vec3R& rayDir) const override
737 {
738 // We assume a single directional light source at the camera,
739 // so the cosine of the angle between the surface normal and the
740 // direction of the light source becomes the dot product of the
741 // surface normal and inverse direction of the ray. We also ignore
742 // negative dot products, corresponding to strict one-sided shading.
743 //return mRGBA * math::Max(0.0, normal.dot(-rayDir));
744
745 // We take the abs of the dot product corresponding to having
746 // light sources at +/- rayDir, i.e., two-sided shading.
747 return mRGBA * static_cast<Film::RGBA::ValueT>(math::Abs(normal.dot(rayDir)));
748 }
749 BaseShader* copy() const override { return new DiffuseShader<Film::RGBA, SamplerType>(*this); }
750
751private:
752 const Film::RGBA mRGBA;
753};
754
755
756//////////////////////////////////////// RAYTRACER ////////////////////////////////////////
757
758template<typename GridT>
759void rayTrace(const GridT& grid,
760 const BaseShader& shader,
761 BaseCamera& camera,
762 size_t pixelSamples,
763 unsigned int seed,
764 bool threaded)
765{
767 tracer(grid, shader, camera, pixelSamples, seed);
768 tracer.render(threaded);
769}
770
771
772template<typename GridT, typename IntersectorT>
773void rayTrace(const GridT&,
774 const IntersectorT& inter,
775 const BaseShader& shader,
776 BaseCamera& camera,
777 size_t pixelSamples,
778 unsigned int seed,
779 bool threaded)
780{
781 LevelSetRayTracer<GridT, IntersectorT> tracer(inter, shader, camera, pixelSamples, seed);
782 tracer.render(threaded);
783}
784
785
786//////////////////////////////////////// LevelSetRayTracer ////////////////////////////////////////
787
788
789template<typename GridT, typename IntersectorT>
791LevelSetRayTracer(const GridT& grid,
792 const BaseShader& shader,
793 BaseCamera& camera,
794 size_t pixelSamples,
795 unsigned int seed)
796 : mIsMaster(true),
797 mRand(nullptr),
798 mInter(grid),
799 mShader(shader.copy()),
800 mCamera(&camera)
801{
802 this->setPixelSamples(pixelSamples, seed);
803}
804
805template<typename GridT, typename IntersectorT>
807LevelSetRayTracer(const IntersectorT& inter,
808 const BaseShader& shader,
809 BaseCamera& camera,
810 size_t pixelSamples,
811 unsigned int seed)
812 : mIsMaster(true),
813 mRand(nullptr),
814 mInter(inter),
815 mShader(shader.copy()),
816 mCamera(&camera)
817{
818 this->setPixelSamples(pixelSamples, seed);
819}
820
821template<typename GridT, typename IntersectorT>
824 mIsMaster(false),
825 mRand(other.mRand),
826 mInter(other.mInter),
827 mShader(other.mShader->copy()),
828 mCamera(other.mCamera),
829 mSubPixels(other.mSubPixels)
830{
831}
832
833template<typename GridT, typename IntersectorT>
836{
837 if (mIsMaster) delete [] mRand;
838}
839
840template<typename GridT, typename IntersectorT>
842setGrid(const GridT& grid)
843{
844 OPENVDB_ASSERT(mIsMaster);
845 mInter = IntersectorT(grid);
846}
847
848template<typename GridT, typename IntersectorT>
850setIntersector(const IntersectorT& inter)
851{
852 OPENVDB_ASSERT(mIsMaster);
853 mInter = inter;
854}
855
856template<typename GridT, typename IntersectorT>
858setShader(const BaseShader& shader)
859{
860 OPENVDB_ASSERT(mIsMaster);
861 mShader.reset(shader.copy());
862}
863
864template<typename GridT, typename IntersectorT>
866setCamera(BaseCamera& camera)
867{
868 OPENVDB_ASSERT(mIsMaster);
869 mCamera = &camera;
870}
871
872template<typename GridT, typename IntersectorT>
874setPixelSamples(size_t pixelSamples, unsigned int seed)
875{
876 OPENVDB_ASSERT(mIsMaster);
877 if (pixelSamples == 0) {
878 OPENVDB_THROW(ValueError, "pixelSamples must be larger than zero!");
879 }
880 mSubPixels = pixelSamples - 1;
881 delete [] mRand;
882 if (mSubPixels > 0) {
883 mRand = new double[16];
884 math::Rand01<double> rand(seed);//offsets for anti-aliaing by jittered super-sampling
885 for (size_t i=0; i<16; ++i) mRand[i] = rand();
886 } else {
887 mRand = nullptr;
888 }
889}
890
891template<typename GridT, typename IntersectorT>
893render(bool threaded) const
894{
895 tbb::blocked_range<size_t> range(0, mCamera->height());
896 threaded ? tbb::parallel_for(range, *this) : (*this)(range);
897}
898
899template<typename GridT, typename IntersectorT>
901operator()(const tbb::blocked_range<size_t>& range) const
902{
903 const BaseShader& shader = *mShader;
904 Vec3Type xyz, nml;
905 const float frac = 1.0f / (1.0f + float(mSubPixels));
906 for (size_t j=range.begin(), n=0, je = range.end(); j<je; ++j) {
907 for (size_t i=0, ie = mCamera->width(); i<ie; ++i) {
908 Film::RGBA& bg = mCamera->pixel(i,j);
909 RayType ray = mCamera->getRay(i, j);//primary ray
910 Film::RGBA c = mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg;
911 for (size_t k=0; k<mSubPixels; ++k, n +=2 ) {
912 ray = mCamera->getRay(i, j, mRand[n & 15], mRand[(n+1) & 15]);
913 c += mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg;
914 }//loop over sub-pixels
915 bg = c*frac;
916 }//loop over image height
917 }//loop over image width
918}
919
920//////////////////////////////////////// VolumeRender ////////////////////////////////////////
921
922template<typename IntersectorT, typename SampleT>
924VolumeRender(const IntersectorT& inter, BaseCamera& camera)
925 : mAccessor(inter.grid().getConstAccessor())
926 , mCamera(&camera)
927 , mPrimary(new IntersectorT(inter))
928 , mShadow(new IntersectorT(inter))
929 , mPrimaryStep(1.0)
930 , mShadowStep(3.0)
931 , mCutOff(0.005)
932 , mLightGain(0.2)
933 , mLightDir(Vec3R(0.3, 0.3, 0).unit())
934 , mLightColor(0.7, 0.7, 0.7)
935 , mAbsorption(0.1)
936 , mScattering(1.5)
937{
938}
939
940template<typename IntersectorT, typename SampleT>
942VolumeRender(const VolumeRender& other)
943 : mAccessor(other.mAccessor)
944 , mCamera(other.mCamera)
945 , mPrimary(new IntersectorT(*(other.mPrimary)))
946 , mShadow(new IntersectorT(*(other.mShadow)))
947 , mPrimaryStep(other.mPrimaryStep)
948 , mShadowStep(other.mShadowStep)
949 , mCutOff(other.mCutOff)
950 , mLightGain(other.mLightGain)
951 , mLightDir(other.mLightDir)
952 , mLightColor(other.mLightColor)
953 , mAbsorption(other.mAbsorption)
954 , mScattering(other.mScattering)
955{
956}
957
958template<typename IntersectorT, typename SampleT>
960print(std::ostream& os, int verboseLevel)
961{
962 if (verboseLevel>0) {
963 os << "\nPrimary step: " << mPrimaryStep
964 << "\nShadow step: " << mShadowStep
965 << "\nCutoff: " << mCutOff
966 << "\nLightGain: " << mLightGain
967 << "\nLightDir: " << mLightDir
968 << "\nLightColor: " << mLightColor
969 << "\nAbsorption: " << mAbsorption
970 << "\nScattering: " << mScattering << std::endl;
971 }
972 mPrimary->print(os, verboseLevel);
973}
974
975template<typename IntersectorT, typename SampleT>
977setIntersector(const IntersectorT& inter)
978{
979 mPrimary.reset(new IntersectorT(inter));
980 mShadow.reset( new IntersectorT(inter));
981}
982
983template<typename IntersectorT, typename SampleT>
985render(bool threaded) const
986{
987 tbb::blocked_range<size_t> range(0, mCamera->height());
988 threaded ? tbb::parallel_for(range, *this) : (*this)(range);
989}
990
991template<typename IntersectorT, typename SampleT>
993operator()(const tbb::blocked_range<size_t>& range) const
994{
995 SamplerType sampler(mAccessor, mShadow->grid().transform());//light-weight wrapper
996
997 // Any variable prefixed with p (or s) means it's associated with a primary (or shadow) ray
998 const Vec3R extinction = -mScattering-mAbsorption, One(1.0);
999 const Vec3R albedo = mLightColor*mScattering/(mScattering+mAbsorption);//single scattering
1000 const Real sGain = mLightGain;//in-scattering along shadow ray
1001 const Real pStep = mPrimaryStep;//Integration step along primary ray in voxel units
1002 const Real sStep = mShadowStep;//Integration step along shadow ray in voxel units
1003 const Real cutoff = mCutOff;//Cutoff for density and transmittance
1004
1005 // For the sake of completeness we show how to use two different
1006 // methods (hits/march) in VolumeRayIntersector that produce
1007 // segments along the ray that intersects active values. Comment out
1008 // the line below to use VolumeRayIntersector::march instead of
1009 // VolumeRayIntersector::hits.
1010#define USE_HITS
1011#ifdef USE_HITS
1012 std::vector<typename RayType::TimeSpan> pTS, sTS;
1013 //std::deque<typename RayType::TimeSpan> pTS, sTS;
1014#endif
1015
1016 RayType sRay(Vec3R(0), mLightDir);//Shadow ray
1017 for (size_t j=range.begin(), je = range.end(); j<je; ++j) {
1018 for (size_t i=0, ie = mCamera->width(); i<ie; ++i) {
1019 Film::RGBA& bg = mCamera->pixel(i, j);
1020 bg.a = bg.r = bg.g = bg.b = 0;
1021 RayType pRay = mCamera->getRay(i, j);// Primary ray
1022 if( !mPrimary->setWorldRay(pRay)) continue;
1023 Vec3R pTrans(1.0), pLumi(0.0);
1024#ifndef USE_HITS
1025 Real pT0, pT1;
1026 while (mPrimary->march(pT0, pT1)) {
1027 for (Real pT = pStep*ceil(pT0/pStep); pT <= pT1; pT += pStep) {
1028#else
1029 mPrimary->hits(pTS);
1030 for (size_t k=0; k<pTS.size(); ++k) {
1031 Real pT = pStep*ceil(pTS[k].t0/pStep), pT1=pTS[k].t1;
1032 for (; pT <= pT1; pT += pStep) {
1033#endif
1034 Vec3R pPos = mPrimary->getWorldPos(pT);
1035 const Real density = sampler.wsSample(pPos);
1036 if (density < cutoff) continue;
1037 const Vec3R dT = math::Exp(extinction * density * pStep);
1038 Vec3R sTrans(1.0);
1039 sRay.setEye(pPos);
1040 if( !mShadow->setWorldRay(sRay)) continue;
1041#ifndef USE_HITS
1042 Real sT0, sT1;
1043 while (mShadow->march(sT0, sT1)) {
1044 for (Real sT = sStep*ceil(sT0/sStep); sT <= sT1; sT+= sStep) {
1045#else
1046 mShadow->hits(sTS);
1047 for (size_t l=0; l<sTS.size(); ++l) {
1048 Real sT = sStep*ceil(sTS[l].t0/sStep), sT1=sTS[l].t1;
1049 for (; sT <= sT1; sT+= sStep) {
1050#endif
1051 const Real d = sampler.wsSample(mShadow->getWorldPos(sT));
1052 if (d < cutoff) continue;
1053 sTrans *= math::Exp(extinction * d * sStep/(1.0+sT*sGain));
1054 if (sTrans.lengthSqr()<cutoff) goto Luminance;//Terminate sRay
1055 }//Integration over shadow segment
1056 }// Shadow ray march
1057 Luminance:
1058 pLumi += albedo * sTrans * pTrans * (One-dT);
1059 pTrans *= dT;
1060 if (pTrans.lengthSqr()<cutoff) goto Pixel; // Terminate Ray
1061 }//Integration over primary segment
1062 }// Primary ray march
1063 Pixel:
1064 bg.r = static_cast<Film::RGBA::ValueT>(pLumi[0]);
1065 bg.g = static_cast<Film::RGBA::ValueT>(pLumi[1]);
1066 bg.b = static_cast<Film::RGBA::ValueT>(pLumi[2]);
1067 bg.a = static_cast<Film::RGBA::ValueT>(1.0f - pTrans.sum()/3.0f);
1068 }//Horizontal pixel scan
1069 }//Vertical pixel scan
1070}
1071
1072
1073////////////////////////////////////////
1074
1075
1076// Explicit Template Instantiation
1077
1078#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1079
1080#ifdef OPENVDB_INSTANTIATE_RAYTRACER
1082#endif
1083
1084#define _FUNCTION(TreeT) \
1085 void rayTrace(const Grid<TreeT>&, const BaseShader&, BaseCamera&, size_t, unsigned int, bool)
1087#undef _FUNCTION
1088
1089#define _FUNCTION(TreeT) \
1090 void rayTrace(const Grid<TreeT>&, const tools::LevelSetRayIntersector<Grid<TreeT>>&, const BaseShader&, BaseCamera&, size_t, unsigned int, bool)
1092#undef _FUNCTION
1093
1096
1097#endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1098
1099
1100} // namespace tools
1101} // namespace OPENVDB_VERSION_NAME
1102} // namespace openvdb
1103
1104#endif // OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Accelerated intersection of a ray with a narrow-band level set or a generic (e.g. density) volume....
Definition Exceptions.h:65
A general linear transform using homogeneous coordinates to perform rotation, scaling,...
Definition Maps.h:296
Axis-aligned bounding box.
Definition BBox.h:24
void postTranslate(const Vec3< T0 > &tr)
Right multiplies by the specified translation matrix, i.e. (*this) * Trans.
Definition Mat4.h:714
Simple generator of random numbers over the range [0, 1)
Definition Math.h:180
Definition Ray.h:28
const Vec3T & dir() const
Definition Ray.h:100
void setEye(const Vec3Type &eye)
Definition Ray.h:65
void setDir(const Vec3Type &dir)
Definition Ray.h:67
void scaleTimes(RealT scale)
Definition Ray.h:85
Definition Transform.h:40
T dot(const Vec3< T > &v) const
Dot product.
Definition Vec3.h:192
T lengthSqr() const
Definition Vec3.h:212
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition Vec3.h:363
Abstract base class for the perspective and orthographic cameras.
Definition RayTracer.h:352
virtual ~BaseCamera()
Definition RayTracer.h:368
double mScaleHeight
Definition RayTracer.h:412
double mScaleWidth
Definition RayTracer.h:412
void initRay(double t0, double t1)
Definition RayTracer.h:404
void lookAt(const Vec3R &xyz, const Vec3R &up=Vec3R(0.0, 1.0, 0.0))
Definition RayTracer.h:379
virtual math::Ray< double > getRay(size_t i, size_t j, double iOffset=0.5, double jOffset=0.5) const =0
Return a Ray in world space given the pixel indices and optional offsets in the range [0,...
size_t width() const
Definition RayTracer.h:372
BaseCamera(Film &film, const Vec3R &rotation, const Vec3R &translation, double frameWidth, double nearPlane, double farPlane)
Definition RayTracer.h:354
math::Ray< double > mRay
Definition RayTracer.h:413
size_t height() const
Definition RayTracer.h:373
Film::RGBA & pixel(size_t i, size_t j)
Definition RayTracer.h:370
Vec3R rasterToScreen(double i, double j, double z) const
Definition RayTracer.h:391
Film * mFilm
Definition RayTracer.h:411
math::AffineMap mScreenToWorld
Definition RayTracer.h:414
Abstract base class for the shaders.
Definition RayTracer.h:521
BaseShader()
Definition RayTracer.h:524
math::Ray< Real > RayT
Definition RayTracer.h:523
virtual Film::RGBA operator()(const Vec3R &xyz, const Vec3R &nml, const Vec3R &dir) const =0
Defines the interface of the virtual function that returns a RGB color.
virtual BaseShader * copy() const =0
BaseShader(const BaseShader &)=default
DiffuseShader(const Film::RGBA &d=Film::RGBA(1.0f))
Definition RayTracer.h:732
BaseShader * copy() const override
Definition RayTracer.h:749
Film::RGBA operator()(const Vec3R &, const Vec3R &normal, const Vec3R &rayDir) const override
Apply Lambertian shading using the constant material color, the surface normal and the ray direction;...
Definition RayTracer.h:736
Film::RGBA operator()(const Vec3R &xyz, const Vec3R &normal, const Vec3R &rayDir) const override
Sample the color grid at xyz and apply Lambertian shading based on the surface normal and ray directi...
Definition RayTracer.h:711
BaseShader * copy() const override
Definition RayTracer.h:720
DiffuseShader(const GridT &grid)
Definition RayTracer.h:707
DiffuseShader(const DiffuseShader &)=default
A simple class that allows for concurrent writes to pixels in an image, background initialization of ...
Definition RayTracer.h:227
const RGBA & pixel(size_t w, size_t h) const
Definition RayTracer.h:275
size_t numPixels() const
Definition RayTracer.h:339
Film(size_t width, size_t height, const RGBA &bg)
Definition RayTracer.h:269
void savePPM(const std::string &fileName)
Definition RayTracer.h:319
void checkerboard(const RGBA &c1=RGBA(0.3f), const RGBA &c2=RGBA(0.6f), size_t size=32)
Definition RayTracer.h:290
std::unique_ptr< Type[]> convertToBitBuffer(const bool alpha=true) const
Definition RayTracer.h:301
size_t width() const
Definition RayTracer.h:337
RGBA & pixel(size_t w, size_t h)
Definition RayTracer.h:282
void fill(const RGBA &rgb=RGBA(0))
Definition RayTracer.h:289
size_t height() const
Definition RayTracer.h:338
const RGBA * pixels() const
Definition RayTracer.h:340
Film(size_t width, size_t height)
Definition RayTracer.h:265
Class that provides the interface for continuous sampling of values in a tree.
Definition Interpolation.h:286
ValueType wsSample(const Vec3d &wspoint) const
Sample in world space.
Definition Interpolation.h:341
A (very) simple multithreaded ray tracer specifically for narrow-band level sets.
Definition RayTracer.h:73
LevelSetRayTracer(const GridT &grid, const BaseShader &shader, BaseCamera &camera, size_t pixelSamples=1, unsigned int seed=0)
Constructor based on an instance of the grid to be rendered.
Definition RayTracer.h:791
typename IntersectorT::RayType RayType
Definition RayTracer.h:77
void render(bool threaded=true) const
Perform the actual (potentially multithreaded) ray-tracing.
Definition RayTracer.h:893
void setGrid(const GridT &grid)
Set the level set grid to be ray-traced.
Definition RayTracer.h:842
void operator()(const tbb::blocked_range< size_t > &range) const
Public method required by tbb::parallel_for.
Definition RayTracer.h:901
void setIntersector(const IntersectorT &inter)
Set the intersector that performs the actual intersection of the rays against the narrow-band level s...
Definition RayTracer.h:850
typename IntersectorT::Vec3Type Vec3Type
Definition RayTracer.h:76
void setCamera(BaseCamera &camera)
Set the camera derived from the abstract BaseCamera class.
Definition RayTracer.h:866
~LevelSetRayTracer()
Destructor.
Definition RayTracer.h:835
void setShader(const BaseShader &shader)
Set the shader derived from the abstract BaseShader class.
Definition RayTracer.h:858
GridT GridType
Definition RayTracer.h:75
void setPixelSamples(size_t pixelSamples, unsigned int seed=0)
Set the number of pixel samples and the seed for jittered sub-rays. A value larger than one implies a...
Definition RayTracer.h:874
BaseShader * copy() const override
Definition RayTracer.h:577
MatteShader(const Film::RGBA &c=Film::RGBA(1.0f))
Definition RayTracer.h:569
Film::RGBA operator()(const Vec3R &, const Vec3R &, const Vec3R &) const override
Return the constant matte color; all shading inputs are unused.
Definition RayTracer.h:573
BaseShader * copy() const override
Definition RayTracer.h:557
MatteShader(const MatteShader &)=default
Film::RGBA operator()(const Vec3R &xyz, const Vec3R &, const Vec3R &) const override
Sample the color grid at xyz; surface normal and ray direction are unused.
Definition RayTracer.h:551
MatteShader(const GridT &grid)
Definition RayTracer.h:547
NormalShader(const Film::RGBA &c=Film::RGBA(1.0f))
Definition RayTracer.h:618
BaseShader * copy() const override
Definition RayTracer.h:626
Film::RGBA operator()(const Vec3R &, const Vec3R &normal, const Vec3R &) const override
Return the constant color modulated by the surface normal; position and ray direction are unused.
Definition RayTracer.h:622
NormalShader(const GridT &grid)
Definition RayTracer.h:596
BaseShader * copy() const override
Definition RayTracer.h:606
NormalShader(const NormalShader &)=default
Film::RGBA operator()(const Vec3R &xyz, const Vec3R &normal, const Vec3R &) const override
Sample the color grid at xyz and modulate by the surface normal; ray direction is unused.
Definition RayTracer.h:600
math::Ray< double > getRay(size_t i, size_t j, double iOffset=0.5, double jOffset=0.5) const override
Return a Ray in world space given the pixel indices and optional offsets in the range [0,...
Definition RayTracer.h:505
OrthographicCamera(Film &film, const Vec3R &rotation=Vec3R(0.0), const Vec3R &translation=Vec3R(0.0), double frameWidth=1.0, double nearPlane=1e-3, double farPlane=std::numeric_limits< double >::max())
Constructor.
Definition RayTracer.h:494
PerspectiveCamera(Film &film, const Vec3R &rotation=Vec3R(0.0), const Vec3R &translation=Vec3R(0.0), double focalLength=50.0, double aperture=41.2136, double nearPlane=1e-3, double farPlane=std::numeric_limits< double >::max())
Constructor.
Definition RayTracer.h:436
static double focalLengthToFieldOfView(double length, double aperture)
Return the horizontal field of view in degrees given a focal lenth in mm and the specified aperture i...
Definition RayTracer.h:466
static double fieldOfViewToFocalLength(double fov, double aperture)
Return the focal length in mm given a horizontal field of view in degrees and the specified aperture ...
Definition RayTracer.h:472
math::Ray< double > getRay(size_t i, size_t j, double iOffset=0.5, double jOffset=0.5) const override
Return a Ray in world space given the pixel indices and optional offsets in the range [0,...
Definition RayTracer.h:452
PositionShader(const math::BBox< Vec3R > &bbox, const Film::RGBA &c=Film::RGBA(1.0f))
Definition RayTracer.h:675
BaseShader * copy() const override
Definition RayTracer.h:685
Film::RGBA operator()(const Vec3R &xyz, const Vec3R &, const Vec3R &) const override
Return the constant color modulated by the normalized position of xyz within the bbox; surface normal...
Definition RayTracer.h:680
BaseShader * copy() const override
Definition RayTracer.h:662
Film::RGBA operator()(const Vec3R &xyz, const Vec3R &, const Vec3R &) const override
Sample the color grid at xyz and modulate by the normalized position within the bbox; surface normal ...
Definition RayTracer.h:655
PositionShader(const PositionShader &)=default
PositionShader(const math::BBox< Vec3R > &bbox, const GridT &grid)
Definition RayTracer.h:645
void setShadowStep(Real shadowStep)
Set the integration step-size in voxel units for the primay ray.
Definition RayTracer.h:188
typename IntersectorT::RayType RayType
Definition RayTracer.h:154
void render(bool threaded=true) const
Perform the actual (potentially multithreaded) volume rendering.
Definition RayTracer.h:985
void setAbsorption(Real x, Real y, Real z)
Set absorption coefficients.
Definition RayTracer.h:194
void print(std::ostream &os=std::cout, int verboseLevel=1)
Print parameters, statistics, memory usage and other information.
Definition RayTracer.h:960
void operator()(const tbb::blocked_range< size_t > &range) const
Public method required by tbb::parallel_for.
Definition RayTracer.h:993
void setIntersector(const IntersectorT &inter)
Set the intersector that performs the actual intersection of the rays against the volume.
Definition RayTracer.h:977
void setLightDir(Real x, Real y, Real z)
Set the vector components of a directional light source.
Definition RayTracer.h:179
tools::GridSampler< AccessorType, SamplerT > SamplerType
Definition RayTracer.h:157
typename GridType::ValueType ValueType
Definition RayTracer.h:155
void setCamera(BaseCamera &camera)
Set the camera derived from the abstract BaseCamera class.
Definition RayTracer.h:171
void setPrimaryStep(Real primaryStep)
Set the integration step-size in voxel units for the primay ray.
Definition RayTracer.h:185
typename GridType::ConstAccessor AccessorType
Definition RayTracer.h:156
void setLightColor(Real r, Real g, Real b)
Set the color of the directional light source.
Definition RayTracer.h:182
typename IntersectorT::GridType GridType
Definition RayTracer.h:153
void setScattering(Real x, Real y, Real z)
Set Scattering coefficients.
Definition RayTracer.h:191
VolumeRender(const IntersectorT &inter, BaseCamera &camera)
Constructor taking an intersector and a base camera.
Definition RayTracer.h:924
void setLightGain(Real gain)
Set parameter that imitates multi-scattering. A value of zero implies no multi-scattering.
Definition RayTracer.h:198
void setCutOff(Real cutOff)
Set the cut-off value for density and transmittance.
Definition RayTracer.h:201
constexpr T pi()
Pi constant taken from Boost to match old behaviour.
Definition Math.h:130
Type Exp(const Type &x)
Return ex.
Definition Math.h:778
Coord Abs(const Coord &xyz)
Definition Coord.h:518
Mat4< double > Mat4d
Definition Mat4.h:1355
MatType aim(const Vec3< typename MatType::value_type > &direction, const Vec3< typename MatType::value_type > &vertical)
Return an orientation matrix such that z points along direction, and y is along the direction / verti...
Definition Mat.h:726
@ Z_AXIS
Definition Math.h:972
@ X_AXIS
Definition Math.h:970
@ Y_AXIS
Definition Math.h:971
void rayTrace(const GridT &, const BaseShader &, BaseCamera &, size_t pixelSamples=1, unsigned int seed=0, bool threaded=true)
Ray-trace a volume.
Definition RayTracer.h:759
double Real
Definition Types.h:40
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
math::Vec3< Real > Vec3R
Definition Types.h:53
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
A Ray class.
Definition Interpolation.h:121
Floating-point RGBA components in the range [0, 1].
Definition RayTracer.h:232
ValueT g
Definition RayTracer.h:261
ValueT a
Definition RayTracer.h:261
RGBA(ValueT intensity)
Definition RayTracer.h:236
ValueT r
Definition RayTracer.h:261
RGBA(ValueT _r, ValueT _g, ValueT _b, ValueT _a=static_cast< ValueT >(1.0))
Definition RayTracer.h:237
RGBA(double _r, double _g, double _b, double _a=1.0)
Definition RayTracer.h:240
void over(const RGBA &rhs)
Definition RayTracer.h:252
RGBA & operator+=(const RGBA &rhs)
Definition RayTracer.h:250
ValueT b
Definition RayTracer.h:261
RGBA()
Definition RayTracer.h:235
float ValueT
Definition RayTracer.h:233
Definition Interpolation.h:98
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:284
#define OPENVDB_INSTANTIATE_CLASS
Definition version.h.in:224
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:228