Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

View File

@@ -0,0 +1,175 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__NORI_BVH_H)
#define __NORI_BVH_H
#include <nori/mesh.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Bounding Volume Hierarchy for fast ray intersection queries
*
* This class builds a Bounding Volume Hierarchy (BVH) using a greedy
* divide and conquer build strategy, which locally maximizes a criterion
* known as the Surface Area Heuristic (SAH) to obtain a tree that is
* particularly well-suited for ray intersection queries.
*
* Construction of a BVH is generally slow; the implementation here runs
* in parallel to accelerate this process much as possible. For details
* on how this works, refer to the paper
*
* "Fast and Parallel Construction of SAH-based Bounding Volume Hierarchies"
* by Ingo Wald (Proc. IEEE/EG Symposium on Interactive Ray Tracing, 2007)
*
* \author Wenzel Jakob
*/
class Accel {
friend class BVHBuildTask;
public:
/// Create a new and empty BVH
Accel() { m_meshOffset.push_back(0u); }
/// Release all resources
virtual ~Accel() { clear(); };
/// Release all resources
void clear();
/**
* \brief Register a triangle mesh for inclusion in the BVH.
*
* This function can only be used before \ref build() is called
*/
void addMesh(Mesh *mesh);
/// Build the BVH
void build();
/**
* \brief Intersect a ray against all triangle meshes registered
* with the BVH
*
* Detailed information about the intersection, if any, will be
* stored in the provided \ref Intersection data record.
*
* The <tt>shadowRay</tt> parameter specifies whether this detailed
* information is really needed. When set to \c true, the
* function just checks whether or not there is occlusion, but without
* providing any more detail (i.e. \c its will not be filled with
* contents). This is usually much faster.
*
* \return \c true If an intersection was found
*/
bool rayIntersect(const Ray3f &ray, Intersection &its,
bool shadowRay = false) const;
/// Return the total number of meshes registered with the BVH
uint32_t getMeshCount() const { return (uint32_t) m_meshes.size(); }
/// Return the total number of internally represented triangles
uint32_t getTriangleCount() const { return m_meshOffset.back(); }
/// Return one of the registered meshes
Mesh *getMesh(uint32_t idx) { return m_meshes[idx]; }
/// Return one of the registered meshes (const version)
const Mesh *getMesh(uint32_t idx) const { return m_meshes[idx]; }
//// Return an axis-aligned bounding box containing the entire tree
const BoundingBox3f &getBoundingBox() const {
return m_bbox;
}
protected:
/**
* \brief Compute the mesh and triangle indices corresponding to
* a primitive index used by the underlying generic BVH implementation.
*/
uint32_t findMesh(uint32_t &idx) const {
auto it = std::lower_bound(m_meshOffset.begin(), m_meshOffset.end(), idx+1) - 1;
idx -= *it;
return (uint32_t) (it - m_meshOffset.begin());
}
//// Return an axis-aligned bounding box containing the given triangle
BoundingBox3f getBoundingBox(uint32_t index) const {
uint32_t meshIdx = findMesh(index);
return m_meshes[meshIdx]->getBoundingBox(index);
}
//// Return the centroid of the given triangle
Point3f getCentroid(uint32_t index) const {
uint32_t meshIdx = findMesh(index);
return m_meshes[meshIdx]->getCentroid(index);
}
/// Compute internal tree statistics
std::pair<float, uint32_t> statistics(uint32_t index = 0) const;
/* BVH node in 32 bytes */
struct BVHNode {
union {
struct {
unsigned flag : 1;
uint32_t size : 31;
uint32_t start;
} leaf;
struct {
unsigned flag : 1;
uint32_t axis : 31;
uint32_t rightChild;
} inner;
uint64_t data;
};
BoundingBox3f bbox;
bool isLeaf() const {
return leaf.flag == 1;
}
bool isInner() const {
return leaf.flag == 0;
}
bool isUnused() const {
return data == 0;
}
uint32_t start() const {
return leaf.start;
}
uint32_t end() const {
return leaf.start + leaf.size;
}
};
private:
std::vector<Mesh *> m_meshes; ///< List of meshes registered with the BVH
std::vector<uint32_t> m_meshOffset; ///< Index of the first triangle for each shape
std::vector<BVHNode> m_nodes; ///< BVH nodes
std::vector<uint32_t> m_indices; ///< Index references by BVH nodes
BoundingBox3f m_bbox; ///< Bounding box of the entire BVH
};
NORI_NAMESPACE_END
#endif /* __NORI_BVH_H */

View File

@@ -0,0 +1,399 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/ray.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Generic n-dimensional bounding box data structure
*
* Maintains a minimum and maximum position along each dimension and provides
* various convenience functions for querying and modifying them.
*
* This class is parameterized by the underlying point data structure,
* which permits the use of different scalar types and dimensionalities, e.g.
* \code
* TBoundingBox<Vector3i> integerBBox(Point3i(0, 1, 3), Point3i(4, 5, 6));
* TBoundingBox<Vector2d> doubleBBox(Point2d(0.0, 1.0), Point2d(4.0, 5.0));
* \endcode
*
* \tparam T The underlying point data type (e.g. \c Point2d)
* \ingroup libcore
*/
template <typename _PointType> struct TBoundingBox {
enum {
Dimension = _PointType::Dimension
};
typedef _PointType PointType;
typedef typename PointType::Scalar Scalar;
typedef typename PointType::VectorType VectorType;
/**
* \brief Create a new invalid bounding box
*
* Initializes the components of the minimum
* and maximum position to \f$\infty\f$ and \f$-\infty\f$,
* respectively.
*/
TBoundingBox() {
reset();
}
/// Create a collapsed bounding box from a single point
TBoundingBox(const PointType &p)
: min(p), max(p) { }
/// Create a bounding box from two positions
TBoundingBox(const PointType &min, const PointType &max)
: min(min), max(max) {
}
/// Test for equality against another bounding box
bool operator==(const TBoundingBox &bbox) const {
return min == bbox.min && max == bbox.max;
}
/// Test for inequality against another bounding box
bool operator!=(const TBoundingBox &bbox) const {
return min != bbox.min || max != bbox.max;
}
/// Calculate the n-dimensional volume of the bounding box
Scalar getVolume() const {
return (max - min).prod();
}
/// Calculate the n-1 dimensional volume of the boundary
float getSurfaceArea() const {
VectorType d = max - min;
float result = 0.0f;
for (int i=0; i<Dimension; ++i) {
float term = 1.0f;
for (int j=0; j<Dimension; ++j) {
if (i == j)
continue;
term *= d[j];
}
result += term;
}
return 2.0f * result;
}
/// Return the center point
PointType getCenter() const {
return (max + min) * (Scalar) 0.5f;
}
/**
* \brief Check whether a point lies \a on or \a inside the bounding box
*
* \param p The point to be tested
*
* \param strict Set this parameter to \c true if the bounding
* box boundary should be excluded in the test
*/
bool contains(const PointType &p, bool strict = false) const {
if (strict) {
return (p.array() > min.array()).all()
&& (p.array() < max.array()).all();
} else {
return (p.array() >= min.array()).all()
&& (p.array() <= max.array()).all();
}
}
/**
* \brief Check whether a specified bounding box lies \a on or \a within
* the current bounding box
*
* Note that by definition, an 'invalid' bounding box (where min=\f$\infty\f$
* and max=\f$-\infty\f$) does not cover any space. Hence, this method will always
* return \a true when given such an argument.
*
* \param strict Set this parameter to \c true if the bounding
* box boundary should be excluded in the test
*/
bool contains(const TBoundingBox &bbox, bool strict = false) const {
if (strict) {
return (bbox.min.array() > min.array()).all()
&& (bbox.max.array() < max.array()).all();
} else {
return (bbox.min.array() >= min.array()).all()
&& (bbox.max.array() <= max.array()).all();
}
}
/**
* \brief Check two axis-aligned bounding boxes for possible overlap.
*
* \param strict Set this parameter to \c true if the bounding
* box boundary should be excluded in the test
*
* \return \c true If overlap was detected.
*/
bool overlaps(const TBoundingBox &bbox, bool strict = false) const {
if (strict) {
return (bbox.min.array() < max.array()).all()
&& (bbox.max.array() > min.array()).all();
} else {
return (bbox.min.array() <= max.array()).all()
&& (bbox.max.array() >= min.array()).all();
}
}
/**
* \brief Calculate the smallest squared distance between
* the axis-aligned bounding box and the point \c p.
*/
Scalar squaredDistanceTo(const PointType &p) const {
Scalar result = 0;
for (int i=0; i<Dimension; ++i) {
Scalar value = 0;
if (p[i] < min[i])
value = min[i] - p[i];
else if (p[i] > max[i])
value = p[i] - max[i];
result += value*value;
}
return result;
}
/**
* \brief Calculate the smallest distance between
* the axis-aligned bounding box and the point \c p.
*/
Scalar distanceTo(const PointType &p) const {
return std::sqrt(squaredDistanceTo(p));
}
/**
* \brief Calculate the smallest square distance between
* the axis-aligned bounding box and \c bbox.
*/
Scalar squaredDistanceTo(const TBoundingBox &bbox) const {
Scalar result = 0;
for (int i=0; i<Dimension; ++i) {
Scalar value = 0;
if (bbox.max[i] < min[i])
value = min[i] - bbox.max[i];
else if (bbox.min[i] > max[i])
value = bbox.min[i] - max[i];
result += value*value;
}
return result;
}
/**
* \brief Calculate the smallest distance between
* the axis-aligned bounding box and \c bbox.
*/
Scalar distanceTo(const TBoundingBox &bbox) const {
return std::sqrt(squaredDistanceTo(bbox));
}
/**
* \brief Check whether this is a valid bounding box
*
* A bounding box \c bbox is valid when
* \code
* bbox.min[dim] <= bbox.max[dim]
* \endcode
* holds along each dimension \c dim.
*/
bool isValid() const {
return (max.array() >= min.array()).all();
}
/// Check whether this bounding box has collapsed to a single point
bool isPoint() const {
return (max.array() == min.array()).all();
}
/// Check whether this bounding box has any associated volume
bool hasVolume() const {
return (max.array() > min.array()).all();
}
/// Return the dimension index with the largest associated side length
int getMajorAxis() const {
VectorType d = max - min;
int largest = 0;
for (int i=1; i<Dimension; ++i)
if (d[i] > d[largest])
largest = i;
return largest;
}
/// Return the dimension index with the shortest associated side length
int getMinorAxis() const {
VectorType d = max - min;
int shortest = 0;
for (int i=1; i<Dimension; ++i)
if (d[i] < d[shortest])
shortest = i;
return shortest;
}
/**
* \brief Calculate the bounding box extents
* \return max-min
*/
VectorType getExtents() const {
return max - min;
}
/// Clip to another bounding box
void clip(const TBoundingBox &bbox) {
min = min.cwiseMax(bbox.min);
max = max.cwiseMin(bbox.max);
}
/**
* \brief Mark the bounding box as invalid.
*
* This operation sets the components of the minimum
* and maximum position to \f$\infty\f$ and \f$-\infty\f$,
* respectively.
*/
void reset() {
min.setConstant( std::numeric_limits<Scalar>::infinity());
max.setConstant(-std::numeric_limits<Scalar>::infinity());
}
/// Expand the bounding box to contain another point
void expandBy(const PointType &p) {
min = min.cwiseMin(p);
max = max.cwiseMax(p);
}
/// Expand the bounding box to contain another bounding box
void expandBy(const TBoundingBox &bbox) {
min = min.cwiseMin(bbox.min);
max = max.cwiseMax(bbox.max);
}
/// Merge two bounding boxes
static TBoundingBox merge(const TBoundingBox &bbox1, const TBoundingBox &bbox2) {
return TBoundingBox(
bbox1.min.cwiseMin(bbox2.min),
bbox1.max.cwiseMax(bbox2.max)
);
}
/// Return the index of the largest axis
int getLargestAxis() const {
VectorType extents = max-min;
if (extents[0] >= extents[1] && extents[0] >= extents[2])
return 0;
else if (extents[1] >= extents[0] && extents[1] >= extents[2])
return 1;
else
return 2;
}
/// Return the position of a bounding box corner
PointType getCorner(int index) const {
PointType result;
for (int i=0; i<Dimension; ++i)
result[i] = (index & (1 << i)) ? max[i] : min[i];
return result;
}
/// Return a string representation of the bounding box
std::string toString() const {
if (!isValid())
return "BoundingBox[invalid]";
else
return tfm::format("BoundingBox[min=%s, max=%s]", min.toString(), max.toString());
}
/// Check if a ray intersects a bounding box
bool rayIntersect(const Ray3f &ray) const {
float nearT = -std::numeric_limits<float>::infinity();
float farT = std::numeric_limits<float>::infinity();
for (int i=0; i<3; i++) {
float origin = ray.o[i];
float minVal = min[i], maxVal = max[i];
if (ray.d[i] == 0) {
if (origin < minVal || origin > maxVal)
return false;
} else {
float t1 = (minVal - origin) * ray.dRcp[i];
float t2 = (maxVal - origin) * ray.dRcp[i];
if (t1 > t2)
std::swap(t1, t2);
nearT = std::max(t1, nearT);
farT = std::min(t2, farT);
if (!(nearT <= farT))
return false;
}
}
return ray.mint <= farT && nearT <= ray.maxt;
}
/// Return the overlapping region of the bounding box and an unbounded ray
bool rayIntersect(const Ray3f &ray, float &nearT, float &farT) const {
nearT = -std::numeric_limits<float>::infinity();
farT = std::numeric_limits<float>::infinity();
for (int i=0; i<3; i++) {
float origin = ray.o[i];
float minVal = min[i], maxVal = max[i];
if (ray.d[i] == 0) {
if (origin < minVal || origin > maxVal)
return false;
} else {
float t1 = (minVal - origin) * ray.dRcp[i];
float t2 = (maxVal - origin) * ray.dRcp[i];
if (t1 > t2)
std::swap(t1, t2);
nearT = std::max(t1, nearT);
farT = std::min(t2, farT);
if (!(nearT <= farT))
return false;
}
}
return true;
}
PointType min; ///< Component-wise minimum
PointType max; ///< Component-wise maximum
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,54 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/color.h>
#include <nori/vector.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Stores a RGB high dynamic-range bitmap
*
* The bitmap class provides I/O support using the OpenEXR file format
*/
class Bitmap : public Eigen::Array<Color3f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> {
public:
typedef Eigen::Array<Color3f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Base;
/**
* \brief Allocate a new bitmap of the specified size
*
* The contents will initially be undefined, so make sure
* to call \ref clear() if necessary
*/
Bitmap(const Vector2i &size = Vector2i(0, 0))
: Base(size.y(), size.x()) { }
/// Load an OpenEXR file with the specified filename
Bitmap(const std::string &filename);
/// Save the bitmap as an EXR file with the specified filename
void saveEXR(const std::string &filename);
/// Save the bitmap as a PNG file (with sRGB tonemapping) with the specified filename
void savePNG(const std::string &filename);
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,166 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* =======================================================================
This file contains classes for parallel rendering of "image blocks".
* ======================================================================= */
#pragma once
#include <nori/color.h>
#include <nori/vector.h>
#include <tbb/mutex.h>
#define NORI_BLOCK_SIZE 32 /* Block size used for parallelization */
NORI_NAMESPACE_BEGIN
/**
* \brief Weighted pixel storage for a rectangular subregion of an image
*
* This class implements storage for a rectangular subregion of a
* larger image that is being rendered. For each pixel, it records color
* values along with a weight that specifies the accumulated influence of
* nearby samples on the pixel (according to the used reconstruction filter).
*
* When rendering with filters, the samples in a rectangular
* region will generally also contribute to pixels just outside of
* this region. For that reason, this class also stores information about
* a small border region around the rectangle, whose size depends on the
* properties of the reconstruction filter.
*/
class ImageBlock : public Eigen::Array<Color4f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> {
public:
/**
* Create a new image block of the specified maximum size
* \param size
* Desired maximum size of the block
* \param filter
* Samples will be convolved with the image reconstruction
* filter provided here.
*/
ImageBlock(const Vector2i &size, const ReconstructionFilter *filter);
/// Release all memory
~ImageBlock();
/// Configure the offset of the block within the main image
void setOffset(const Point2i &offset) { m_offset = offset; }
/// Return the offset of the block within the main image
inline const Point2i &getOffset() const { return m_offset; }
/// Configure the size of the block within the main image
void setSize(const Point2i &size) { m_size = size; }
/// Return the size of the block within the main image
inline const Vector2i &getSize() const { return m_size; }
/// Return the border size in pixels
inline int getBorderSize() const { return m_borderSize; }
/**
* \brief Turn the block into a proper bitmap
*
* This entails normalizing all pixels and discarding
* the border region.
*/
Bitmap *toBitmap() const;
/// Convert a bitmap into an image block
void fromBitmap(const Bitmap &bitmap);
/// Clear all contents
void clear() { setConstant(Color4f()); }
/// Record a sample with the given position and radiance value
void put(const Point2f &pos, const Color3f &value);
/**
* \brief Merge another image block into this one
*
* During the merge operation, this function locks
* the destination block using a mutex.
*/
void put(ImageBlock &b);
/// Lock the image block (using an internal mutex)
inline void lock() const { m_mutex.lock(); }
/// Unlock the image block
inline void unlock() const { m_mutex.unlock(); }
/// Return a human-readable string summary
std::string toString() const;
protected:
Point2i m_offset;
Vector2i m_size;
int m_borderSize = 0;
float *m_filter = nullptr;
float m_filterRadius = 0;
float *m_weightsX = nullptr;
float *m_weightsY = nullptr;
float m_lookupFactor = 0;
mutable tbb::mutex m_mutex;
};
/**
* \brief Spiraling block generator
*
* This class can be used to chop up an image into many small
* rectangular blocks suitable for parallel rendering. The blocks
* are ordered in spiraling pattern so that the center is
* rendered first.
*/
class BlockGenerator {
public:
/**
* \brief Create a block generator with
* \param size
* Size of the image that should be split into blocks
* \param blockSize
* Maximum size of the individual blocks
*/
BlockGenerator(const Vector2i &size, int blockSize);
/**
* \brief Return the next block to be rendered
*
* This function is thread-safe
*
* \return \c false if there were no more blocks
*/
bool next(ImageBlock &block);
/// Return the total number of blocks
int getBlockCount() const { return m_blocksLeft; }
protected:
enum EDirection { ERight = 0, EDown, ELeft, EUp };
Point2i m_block;
Vector2i m_numBlocks;
Vector2i m_size;
int m_blockSize;
int m_numSteps;
int m_blocksLeft;
int m_stepsLeft;
int m_direction;
tbb::mutex m_mutex;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,117 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Convenience data structure used to pass multiple
* parameters to the evaluation and sampling routines in \ref BSDF
*/
struct BSDFQueryRecord {
/// Incident direction (in the local frame)
Vector3f wi;
/// Outgoing direction (in the local frame)
Vector3f wo;
/// Relative refractive index in the sampled direction
float eta;
Point2f uv;
/// Measure associated with the sample
EMeasure measure;
/// Create a new record for sampling the BSDF
BSDFQueryRecord(const Vector3f &wi)
: wi(wi), eta(1.f), measure(EUnknownMeasure) { }
/// Create a new record for querying the BSDF
BSDFQueryRecord(const Vector3f &wi,
const Vector3f &wo, EMeasure measure)
: wi(wi), wo(wo), eta(1.f), measure(measure) { }
};
/**
* \brief Superclass of all bidirectional scattering distribution functions
*/
class BSDF : public NoriObject {
public:
/**
* \brief Sample the BSDF and return the importance weight (i.e. the
* value of the BSDF * cos(theta_o) divided by the probability density
* of the sample with respect to solid angles).
*
* \param bRec A BSDF query record
* \param sample A uniformly distributed sample on \f$[0,1]^2\f$
*
* \return The BSDF value divided by the probability density of the sample
* sample. The returned value also includes the cosine
* foreshortening factor associated with the outgoing direction,
* when this is appropriate. A zero value means that sampling
* failed.
*/
virtual Color3f sample(BSDFQueryRecord &bRec, const Point2f &sample) const = 0;
/**
* \brief Evaluate the BSDF for a pair of directions and measure
* specified in \code bRec
*
* \param bRec
* A record with detailed information on the BSDF query
* \return
* The BSDF value, evaluated for each color channel
*/
virtual Color3f eval(const BSDFQueryRecord &bRec) const = 0;
/**
* \brief Compute the probability of sampling \c bRec.wo
* (conditioned on \c bRec.wi).
*
* This method provides access to the probability density that
* is realized by the \ref sample() method.
*
* \param bRec
* A record with detailed information on the BSDF query
*
* \return
* A probability/density value expressed with respect
* to the specified measure
*/
virtual float pdf(const BSDFQueryRecord &bRec) const = 0;
/**
* \brief Return the type of object (i.e. Mesh/BSDF/etc.)
* provided by this instance
* */
EClassType getClassType() const { return EBSDF; }
/**
* \brief Return whether or not this BRDF is diffuse. This
* is primarily used by photon mapping to decide whether
* or not to store photons on a surface
*/
virtual bool isDiffuse() const { return false; }
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,76 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Generic camera interface
*
* This class provides an abstract interface to cameras in Nori and
* exposes the ability to sample their response function. By default, only
* a perspective camera implementation exists, but you may choose to
* implement other types (e.g. an environment camera, or a physically-based
* camera model that simulates the behavior actual lenses)
*/
class Camera : public NoriObject {
public:
/**
* \brief Importance sample a ray according to the camera's response function
*
* \param ray
* A ray data structure to be filled with a position
* and direction value
*
* \param samplePosition
* Denotes the desired sample position on the film
* expressed in fractional pixel coordinates
*
* \param apertureSample
* A uniformly distributed 2D vector that is used to sample
* a position on the aperture of the sensor if necessary.
*
* \return
* An importance weight associated with the sampled ray.
* This accounts for the difference in the camera response
* function and the sampling density.
*/
virtual Color3f sampleRay(Ray3f &ray,
const Point2f &samplePosition,
const Point2f &apertureSample) const = 0;
/// Return the size of the output image in pixels
const Vector2i &getOutputSize() const { return m_outputSize; }
/// Return the camera's reconstruction filter in image space
const ReconstructionFilter *getReconstructionFilter() const { return m_rfilter; }
/**
* \brief Return the type of object (i.e. Mesh/Camera/etc.)
* provided by this instance
* */
EClassType getClassType() const { return ECamera; }
protected:
Vector2i m_outputSize;
ReconstructionFilter *m_rfilter;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,138 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Represents a linear RGB color value
*/
struct Color3f : public Eigen::Array3f {
public:
typedef Eigen::Array3f Base;
/// Initialize the color vector with a uniform value
Color3f(float value = 0.f) : Base(value, value, value) { }
/// Initialize the color vector with specific per-channel values
Color3f(float r, float g, float b) : Base(r, g, b) { }
/// Construct a color vector from ArrayBase (needed to play nice with Eigen)
template <typename Derived> Color3f(const Eigen::ArrayBase<Derived>& p)
: Base(p) { }
/// Assign a color vector from ArrayBase (needed to play nice with Eigen)
template <typename Derived> Color3f &operator=(const Eigen::ArrayBase<Derived>& p) {
this->Base::operator=(p);
return *this;
}
/// Return a reference to the red channel
float &r() { return x(); }
/// Return a reference to the red channel (const version)
const float &r() const { return x(); }
/// Return a reference to the green channel
float &g() { return y(); }
/// Return a reference to the green channel (const version)
const float &g() const { return y(); }
/// Return a reference to the blue channel
float &b() { return z(); }
/// Return a reference to the blue channel (const version)
const float &b() const { return z(); }
/// Clamp to the positive range
Color3f clamp() const { return Color3f(std::max(r(), 0.0f),
std::max(g(), 0.0f), std::max(b(), 0.0f)); }
/// Check if the color vector contains a NaN/Inf/negative value
bool isValid() const;
/// Convert from sRGB to linear RGB
Color3f toLinearRGB() const;
/// Convert from linear RGB to sRGB
Color3f toSRGB() const;
/// Return the associated luminance
float getLuminance() const;
/// Return a human-readable string summary
std::string toString() const {
return tfm::format("[%f, %f, %f]", coeff(0), coeff(1), coeff(2));
}
};
inline Color3f lerp(float v, const Color3f& a, const Color3f& b){
return (1.0-v)*a + v * b;
}
inline Color3f bilerp(float x, float y, const Color3f& a, const Color3f& b, const Color3f& c, const Color3f& d){
return a*(1.0-x)*(1.0-y)+
b*(x)*(1.0-y)+
c*(1.0-x)*(y)+
d*(x)*(y);;
}
/**
* \brief Represents a linear RGB color and a weight
*
* This is used by Nori's image reconstruction filter code
*/
struct Color4f : public Eigen::Array4f {
public:
typedef Eigen::Array4f Base;
/// Create an zero value
Color4f() : Base(0.0f, 0.0f, 0.0f, 0.0f) { }
/// Create from a 3-channel color
Color4f(const Color3f &c) : Base(c.r(), c.g(), c.b(), 1.0f) { }
/// Initialize the color vector with specific per-channel values
Color4f(float r, float g, float b, float w) : Base(r, g, b, w) { }
/// Construct a color vector from ArrayBase (needed to play nice with Eigen)
template <typename Derived> Color4f(const Eigen::ArrayBase<Derived>& p)
: Base(p) { }
/// Assign a color vector from ArrayBase (needed to play nice with Eigen)
template <typename Derived> Color4f &operator=(const Eigen::ArrayBase<Derived>& p) {
this->Base::operator=(p);
return *this;
}
/// Divide by the filter weight and convert into a \ref Color3f value
Color3f divideByFilterWeight() const {
if (w() != 0)
return head<3>() / w();
else
return Color3f(0.0f);
}
/// Return a human-readable string summary
std::string toString() const {
return tfm::format("[%f, %f, %f, %f]", coeff(0), coeff(1), coeff(2), coeff(3));
}
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,275 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined(_MSC_VER)
/* Disable some warnings on MSVC++ */
#pragma warning(disable : 4127 4702 4100 4515 4800 4146 4512)
#define WIN32_LEAN_AND_MEAN /* Don't ever include MFC on Windows */
#define NOMINMAX /* Don't override min/max */
#endif
/* Include the basics needed by any Nori file */
#include <iostream>
#include <algorithm>
#include <vector>
#include <Eigen/Core>
#include <stdint.h>
#include <ImathPlatform.h>
#include <tinyformat.h>
/* Convenience definitions */
#define NORI_NAMESPACE_BEGIN namespace nori {
#define NORI_NAMESPACE_END }
#if defined(__NORI_APPLE__NORI_)
#define PLATFORM_MACOS
#elif defined(__NORI_linux__NORI_)
#define PLATFORM_LINUX
#elif defined(WIN32)
#define PLATFORM_WINDOWS
#endif
/* "Ray epsilon": relative error threshold for ray intersection computations */
#define Epsilon 1e-4f
/* A few useful constants */
#undef M_PI
#define M_PI 3.14159265358979323846f
#define INV_PI 0.31830988618379067154f
#define INV_TWOPI 0.15915494309189533577f
#define INV_FOURPI 0.07957747154594766788f
#define SQRT_TWO 1.41421356237309504880f
#define INV_SQRT_TWO 0.70710678118654752440f
/* Forward declarations */
namespace filesystem {
class path;
class resolver;
};
NORI_NAMESPACE_BEGIN
/* Forward declarations */
template <typename Scalar, int Dimension> struct TVector;
template <typename Scalar, int Dimension> struct TPoint;
template <typename Point, typename Vector> struct TRay;
template <typename Point> struct TBoundingBox;
/* Basic Nori data structures (vectors, points, rays, bounding boxes,
kd-trees) are oblivious to the underlying data type and dimension.
The following list of typedefs establishes some convenient aliases
for specific types. */
typedef TVector<float, 1> Vector1f;
typedef TVector<float, 2> Vector2f;
typedef TVector<float, 3> Vector3f;
typedef TVector<float, 4> Vector4f;
typedef TVector<double, 1> Vector1d;
typedef TVector<double, 2> Vector2d;
typedef TVector<double, 3> Vector3d;
typedef TVector<double, 4> Vector4d;
typedef TVector<int, 1> Vector1i;
typedef TVector<int, 2> Vector2i;
typedef TVector<int, 3> Vector3i;
typedef TVector<int, 4> Vector4i;
typedef TPoint<float, 1> Point1f;
typedef TPoint<float, 2> Point2f;
typedef TPoint<float, 3> Point3f;
typedef TPoint<float, 4> Point4f;
typedef TPoint<double, 1> Point1d;
typedef TPoint<double, 2> Point2d;
typedef TPoint<double, 3> Point3d;
typedef TPoint<double, 4> Point4d;
typedef TPoint<int, 1> Point1i;
typedef TPoint<int, 2> Point2i;
typedef TPoint<int, 3> Point3i;
typedef TPoint<int, 4> Point4i;
typedef TBoundingBox<Point1f> BoundingBox1f;
typedef TBoundingBox<Point2f> BoundingBox2f;
typedef TBoundingBox<Point3f> BoundingBox3f;
typedef TBoundingBox<Point4f> BoundingBox4f;
typedef TBoundingBox<Point1d> BoundingBox1d;
typedef TBoundingBox<Point2d> BoundingBox2d;
typedef TBoundingBox<Point3d> BoundingBox3d;
typedef TBoundingBox<Point4d> BoundingBox4d;
typedef TBoundingBox<Point1i> BoundingBox1i;
typedef TBoundingBox<Point2i> BoundingBox2i;
typedef TBoundingBox<Point3i> BoundingBox3i;
typedef TBoundingBox<Point4i> BoundingBox4i;
typedef TRay<Point2f, Vector2f> Ray2f;
typedef TRay<Point3f, Vector3f> Ray3f;
/// Some more forward declarations
class BSDF;
class Bitmap;
class BlockGenerator;
class Camera;
class ImageBlock;
class Integrator;
class KDTree;
class Emitter;
struct EmitterQueryRecord;
class Mesh;
class NoriObject;
class NoriObjectFactory;
class NoriScreen;
class PhaseFunction;
class ReconstructionFilter;
class Sampler;
class Scene;
/// Import cout, cerr, endl for debugging purposes
using std::cout;
using std::cerr;
using std::endl;
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> MatrixXf;
typedef Eigen::Matrix<uint32_t, Eigen::Dynamic, Eigen::Dynamic> MatrixXu;
/// Simple exception class, which stores a human-readable error description
class NoriException : public std::runtime_error {
public:
/// Variadic template constructor to support printf-style arguments
template <typename... Args> NoriException(const char *fmt, const Args &... args)
: std::runtime_error(tfm::format(fmt, args...)) { }
};
/// Return the number of cores (real and virtual)
extern int getCoreCount();
/// Indent a string by the specified number of spaces
extern std::string indent(const std::string &string, int amount = 2);
/// Convert a string to lower case
extern std::string toLower(const std::string &value);
/// Convert a string into an boolean value
extern bool toBool(const std::string &str);
/// Convert a string into a signed integer value
extern int toInt(const std::string &str);
/// Convert a string into an unsigned integer value
extern unsigned int toUInt(const std::string &str);
/// Convert a string into a floating point value
extern float toFloat(const std::string &str);
/// Convert a string into a 3D vector
extern Eigen::Vector3f toVector3f(const std::string &str);
/// Tokenize a string into a list by splitting at 'delim'
extern std::vector<std::string> tokenize(const std::string &s, const std::string &delim = ", ", bool includeEmpty = false);
/// Check if a string ends with another string
extern bool endsWith(const std::string &value, const std::string &ending);
/// Convert a time value in milliseconds into a human-readable string
extern std::string timeString(double time, bool precise = false);
/// Convert a memory amount in bytes into a human-readable string
extern std::string memString(size_t size, bool precise = false);
/// Measures associated with probability distributions
enum EMeasure {
EUnknownMeasure = 0,
ESolidAngle,
EDiscrete
};
//// Convert radians to degrees
inline float radToDeg(float value) { return value * (180.0f / M_PI); }
/// Convert degrees to radians
inline float degToRad(float value) { return value * (M_PI / 180.0f); }
#if !defined(_GNU_SOURCE)
/// Emulate sincosf using sinf() and cosf()
inline void sincosf(float theta, float *_sin, float *_cos) {
*_sin = sinf(theta);
*_cos = cosf(theta);
}
#endif
/// Simple floating point clamping function
inline float clamp(float value, float min, float max) {
if (value < min)
return min;
else if (value > max)
return max;
else return value;
}
/// Simple integer clamping function
inline int clamp(int value, int min, int max) {
if (value < min)
return min;
else if (value > max)
return max;
else return value;
}
/// Linearly interpolate between two values
inline float lerp(float t, float v1, float v2) {
return ((float) 1 - t) * v1 + t * v2;
}
inline float bilerp(float x, float y, float v1, float v2, float v3, float v4) {
return v1*(1.0-x)*(1.0-y)+
v2*(x)*(1.0-y)+
v3*(1.0-x)*(y)+
v4*(x)*(y);
}
/// Always-positive modulo operation
inline int mod(int a, int b) {
int r = a % b;
return (r < 0) ? r+b : r;
}
/// Compute a direction for the given coordinates in spherical coordinates
extern Vector3f sphericalDirection(float theta, float phi);
/// Compute a direction for the given coordinates in spherical coordinates
extern Point2f sphericalCoordinates(const Vector3f &dir);
/**
* \brief Calculates the unpolarized fresnel reflection coefficient for a
* dielectric material. Handles incidence from either side (i.e.
* \code cosThetaI<0 is allowed).
*
* \param cosThetaI
* Cosine of the angle between the normal and the incident ray
* \param extIOR
* Refractive index of the side that contains the surface normal
* \param intIOR
* Refractive index of the interior
*/
extern float fresnel(float cosThetaI, float extIOR, float intIOR);
/**
* \brief Return the global file resolver instance
*
* This class is used to locate resource files (e.g. mesh or
* texture files) referenced by a scene being loaded
*/
extern filesystem::resolver *getFileResolver();
NORI_NAMESPACE_END

View File

@@ -0,0 +1,198 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Discrete probability distribution
*
* This data structure can be used to transform uniformly distributed
* samples to a stored discrete probability distribution.
*
* \ingroup libcore
*/
struct DiscretePDF {
public:
/// Allocate memory for a distribution with the given number of entries
explicit DiscretePDF(size_t nEntries = 0) {
reserve(nEntries);
clear();
}
/// Clear all entries
void clear() {
m_cdf.clear();
m_cdf.push_back(0.0f);
m_normalized = false;
}
/// Reserve memory for a certain number of entries
void reserve(size_t nEntries) {
m_cdf.reserve(nEntries+1);
}
/// Append an entry with the specified discrete probability
void append(float pdfValue) {
m_cdf.push_back(m_cdf[m_cdf.size()-1] + pdfValue);
}
/// Return the number of entries so far
size_t size() const {
return m_cdf.size()-1;
}
/// Access an entry by its index
float operator[](size_t entry) const {
return m_cdf[entry+1] - m_cdf[entry];
}
/// Have the probability densities been normalized?
bool isNormalized() const {
return m_normalized;
}
/**
* \brief Return the original (unnormalized) sum of all PDF entries
*
* This assumes that \ref normalize() has previously been called
*/
float getSum() const {
return m_sum;
}
/**
* \brief Return the normalization factor (i.e. the inverse of \ref getSum())
*
* This assumes that \ref normalize() has previously been called
*/
float getNormalization() const {
return m_normalization;
}
/**
* \brief Normalize the distribution
*
* \return Sum of the (previously unnormalized) entries
*/
float normalize() {
m_sum = m_cdf[m_cdf.size()-1];
if (m_sum > 0) {
m_normalization = 1.0f / m_sum;
for (size_t i=1; i<m_cdf.size(); ++i)
m_cdf[i] *= m_normalization;
m_cdf[m_cdf.size()-1] = 1.0f;
m_normalized = true;
} else {
m_normalization = 0.0f;
}
return m_sum;
}
/**
* \brief %Transform a uniformly distributed sample to the stored distribution
*
* \param[in] sampleValue
* An uniformly distributed sample on [0,1]
* \return
* The discrete index associated with the sample
*/
size_t sample(float sampleValue) const {
std::vector<float>::const_iterator entry =
std::lower_bound(m_cdf.begin(), m_cdf.end(), sampleValue);
size_t index = (size_t) std::max((ptrdiff_t) 0, entry - m_cdf.begin() - 1);
return std::min(index, m_cdf.size()-2);
}
/**
* \brief %Transform a uniformly distributed sample to the stored distribution
*
* \param[in] sampleValue
* An uniformly distributed sample on [0,1]
* \param[out] pdf
* Probability value of the sample
* \return
* The discrete index associated with the sample
*/
size_t sample(float sampleValue, float &pdf) const {
size_t index = sample(sampleValue);
pdf = operator[](index);
return index;
}
/**
* \brief %Transform a uniformly distributed sample to the stored distribution
*
* The original sample is value adjusted so that it can be "reused".
*
* \param[in, out] sampleValue
* An uniformly distributed sample on [0,1]
* \return
* The discrete index associated with the sample
*/
size_t sampleReuse(float &sampleValue) const {
size_t index = sample(sampleValue);
sampleValue = (sampleValue - m_cdf[index])
/ (m_cdf[index + 1] - m_cdf[index]);
return index;
}
/**
* \brief %Transform a uniformly distributed sample.
*
* The original sample is value adjusted so that it can be "reused".
*
* \param[in,out]
* An uniformly distributed sample on [0,1]
* \param[out] pdf
* Probability value of the sample
* \return
* The discrete index associated with the sample
*/
size_t sampleReuse(float &sampleValue, float &pdf) const {
size_t index = sample(sampleValue, pdf);
sampleValue = (sampleValue - m_cdf[index])
/ (m_cdf[index + 1] - m_cdf[index]);
return index;
}
/**
* \brief Turn the underlying distribution into a
* human-readable string format
*/
std::string toString() const {
std::string result = tfm::format("DiscretePDF[sum=%f, "
"normalized=%f, pdf = {", m_sum, m_normalized);
for (size_t i=0; i<m_cdf.size(); ++i) {
result += std::to_string(operator[](i));
if (i != m_cdf.size()-1)
result += ", ";
}
return result + "}]";
}
private:
std::vector<float> m_cdf;
float m_sum, m_normalization;
bool m_normalized;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,71 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
#include <nori/mesh.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Superclass of all emitters
*/
class Emitter : public NoriObject {
public:
//Sample Emitters without Mesh attached
virtual Color3f samplePosition(const Point2f &s, EmitterSample& es) const {return Color3f();};
/**
* \brief Sample the Emiter
*
* \param scene Scene
* \param p position
* \param lp light position
* \param ln light normal
* \param pdf_dir direction of the PDF
* \param sample A uniformly distributed sample on \f$[0,1]^2\f$
*
* \return Color value
*/
virtual Color3f sample(const Scene *scene, EmitterSample& es) const = 0;
/**
* \brief Returns the Color evaluated using the light normal and the light to interection path
*
* \param its light intersection
*/
virtual Color3f eval(const Intersection &its) const = 0;
/**
* \brief Returns the PDF using the light normal and the light to interection path
* \param lti ray
*/
virtual float pdf(const Vector3f &lti) const = 0;
/**
* \brief Return the type of object (i.e. Mesh/Emitter/etc.)
* provided by this instance
* */
EClassType getClassType() const { return EEmitter; }
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,147 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/vector.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Stores a three-dimensional orthonormal coordinate frame
*
* This class is mostly used to quickly convert between different
* cartesian coordinate systems and to efficiently compute certain
* quantities (e.g. \ref cosTheta(), \ref tanTheta, ..).
*/
struct Frame {
Vector3f s, t;
Normal3f n;
/// Default constructor -- performs no initialization!
Frame() { }
/// Given a normal and tangent vectors, construct a new coordinate frame
Frame(const Vector3f &s, const Vector3f &t, const Normal3f &n)
: s(s), t(t), n(n) { }
/// Construct a frame from the given orthonormal vectors
Frame(const Vector3f &x, const Vector3f &y, const Vector3f &z)
: s(x), t(y), n(z) { }
/// Construct a new coordinate frame from a single vector
Frame(const Vector3f &n) : n(n) {
coordinateSystem(n, s, t);
}
/// Convert from world coordinates to local coordinates
Vector3f toLocal(const Vector3f &v) const {
return Vector3f(
v.dot(s), v.dot(t), v.dot(n)
);
}
/// Convert from local coordinates to world coordinates
Vector3f toWorld(const Vector3f &v) const {
return s * v.x() + t * v.y() + n * v.z();
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the cosine of the angle between the normal and v */
static float cosTheta(const Vector3f &v) {
return v.z();
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the sine of the angle between the normal and v */
static float sinTheta(const Vector3f &v) {
float temp = sinTheta2(v);
if (temp <= 0.0f)
return 0.0f;
return std::sqrt(temp);
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the tangent of the angle between the normal and v */
static float tanTheta(const Vector3f &v) {
float temp = 1 - v.z()*v.z();
if (temp <= 0.0f)
return 0.0f;
return std::sqrt(temp) / v.z();
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the squared sine of the angle between the normal and v */
static float sinTheta2(const Vector3f &v) {
return 1.0f - v.z() * v.z();
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the sine of the phi parameter in spherical coordinates */
static float sinPhi(const Vector3f &v) {
float sinTheta = Frame::sinTheta(v);
if (sinTheta == 0.0f)
return 1.0f;
return clamp(v.y() / sinTheta, -1.0f, 1.0f);
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the cosine of the phi parameter in spherical coordinates */
static float cosPhi(const Vector3f &v) {
float sinTheta = Frame::sinTheta(v);
if (sinTheta == 0.0f)
return 1.0f;
return clamp(v.x() / sinTheta, -1.0f, 1.0f);
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the squared sine of the phi parameter in spherical
* coordinates */
static float sinPhi2(const Vector3f &v) {
return clamp(v.y() * v.y() / sinTheta2(v), 0.0f, 1.0f);
}
/** \brief Assuming that the given direction is in the local coordinate
* system, return the squared cosine of the phi parameter in spherical
* coordinates */
static float cosPhi2(const Vector3f &v) {
return clamp(v.x() * v.x() / sinTheta2(v), 0.0f, 1.0f);
}
/// Equality test
bool operator==(const Frame &frame) const {
return frame.s == s && frame.t == t && frame.n == n;
}
/// Inequality test
bool operator!=(const Frame &frame) const {
return !operator==(frame);
}
/// Return a human-readable string summary of this frame
std::string toString() const {
return tfm::format(
"Frame[\n"
" s = %s,\n"
" t = %s,\n"
" n = %s\n"
"]", s.toString(), t.toString(), n.toString());
}
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,38 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
#include <nanogui/screen.h>
NORI_NAMESPACE_BEGIN
class NoriScreen : public nanogui::Screen {
public:
NoriScreen(const ImageBlock &block);
void draw_contents() override;
private:
const ImageBlock &m_block;
nanogui::ref<nanogui::Shader> m_shader;
nanogui::ref<nanogui::Texture> m_texture;
nanogui::ref<nanogui::RenderPass> m_renderPass;
float m_scale = 1.f;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,63 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Abstract integrator (i.e. a rendering technique)
*
* In Nori, the different rendering techniques are collectively referred to as
* integrators, since they perform integration over a high-dimensional
* space. Each integrator represents a specific approach for solving
* the light transport equation---usually favored in certain scenarios, but
* at the same time affected by its own set of intrinsic limitations.
*/
class Integrator : public NoriObject {
public:
/// Release all memory
virtual ~Integrator() { }
/// Perform an (optional) preprocess step
virtual void preprocess(const Scene *scene) { }
/**
* \brief Sample the incident radiance along a ray
*
* \param scene
* A pointer to the underlying scene
* \param sampler
* A pointer to a sample generator
* \param ray
* The ray in question
* \return
* A (usually) unbiased estimate of the radiance in this direction
*/
virtual Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const = 0;
/**
* \brief Return the type of object (i.e. Mesh/BSDF/etc.)
* provided by this instance
* */
EClassType getClassType() const { return EIntegrator; }
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,213 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
#include <nori/frame.h>
#include <nori/bbox.h>
#include <nori/dpdf.h>
NORI_NAMESPACE_BEGIN
struct EmitterSample{
Vector3f o;
Vector3f p;
Vector3f n;
Vector3f dir;
float dist;
float pdf=1.0;
Point2f uv;
EmitterSample(Vector3f& p, Vector3f& n, Vector3f& dir, float dist, float pdf, Point2f& uv):
p(p),n(n),dir(dir),dist(dist),pdf(pdf),uv(uv){};
EmitterSample(){};
};
/**
* \brief Intersection data structure
*
* This data structure records local information about a ray-triangle intersection.
* This includes the position, traveled ray distance, uv coordinates, as well
* as well as two local coordinate frames (one that corresponds to the true
* geometry, and one that is used for shading computations).
*/
struct Intersection {
/// Position of the surface intersection
Point3f p;
/// Unoccluded distance along the ray
float t;
/// Ray WI (input vector)
Vector3f wi;
/// UV coordinates, if any
Point2f uv;
/// Shading frame (based on the shading normal)
Frame shFrame;
/// Geometric frame (based on the true geometry)
Frame geoFrame;
/// Pointer to the associated mesh
const Mesh *mesh;
/// Create an uninitialized intersection record
Intersection() : mesh(nullptr) { }
/// Transform a direction vector into the local shading frame
Vector3f toLocal(const Vector3f &d) const {
return shFrame.toLocal(d);
}
/// Transform a direction vector from local to world coordinates
Vector3f toWorld(const Vector3f &d) const {
return shFrame.toWorld(d);
}
/// Return a human-readable summary of the intersection record
std::string toString() const;
};
/**
* \brief Triangle mesh
*
* This class stores a triangle mesh object and provides numerous functions
* for querying the individual triangles. Subclasses of \c Mesh implement
* the specifics of how to create its contents (e.g. by loading from an
* external file)
*/
class Mesh : public NoriObject {
public:
/// Release all memory
virtual ~Mesh();
/// Initialize internal data structures (called once by the XML parser)
virtual void activate();
/// Return the total number of triangles in this shape
uint32_t getTriangleCount() const { return (uint32_t) m_F.cols(); }
/// Return the total number of vertices in this shape
uint32_t getVertexCount() const { return (uint32_t) m_V.cols(); }
/// Return the surface area of the given triangle
float surfaceArea(uint32_t index) const;
//// Return an axis-aligned bounding box of the entire mesh
const BoundingBox3f &getBoundingBox() const { return m_bbox; }
//// Return an axis-aligned bounding box containing the given triangle
BoundingBox3f getBoundingBox(uint32_t index) const;
//// Return the centroid of the given triangle
Point3f getCentroid(uint32_t index) const;
/** \brief Ray-triangle intersection test
*
* Uses the algorithm by Moeller and Trumbore discussed at
* <tt>http://www.acm.org/jgt/papers/MollerTrumbore97/code.html</tt>.
*
* Note that the test only applies to a single triangle in the mesh.
* An acceleration data structure like \ref BVH is needed to search
* for intersections against many triangles.
*
* \param index
* Index of the triangle that should be intersected
* \param ray
* The ray segment to be used for the intersection query
* \param t
* Upon success, \a t contains the distance from the ray origin to the
* intersection point,
* \param u
* Upon success, \c u will contain the 'U' component of the intersection
* in barycentric coordinates
* \param v
* Upon success, \c v will contain the 'V' component of the intersection
* in barycentric coordinates
* \return
* \c true if an intersection has been detected
*/
bool rayIntersect(uint32_t index, const Ray3f &ray, float &u, float &v, float &t) const;
/*
* \brief Uniform Sampling for a position on the mesh
*
* \param s SamplePoint
* \param es EmitterSample
*/
void samplePosition(const Point2f &s, EmitterSample& es) const;
/// Return a pointer to the vertex positions
const MatrixXf &getVertexPositions() const { return m_V; }
/// Return a pointer to the vertex normals (or \c nullptr if there are none)
const MatrixXf &getVertexNormals() const { return m_N; }
/// Return a pointer to the texture coordinates (or \c nullptr if there are none)
const MatrixXf &getVertexTexCoords() const { return m_UV; }
/// Return a pointer to the triangle vertex index list
const MatrixXu &getIndices() const { return m_F; }
/// Is this mesh an area emitter?
bool isEmitter() const { return m_emitter != nullptr; }
/// Return a pointer to an attached area emitter instance
Emitter *getEmitter() { return m_emitter; }
/// Return a pointer to an attached area emitter instance (const version)
const Emitter *getEmitter() const { return m_emitter; }
/// Return a pointer to the BSDF associated with this mesh
const BSDF *getBSDF() const { return m_bsdf; }
/// Return DPDF Normalization factor
float getDPDFNormalization() const { return m_dpdf->getNormalization(); }
/// Register a child object (e.g. a BSDF) with the mesh
virtual void addChild(NoriObject *child);
/// Return the name of this mesh
const std::string &getName() const { return m_name; }
/// Return a human-readable summary of this instance
std::string toString() const;
/**
* \brief Return the type of object (i.e. Mesh/BSDF/etc.)
* provided by this instance
* */
EClassType getClassType() const { return EMesh; }
protected:
/// Create an empty mesh
Mesh();
protected:
std::string m_name; ///< Identifying name
MatrixXf m_V; ///< Vertex positions
MatrixXf m_N; ///< Vertex normals
MatrixXf m_UV; ///< Vertex texture coordinates
MatrixXu m_F; ///< Faces
BSDF *m_bsdf = nullptr; ///< BSDF of the surface
DiscretePDF *m_dpdf = nullptr; ///< DPDF
Emitter *m_emitter = nullptr; ///< Associated emitter, if any
BoundingBox3f m_bbox; ///< Bounding box of the mesh
float m_surface_total; ///< Surface Total
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,58 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/warp.h>
#include <nori/bitmap.h>
#include <map>
NORI_NAMESPACE_BEGIN
/**
* \brief MIPMAP Class
*/
struct Mipmap {
public:
Mipmap(){};
Mipmap(const std::string &filename);
float get(size_t x, size_t y, size_t size) const;
Color3f getColor(float x, float y) const;
size_t getSize() const {
return m_size;
}
float getPDFF() const {
return m_size*m_size;
}
private:
Bitmap m_img;
size_t m_size;
float* m_mm;
float m_maxv;
std::map<size_t,float*> m_stp;
void fill_mm(size_t size);
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,164 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/proplist.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Base class of all objects
*
* A Nori object represents an instance that is part of
* a scene description, e.g. a scattering model or emitter.
*/
class NoriObject {
public:
enum EClassType {
EScene = 0,
EMesh,
EBSDF,
EPhaseFunction,
EEmitter,
EMedium,
ECamera,
EIntegrator,
ESampler,
ETest,
ETexture,
EReconstructionFilter,
EClassTypeCount
};
/// Virtual destructor
virtual ~NoriObject() { }
/**
* \brief Return the type of object (i.e. Mesh/BSDF/etc.)
* provided by this instance
* */
virtual EClassType getClassType() const = 0;
/**
* \brief Add a child object to the current instance
*
* The default implementation does not support children and
* simply throws an exception
*/
virtual void addChild(NoriObject *child);
/**
* \brief Set the parent object
*
* Subclasses may choose to override this method to be
* notified when they are added to a parent object. The
* default implementation does nothing.
*/
virtual void setParent(NoriObject *parent);
/**
* \brief Perform some action associated with the object
*
* The default implementation throws an exception. Certain objects
* may choose to override it, e.g. to implement initialization,
* testing, or rendering functionality.
*
* This function is called by the XML parser once it has
* constructed an object and added all of its children
* using \ref addChild().
*/
virtual void activate();
/// Return a brief string summary of the instance (for debugging purposes)
virtual std::string toString() const = 0;
/// Turn a class type into a human-readable string
static std::string classTypeName(EClassType type) {
switch (type) {
case EScene: return "scene";
case EMesh: return "mesh";
case EBSDF: return "bsdf";
case EEmitter: return "emitter";
case ECamera: return "camera";
case EIntegrator: return "integrator";
case ESampler: return "sampler";
case ETest: return "test";
default: return "<unknown>";
}
}
};
/**
* \brief Factory for Nori objects
*
* This utility class is part of a mini-RTTI framework and can
* instantiate arbitrary Nori objects by their name.
*/
class NoriObjectFactory {
public:
typedef std::function<NoriObject *(const PropertyList &)> Constructor;
/**
* \brief Register an object constructor with the object factory
*
* This function is called by the macro \ref NORI_REGISTER_CLASS
*
* \param name
* An internal name that is associated with this class. This is the
* 'type' field found in the scene description XML files
*
* \param constr
* A function pointer to an anonymous function that is
* able to call the constructor of the class.
*/
static void registerClass(const std::string &name, const Constructor &constr);
/**
* \brief Construct an instance from the class of the given name
*
* \param name
* An internal name that is associated with this class. This is the
* 'type' field found in the scene description XML files
*
* \param propList
* A list of properties that will be passed to the constructor
* of the class.
*/
static NoriObject *createInstance(const std::string &name,
const PropertyList &propList) {
if (!m_constructors || m_constructors->find(name) == m_constructors->end())
throw NoriException("A constructor for class \"%s\" could not be found!", name);
return (*m_constructors)[name](propList);
}
private:
static std::map<std::string, Constructor> *m_constructors;
};
/// Macro for registering an object constructor with the \ref NoriObjectFactory
#define NORI_REGISTER_CLASS(cls, name) \
cls *cls ##_create(const PropertyList &list) { \
return new cls(list); \
} \
static struct cls ##_{ \
cls ##_() { \
NoriObjectFactory::registerClass(name, cls ##_create); \
} \
} cls ##__NORI_;
NORI_NAMESPACE_END

View File

@@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <nori/mesh.h>
NORI_NAMESPACE_BEGIN
class OctreeNode {
public:
//Constructor for Internal Node
OctreeNode(BoundingBox3f bbox) : m_bbox(bbox) {};
//Constructor for Leaf Node
OctreeNode(BoundingBox3f bbox, std::vector<uint32_t>* triangle_ids) : m_triangle_ids(*triangle_ids), m_bbox(bbox) {};
//Computes the Statistics of the Octree Node
void computeStats(size_t* internal, size_t* leaf, size_t* triangles);
OctreeNode* m_child_nodes[8] = {0}; ///< Child Nodes (Branch)
std::vector<uint32_t> m_triangle_ids; ///< Triangle Ids (Leaf)
BoundingBox3f m_bbox; ///< Bounding Box
private:
};
//Creates a Octree Node
OctreeNode* octreenode_builder(Mesh* mesh, BoundingBox3f bbox, std::vector<uint32_t>* triangle_ids, int depth);
NORI_NAMESPACE_END

View File

@@ -0,0 +1,31 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Load a scene from the specified filename and
* return its root object
*/
extern NoriObject *loadFromXML(const std::string &filename);
NORI_NAMESPACE_END

View File

@@ -0,0 +1,139 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/color.h>
#include <nori/transform.h>
#include <map>
NORI_NAMESPACE_BEGIN
/**
* \brief This is an associative container used to supply the constructors
* of \ref NoriObject subclasses with parameter information.
*/
class PropertyList {
public:
PropertyList() { }
bool contains(const std::string &name) const;
/// Set a boolean property
void setBoolean(const std::string &name, const bool &value);
/// Get a boolean property, and throw an exception if it does not exist
bool getBoolean(const std::string &name) const;
/// Get a boolean property, and use a default value if it does not exist
bool getBoolean(const std::string &name, const bool &defaultValue) const;
/// Set an integer property
void setInteger(const std::string &name, const int &value);
/// Get an integer property, and throw an exception if it does not exist
int getInteger(const std::string &name) const;
/// Get am integer property, and use a default value if it does not exist
int getInteger(const std::string &name, const int &defaultValue) const;
/// Set a float property
void setFloat(const std::string &name, const float &value);
/// Get a float property, and throw an exception if it does not exist
float getFloat(const std::string &name) const;
/// Get a float property, and use a default value if it does not exist
float getFloat(const std::string &name, const float &defaultValue) const;
/// Set a string property
void setString(const std::string &name, const std::string &value);
/// Get a string property, and throw an exception if it does not exist
std::string getString(const std::string &name) const;
/// Get a string property, and use a default value if it does not exist
std::string getString(const std::string &name, const std::string &defaultValue) const;
/// Set a color property
void setColor(const std::string &name, const Color3f &value);
/// Get a color property, and throw an exception if it does not exist
Color3f getColor(const std::string &name) const;
/// Get a color property, and use a default value if it does not exist
Color3f getColor(const std::string &name, const Color3f &defaultValue) const;
/// Set a point property
void setPoint(const std::string &name, const Point3f &value);
/// Get a point property, and throw an exception if it does not exist
Point3f getPoint(const std::string &name) const;
/// Get a point property, and use a default value if it does not exist
Point3f getPoint(const std::string &name, const Point3f &defaultValue) const;
/// Set a vector property
void setVector(const std::string &name, const Vector3f &value);
/// Get a vector property, and throw an exception if it does not exist
Vector3f getVector(const std::string &name) const;
/// Get a vector property, and use a default value if it does not exist
Vector3f getVector(const std::string &name, const Vector3f &defaultValue) const;
/// Set a transform property
void setTransform(const std::string &name, const Transform &value);
/// Get a transform property, and throw an exception if it does not exist
Transform getTransform(const std::string &name) const;
/// Get a transform property, and use a default value if it does not exist
Transform getTransform(const std::string &name, const Transform &defaultValue) const;
private:
/* Custom variant data type (stores one of boolean/integer/float/...) */
struct Property {
enum {
boolean_type, integer_type, float_type,
string_type, color_type, point_type,
vector_type, transform_type
} type;
/* Visual studio lacks support for unrestricted unions (as of ver. 2013) */
struct Value
{
Value() : boolean_value(false) { }
~Value() { }
bool boolean_value;
int integer_value;
float float_value;
std::string string_value;
Color3f color_value;
Point3f point_value;
Vector3f vector_value;
Transform transform_value;
} value;
Property() : type(boolean_type) { }
};
std::map<std::string, Property> m_properties;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,101 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/vector.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Simple n-dimensional ray segment data structure
*
* Along with the ray origin and direction, this data structure additionally
* stores a ray segment [mint, maxt] (whose entries may include positive/negative
* infinity), as well as the componentwise reciprocals of the ray direction.
* That is just done for convenience, as these values are frequently required.
*
* \remark Important: be careful when changing the ray direction. You must
* call \ref update() to compute the componentwise reciprocals as well, or Nori's
* ray-triangle intersection code will go haywire.
*/
template <typename _PointType, typename _VectorType> struct TRay {
typedef _PointType PointType;
typedef _VectorType VectorType;
typedef typename PointType::Scalar Scalar;
PointType o; ///< Ray origin
VectorType d; ///< Ray direction
VectorType dRcp; ///< Componentwise reciprocals of the ray direction
Scalar mint; ///< Minimum position on the ray segment
Scalar maxt; ///< Maximum position on the ray segment
/// Construct a new ray
TRay() : mint(Epsilon),
maxt(std::numeric_limits<Scalar>::infinity()) { }
/// Construct a new ray
TRay(const PointType &o, const VectorType &d) : o(o), d(d),
mint(Epsilon), maxt(std::numeric_limits<Scalar>::infinity()) {
update();
}
/// Construct a new ray
TRay(const PointType &o, const VectorType &d,
Scalar mint, Scalar maxt) : o(o), d(d), mint(mint), maxt(maxt) {
update();
}
/// Copy constructor
TRay(const TRay &ray)
: o(ray.o), d(ray.d), dRcp(ray.dRcp),
mint(ray.mint), maxt(ray.maxt) { }
/// Copy a ray, but change the covered segment of the copy
TRay(const TRay &ray, Scalar mint, Scalar maxt)
: o(ray.o), d(ray.d), dRcp(ray.dRcp), mint(mint), maxt(maxt) { }
/// Update the reciprocal ray directions after changing 'd'
void update() {
dRcp = d.cwiseInverse();
}
/// Return the position of a point along the ray
PointType operator() (Scalar t) const { return o + t * d; }
/// Return a ray that points into the opposite direction
TRay reverse() const {
TRay result;
result.o = o; result.d = -d; result.dRcp = -dRcp;
result.mint = mint; result.maxt = maxt;
return result;
}
/// Return a human-readable string summary of this ray
std::string toString() const {
return tfm::format(
"Ray[\n"
" o = %s,\n"
" d = %s,\n"
" mint = %f,\n"
" maxt = %f\n"
"]", o.toString(), d.toString(), mint, maxt);
}
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,57 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
/// Reconstruction filters will be tabulated at this resolution
#define NORI_FILTER_RESOLUTION 32
NORI_NAMESPACE_BEGIN
/**
* \brief Generic radially symmetric image reconstruction filter
*
* When adding radiance-valued samples to the rendered image, Nori
* first convolves them with a so-called image reconstruction filter.
*
* To learn more about reconstruction filters and sampling theory
* in general, take a look at the excellenent chapter 7 of PBRT,
* which is freely available at:
*
* http://graphics.stanford.edu/~mmp/chapters/pbrt_chapter7.pdf
*/
class ReconstructionFilter : public NoriObject {
public:
/// Return the filter radius in fractional pixels
float getRadius() const { return m_radius; }
/// Evaluate the filter function
virtual float eval(float x) const = 0;
/**
* \brief Return the type of object (i.e. Mesh/Camera/etc.)
* provided by this instance
* */
EClassType getClassType() const { return EReconstructionFilter; }
protected:
float m_radius;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,109 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/object.h>
#include <memory>
NORI_NAMESPACE_BEGIN
class ImageBlock;
/**
* \brief Abstract sample generator
*
* A sample generator is responsible for generating the random number stream
* that will be passed an \ref Integrator implementation as it computes the
* radiance incident along a specified ray.
*
* The most simple conceivable sample generator is just a wrapper around the
* Mersenne-Twister random number generator and is implemented in
* <tt>independent.cpp</tt> (it is named this way because it generates
* statistically independent random numbers).
*
* Fancier samplers might use stratification or low-discrepancy sequences
* (e.g. Halton, Hammersley, or Sobol point sets) for improved convergence.
* Another use of this class is in producing intentionally correlated
* random numbers, e.g. as part of a Metropolis-Hastings integration scheme.
*
* The general interface between a sampler and a rendering algorithm is as
* follows: Before beginning to render a pixel, the rendering algorithm calls
* \ref generate(). The first pixel sample can now be computed, after which
* \ref advance() needs to be invoked. This repeats until all pixel samples have
* been exhausted. While computing a pixel sample, the rendering
* algorithm requests (pseudo-) random numbers using the \ref next1D() and
* \ref next2D() functions.
*
* Conceptually, the right way of thinking of this goes as follows:
* For each sample in a pixel, a sample generator produces a (hypothetical)
* point in an infinite dimensional random number hypercube. A rendering
* algorithm can then request subsequent 1D or 2D components of this point
* using the \ref next1D() and \ref next2D() functions. Fancy implementations
* of this class make certain guarantees about the stratification of the
* first n components with respect to the other points that are sampled
* within a pixel.
*/
class Sampler : public NoriObject {
public:
/// Release all memory
virtual ~Sampler() { }
/// Create an exact clone of the current instance
virtual std::unique_ptr<Sampler> clone() const = 0;
/**
* \brief Prepare to render a new image block
*
* This function is called when the sampler begins rendering
* a new image block. This can be used to deterministically
* initialize the sampler so that repeated program runs
* always create the same image.
*/
virtual void prepare(const ImageBlock &block) = 0;
/**
* \brief Prepare to generate new samples
*
* This function is called initially and every time the
* integrator starts rendering a new pixel.
*/
virtual void generate() = 0;
/// Advance to the next sample
virtual void advance() = 0;
/// Retrieve the next component value from the current sample
virtual float next1D() = 0;
/// Retrieve the next two component values from the current sample
virtual Point2f next2D() = 0;
/// Return the number of configured pixel samples
virtual size_t getSampleCount() const { return m_sampleCount; }
/**
* \brief Return the type of object (i.e. Mesh/Sampler/etc.)
* provided by this instance
* */
EClassType getClassType() const { return ESampler; }
protected:
size_t m_sampleCount;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,144 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/accel.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Main scene data structure
*
* This class holds information on scene objects and is responsible for
* coordinating rendering jobs. It also provides useful query routines that
* are mostly used by the \ref Integrator implementations.
*/
class Scene : public NoriObject {
public:
/// Construct a new scene object
Scene(const PropertyList &);
/// Release all memory
virtual ~Scene();
/// Return a pointer to the scene's kd-tree
const Accel *getAccel() const { return m_accel; }
/// Return a pointer to the scene's integrator
const Integrator *getIntegrator() const { return m_integrator; }
/// Return a pointer to the scene's integrator
Integrator *getIntegrator() { return m_integrator; }
/// Return a pointer to the scene's camera
const Camera *getCamera() const { return m_camera; }
/// Return a pointer to the scene's sample generator (const version)
const Sampler *getSampler() const { return m_sampler; }
/// Return a pointer to the scene's sample generator
Sampler *getSampler() { return m_sampler; }
/// Return a reference to an array containing all meshes
const std::vector<Mesh *> &getMeshes() const { return m_meshes; }
/**
* \brief Intersect a ray against all triangles stored in the scene
* and return detailed intersection information
*
* \param ray
* A 3-dimensional ray data structure with minimum/maximum
* extent information
*
* \param its
* A detailed intersection record, which will be filled by the
* intersection query
*
* \return \c true if an intersection was found
*/
bool rayIntersect(const Ray3f &ray, Intersection &its) const {
return m_accel->rayIntersect(ray, its, false);
}
/**
* \brief Intersect a ray against all triangles stored in the scene
* and \a only determine whether or not there is an intersection.
*
* This method much faster than the other ray tracing function,
* but the performance comes at the cost of not providing any
* additional information about the detected intersection
* (not even its position).
*
* \param ray
* A 3-dimensional ray data structure with minimum/maximum
* extent information
*
* \return \c true if an intersection was found
*/
bool rayIntersect(const Ray3f &ray) const {
Intersection its; /* Unused */
return m_accel->rayIntersect(ray, its, true);
}
/// \brief Return an axis-aligned box that bounds the scene
const BoundingBox3f &getBoundingBox() const {
return m_accel->getBoundingBox();
}
const std::pair<Emitter*,Mesh*> getRandomEmitter(float rnd) const {
if(m_emp.size() <=0) return std::pair<Emitter*,Mesh*>(nullptr,nullptr);
auto const & n = m_emp.size();
size_t index = std::min(static_cast<size_t>(std::floor(n*rnd)),n-1);
return m_emp[index];
}
float getEmitterPDF() const {
if(m_emp.size() <=0) return 0.0;
return 1.0/m_emp.size();
}
const Emitter* getEmitterEnv() const {
return m_emenv;
}
/**
* \brief Inherited from \ref NoriObject::activate()
*
* Initializes the internal data structures (kd-tree,
* emitter sampling data structures, etc.)
*/
void activate();
/// Add a child object to the scene (meshes, integrators etc.)
void addChild(NoriObject *obj);
/// Return a string summary of the scene (for debugging purposes)
std::string toString() const;
EClassType getClassType() const { return EScene; }
private:
std::vector<Mesh *> m_meshes;
std::vector<std::pair<Emitter*,Mesh*>> m_emp;
Emitter* m_emenv = nullptr;
Integrator *m_integrator = nullptr;
Sampler *m_sampler = nullptr;
Camera *m_camera = nullptr;
Accel *m_accel = nullptr;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,14 @@
#pragma once
#include <nori/object.h>
NORI_NAMESPACE_BEGIN
class Texture : public NoriObject {
public:
virtual Color3f eval(const Point2f & uv) { return Color3f(); };
EClassType getClassType() const { return ETexture; }
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,67 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
#include <chrono>
NORI_NAMESPACE_BEGIN
/**
* \brief Simple timer with millisecond precision
*
* This class is convenient for collecting performance data
*/
class Timer {
public:
/// Create a new timer and reset it
Timer() { reset(); }
/// Reset the timer to the current time
void reset() { start = std::chrono::system_clock::now(); }
/// Return the number of milliseconds elapsed since the timer was last reset
double elapsed() const {
auto now = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
return (double) duration.count();
}
/// Like \ref elapsed(), but return a human-readable string
std::string elapsedString(bool precise = false) const {
return timeString(elapsed(), precise);
}
/// Return the number of milliseconds elapsed since the timer was last reset and then reset it
double lap() {
auto now = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
start = now;
return (double) duration.count();
}
/// Like \ref lap(), but return a human-readable string
std::string lapString(bool precise = false) {
return timeString(lap(), precise);
}
private:
std::chrono::system_clock::time_point start;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,98 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
#include <nori/ray.h>
NORI_NAMESPACE_BEGIN
/**
* \brief Homogeneous coordinate transformation
*
* This class stores a general homogeneous coordinate tranformation, such as
* rotation, translation, uniform or non-uniform scaling, and perspective
* transformations. The inverse of this transformation is also recorded
* here, since it is required when transforming normal vectors.
*/
struct Transform {
public:
/// Create the identity transform
Transform() :
m_transform(Eigen::Matrix4f::Identity()),
m_inverse(Eigen::Matrix4f::Identity()) { }
/// Create a new transform instance for the given matrix
Transform(const Eigen::Matrix4f &trafo);
/// Create a new transform instance for the given matrix and its inverse
Transform(const Eigen::Matrix4f &trafo, const Eigen::Matrix4f &inv)
: m_transform(trafo), m_inverse(inv) { }
/// Return the underlying matrix
const Eigen::Matrix4f &getMatrix() const {
return m_transform;
}
/// Return the inverse of the underlying matrix
const Eigen::Matrix4f &getInverseMatrix() const {
return m_inverse;
}
/// Return the inverse transformation
Transform inverse() const {
return Transform(m_inverse, m_transform);
}
/// Concatenate with another transform
Transform operator*(const Transform &t) const;
/// Apply the homogeneous transformation to a 3D vector
Vector3f operator*(const Vector3f &v) const {
return m_transform.topLeftCorner<3,3>() * v;
}
/// Apply the homogeneous transformation to a 3D normal
Normal3f operator*(const Normal3f &n) const {
return m_inverse.topLeftCorner<3, 3>().transpose() * n;
}
/// Transform a point by an arbitrary matrix in homogeneous coordinates
Point3f operator*(const Point3f &p) const {
Vector4f result = m_transform * Vector4f(p[0], p[1], p[2], 1.0f);
return result.head<3>() / result.w();
}
/// Apply the homogeneous transformation to a ray
Ray3f operator*(const Ray3f &r) const {
return Ray3f(
operator*(r.o),
operator*(r.d),
r.mint, r.maxt
);
}
/// Return a string representation
std::string toString() const;
private:
Eigen::Matrix4f m_transform;
Eigen::Matrix4f m_inverse;
};
NORI_NAMESPACE_END

View File

@@ -0,0 +1,169 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
NORI_NAMESPACE_BEGIN
/* ===================================================================
This file contains a few templates and specializations, which
provide 2/3D points, vectors, and normals over different
underlying data types. Points, vectors, and normals are distinct
in Nori, because they transform differently under homogeneous
coordinate transformations.
* =================================================================== */
/**
* \brief Generic N-dimensional vector data structure based on Eigen::Matrix
*/
template <typename _Scalar, int _Dimension> struct TVector : public Eigen::Matrix<_Scalar, _Dimension, 1> {
public:
enum {
Dimension = _Dimension
};
typedef _Scalar Scalar;
typedef Eigen::Matrix<Scalar, Dimension, 1> Base;
typedef TVector<Scalar, Dimension> VectorType;
typedef TPoint<Scalar, Dimension> PointType;
/// Create a new vector with constant component vlaues
TVector(Scalar value = (Scalar) 0) { Base::setConstant(value); }
/// Create a new 2D vector (type error if \c Dimension != 2)
TVector(Scalar x, Scalar y) : Base(x, y) { }
/// Create a new 3D vector (type error if \c Dimension != 3)
TVector(Scalar x, Scalar y, Scalar z) : Base(x, y, z) { }
/// Create a new 4D vector (type error if \c Dimension != 4)
TVector(Scalar x, Scalar y, Scalar z, Scalar w) : Base(x, y, z, w) { }
/// Construct a vector from MatrixBase (needed to play nice with Eigen)
template <typename Derived> TVector(const Eigen::MatrixBase<Derived>& p)
: Base(p) { }
/// Assign a vector from MatrixBase (needed to play nice with Eigen)
template <typename Derived> TVector &operator=(const Eigen::MatrixBase<Derived>& p) {
this->Base::operator=(p);
return *this;
}
/// Return a human-readable string summary
std::string toString() const {
std::string result;
for (size_t i=0; i<Dimension; ++i) {
result += std::to_string(this->coeff(i));
if (i+1 < Dimension)
result += ", ";
}
return "[" + result + "]";
}
};
/**
* \brief Generic N-dimensional point data structure based on Eigen::Matrix
*/
template <typename _Scalar, int _Dimension> struct TPoint : public Eigen::Matrix<_Scalar, _Dimension, 1> {
public:
enum {
Dimension = _Dimension
};
typedef _Scalar Scalar;
typedef Eigen::Matrix<Scalar, Dimension, 1> Base;
typedef TVector<Scalar, Dimension> VectorType;
typedef TPoint<Scalar, Dimension> PointType;
/// Create a new point with constant component vlaues
TPoint(Scalar value = (Scalar) 0) { Base::setConstant(value); }
/// Create a new 2D point (type error if \c Dimension != 2)
TPoint(Scalar x, Scalar y) : Base(x, y) { }
/// Create a new 3D point (type error if \c Dimension != 3)
TPoint(Scalar x, Scalar y, Scalar z) : Base(x, y, z) { }
/// Create a new 4D point (type error if \c Dimension != 4)
TPoint(Scalar x, Scalar y, Scalar z, Scalar w) : Base(x, y, z, w) { }
/// Construct a point from MatrixBase (needed to play nice with Eigen)
template <typename Derived> TPoint(const Eigen::MatrixBase<Derived>& p)
: Base(p) { }
/// Assign a point from MatrixBase (needed to play nice with Eigen)
template <typename Derived> TPoint &operator=(const Eigen::MatrixBase<Derived>& p) {
this->Base::operator=(p);
return *this;
}
/// Return a human-readable string summary
std::string toString() const {
std::string result;
for (size_t i=0; i<Dimension; ++i) {
result += std::to_string(this->coeff(i));
if (i+1 < Dimension)
result += ", ";
}
return "[" + result + "]";
}
};
/**
* \brief 3-dimensional surface normal representation
*/
struct Normal3f : public Eigen::Matrix<float, 3, 1> {
public:
enum {
Dimension = 3
};
typedef float Scalar;
typedef Eigen::Matrix<Scalar, Dimension, 1> Base;
typedef TVector<Scalar, Dimension> VectorType;
typedef TPoint<Scalar, Dimension> PointType;
/// Create a new normal with constant component vlaues
Normal3f(Scalar value = 0.0f) { Base::setConstant(value); }
/// Create a new 3D normal
Normal3f(Scalar x, Scalar y, Scalar z) : Base(x, y, z) { }
/// Construct a normal from MatrixBase (needed to play nice with Eigen)
template <typename Derived> Normal3f(const Eigen::MatrixBase<Derived>& p)
: Base(p) { }
/// Assign a normal from MatrixBase (needed to play nice with Eigen)
template <typename Derived> Normal3f &operator=(const Eigen::MatrixBase<Derived>& p) {
this->Base::operator=(p);
return *this;
}
/// Return a human-readable string summary
std::string toString() const {
return tfm::format("[%f, %f, %f]", coeff(0), coeff(1), coeff(2));
}
};
/// Complete the set {a} to an orthonormal base
extern void coordinateSystem(const Vector3f &a, Vector3f &b, Vector3f &c);
NORI_NAMESPACE_END

View File

@@ -0,0 +1,87 @@
/*
This file is part of Nori, a simple educational ray tracer
Copyright (c) 2015 by Wenzel Jakob
Nori is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Nori is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <nori/common.h>
#include <nori/mipmap.h>
#include <nori/sampler.h>
NORI_NAMESPACE_BEGIN
/// A collection of useful warping functions for importance sampling
class Warp {
public:
/// Dummy warping function: takes uniformly distributed points in a square and just returns them
static Point2f squareToUniformSquare(const Point2f &sample);
/// Probability density of \ref squareToUniformSquare()
static float squareToUniformSquarePdf(const Point2f &p);
/// Sample a 2D tent distribution
static Point2f squareToTent(const Point2f &sample);
/// Probability density of \ref squareToTent()
static float squareToTentPdf(const Point2f &p);
/// Uniformly sample a vector on a 2D disk with radius 1, centered around the origin
static Point2f squareToUniformDisk(const Point2f &sample);
/// Probability density of \ref squareToUniformDisk()
static float squareToUniformDiskPdf(const Point2f &p);
/// Uniformly sample a vector on the unit sphere with respect to solid angles
static Vector3f squareToUniformSphere(const Point2f &sample);
/// Probability density of \ref squareToUniformSphere()
static float squareToUniformSpherePdf(const Vector3f &v);
/// Uniformly sample a vector on the unit hemisphere around the pole (0,0,1) with respect to solid angles
static Vector3f squareToUniformHemisphere(const Point2f &sample);
/// Probability density of \ref squareToUniformHemisphere()
static float squareToUniformHemispherePdf(const Vector3f &v);
/// Uniformly sample a vector on the unit hemisphere around the pole (0,0,1) with respect to projected solid angles
static Vector3f squareToCosineHemisphere(const Point2f &sample);
/// Probability density of \ref squareToCosineHemisphere()
static float squareToCosineHemispherePdf(const Vector3f &v);
/// Warp a uniformly distributed square sample to a Beckmann distribution * cosine for the given 'alpha' parameter
static Vector3f squareToBeckmann(const Point2f &sample, float alpha);
/// Probability density of \ref squareToBeckmann()
static float squareToBeckmannPdf(const Vector3f &m, float alpha);
/// Warp a uniformly distributed square sample using Hierarchical Sample Warping
static Point2f squareToHSW(const Point2f &sample, const Mipmap &mm);
/// Probability density of \ref squareToHSW()
static float squareToHSWPdf(const Point2f &m, const Mipmap &mm);
static Vector3f squareToGTR1(const Point2f & sample, float a);
static float squareToGTR1Pdf(const Vector3f & m, float a);
static Vector3f squareToGTR2(const Point2f & sample, float a);
static float squareToGTR2Pdf(const Vector3f & m, float a);
};
NORI_NAMESPACE_END