mitsuba/include/mitsuba/core/transform.h

319 lines
11 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba 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.
Mitsuba 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(__TRANSFORM_H)
#define __TRANSFORM_H
#include <mitsuba/core/matrix.h>
#include <mitsuba/core/ray.h>
MTS_NAMESPACE_BEGIN
/**
* \brief Encapsulates a 4x4 linear transformation and its inverse
* \ingroup libcore
*/
struct MTS_EXPORT_CORE Transform {
public:
/// Create an identity transformation
Transform() {
m_transform.setIdentity();
m_invTransform.setIdentity();
}
/// Unserialize a transformation from a stream
inline Transform(Stream *stream) {
m_transform = Matrix4x4(stream);
m_invTransform = Matrix4x4(stream);
}
/** \brief Create a transform from the given matrix
* and calculate the inverse
*/
Transform(const Matrix4x4 &trafo)
: m_transform(trafo) {
bool success = m_transform.invert(m_invTransform);
if (!success)
SLog(EError, "Unable to invert singular matrix %s", trafo.toString().c_str());
}
/// Create a transform from the given matrices
Transform(const Matrix4x4 &trafo, const Matrix4x4 &invTrafo)
: m_transform(trafo), m_invTransform(invTrafo) {
}
/// Return the inverse transform
Transform inverse() const {
return Transform(m_invTransform, m_transform);
}
/// Matrix-matrix multiplication
Transform operator*(const Transform &t) const;
/// Return the determinant of the upper left 3x3 submatrix
inline Float det3x3() const {
return m_transform.det3x3();
}
/// Test for a scale component
inline bool hasScale() const {
for (int i=0; i<3; ++i) {
for (int j=i; j<3; ++j) {
Float sum = 0;
for (int k=0; k<3; ++k)
sum += m_transform.m[i][k] * m_transform.m[j][k];
if (i == j && std::abs(sum-1) > 1e-3f)
return true;
else if (i != j && std::abs(sum) > 1e-3f)
return true;
}
}
return false;
}
/// Test if this is the identity matrix
inline bool isIdentity() const {
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
if (m_transform.m[i][j] != ((i==j) ? 1 : 0))
return false;
}
}
return true;
}
/// Matrix-vector multiplication for points in 3d space
inline Point operator()(const Point &p) const {
Float x = m_transform.m[0][0] * p.x + m_transform.m[0][1] * p.y
+ m_transform.m[0][2] * p.z + m_transform.m[0][3];
Float y = m_transform.m[1][0] * p.x + m_transform.m[1][1] * p.y
+ m_transform.m[1][2] * p.z + m_transform.m[1][3];
Float z = m_transform.m[2][0] * p.x + m_transform.m[2][1] * p.y
+ m_transform.m[2][2] * p.z + m_transform.m[2][3];
Float w = m_transform.m[3][0] * p.x + m_transform.m[3][1] * p.y
+ m_transform.m[3][2] * p.z + m_transform.m[3][3];
#ifdef MTS_DEBUG
if (w == 0)
SLog(EWarn, "w==0 in Transform::operator(Point &)");
#endif
if (w == 1.0f)
return Point(x, y, z);
else
return Point(x, y, z) / w;
}
/// Transform a point by a affine / non-projective matrix
inline Point transformAffine(const Point &p) const {
Float x = m_transform.m[0][0] * p.x + m_transform.m[0][1] * p.y
+ m_transform.m[0][2] * p.z + m_transform.m[0][3];
Float y = m_transform.m[1][0] * p.x + m_transform.m[1][1] * p.y
+ m_transform.m[1][2] * p.z + m_transform.m[1][3];
Float z = m_transform.m[2][0] * p.x + m_transform.m[2][1] * p.y
+ m_transform.m[2][2] * p.z + m_transform.m[2][3];
return Point(x,y,z);
}
/// Matrix-vector multiplication for points in 3d space (no temporaries)
inline void operator()(const Point &p, Point &dest) const {
dest.x = m_transform.m[0][0] * p.x + m_transform.m[0][1] * p.y
+ m_transform.m[0][2] * p.z + m_transform.m[0][3];
dest.y = m_transform.m[1][0] * p.x + m_transform.m[1][1] * p.y
+ m_transform.m[1][2] * p.z + m_transform.m[1][3];
dest.z = m_transform.m[2][0] * p.x + m_transform.m[2][1] * p.y
+ m_transform.m[2][2] * p.z + m_transform.m[2][3];
Float w = m_transform.m[3][0] * p.x + m_transform.m[3][1] * p.y
+ m_transform.m[3][2] * p.z + m_transform.m[3][3];
#ifdef MTS_DEBUG
if (w == 0)
SLog(EWarn, "w==0 in Transform::operator(Point &, Point &)");
#endif
if (w != 1.0f)
dest /= w;
}
/// Matrix-vector multiplication for vectors in 3d space
inline Vector operator()(const Vector &v) const {
Float x = m_transform.m[0][0] * v.x + m_transform.m[0][1] * v.y
+ m_transform.m[0][2] * v.z;
Float y = m_transform.m[1][0] * v.x + m_transform.m[1][1] * v.y
+ m_transform.m[1][2] * v.z;
Float z = m_transform.m[2][0] * v.x + m_transform.m[2][1] * v.y
+ m_transform.m[2][2] * v.z;
return Vector(x, y, z);
}
/// Matrix-vector multiplication for vectors in 3d space (no temporaries)
inline void operator()(const Vector &v, Vector &dest) const {
dest.x = m_transform.m[0][0] * v.x + m_transform.m[0][1] * v.y
+ m_transform.m[0][2] * v.z;
dest.y = m_transform.m[1][0] * v.x + m_transform.m[1][1] * v.y
+ m_transform.m[1][2] * v.z;
dest.z = m_transform.m[2][0] * v.x + m_transform.m[2][1] * v.y
+ m_transform.m[2][2] * v.z;
}
/// Matrix-normal multiplication
inline Normal operator()(const Normal &v) const {
Float x = m_invTransform.m[0][0] * v.x + m_invTransform.m[1][0] * v.y
+ m_invTransform.m[2][0] * v.z;
Float y = m_invTransform.m[0][1] * v.x + m_invTransform.m[1][1] * v.y
+ m_invTransform.m[2][1] * v.z;
Float z = m_invTransform.m[0][2] * v.x + m_invTransform.m[1][2] * v.y
+ m_invTransform.m[2][2] * v.z;
return Normal(x, y, z);
}
/// Matrix-normal multiplication (no temporaries)
inline void operator()(const Normal &v, Normal &dest) const {
dest.x = m_invTransform.m[0][0] * v.x + m_invTransform.m[1][0] * v.y
+ m_invTransform.m[2][0] * v.z;
dest.y = m_invTransform.m[0][1] * v.x + m_invTransform.m[1][1] * v.y
+ m_invTransform.m[2][1] * v.z;
dest.z = m_invTransform.m[0][2] * v.x + m_invTransform.m[1][2] * v.y
+ m_invTransform.m[2][2] * v.z;
}
/// 4D matrix-vector multiplication
inline Vector4 operator()(const Vector4 &v) const {
Float x = m_transform.m[0][0] * v.x + m_transform.m[0][1] * v.y
+ m_transform.m[0][2] * v.z + m_transform.m[0][3] * v.w;
Float y = m_transform.m[1][0] * v.x + m_transform.m[1][1] * v.y
+ m_transform.m[1][2] * v.z + m_transform.m[1][3] * v.w;
Float z = m_transform.m[2][0] * v.x + m_transform.m[2][1] * v.y
+ m_transform.m[2][2] * v.z + m_transform.m[2][3] * v.w;
Float w = m_transform.m[3][0] * v.x + m_transform.m[3][1] * v.y
+ m_transform.m[3][2] * v.z + m_transform.m[3][3] * v.w;
return Vector4(x,y,z,w);
}
/// 4D matrix-vector multiplication
inline void operator()(const Vector4 &v, Vector4 &dest) const {
dest.x = m_transform.m[0][0] * v.x + m_transform.m[0][1] * v.y
+ m_transform.m[0][2] * v.z + m_transform.m[0][3] * v.w;
dest.y = m_transform.m[1][0] * v.x + m_transform.m[1][1] * v.y
+ m_transform.m[1][2] * v.z + m_transform.m[1][3] * v.w;
dest.z = m_transform.m[2][0] * v.x + m_transform.m[2][1] * v.y
+ m_transform.m[2][2] * v.z + m_transform.m[2][3] * v.w;
dest.w = m_transform.m[3][0] * v.x + m_transform.m[3][1] * v.y
+ m_transform.m[3][2] * v.z + m_transform.m[3][3] * v.w;
}
/// Transform a ray. Assumes that there is no scaling
inline void operator()(const Ray &a, Ray &b) const {
b.mint = a.mint;
b.maxt = a.maxt;
operator()(a.o, b.o);
operator()(a.d, b.d);
#ifdef MTS_DEBUG_FP
bool state = disableFPExceptions();
#endif
/* Re-compute the reciprocal */
b.dRcp.x = 1.0f / b.d.x;
b.dRcp.y = 1.0f / b.d.y;
b.dRcp.z = 1.0f / b.d.z;
b.time = a.time;
#ifdef MTS_DEBUG_FP
restoreFPExceptions(state);
#endif
}
/// Return the underlying matrix
inline const Matrix4x4 &getMatrix() const { return m_transform; }
/// Return the underlying inverse matrix (const version)
inline const Matrix4x4 &getInverseMatrix() const { return m_invTransform; }
/// Create a translation transformation
static Transform translate(const Vector &v);
/// Create a rotation transformation around an arbitrary axis. The angle is specified in degrees
static Transform rotate(const Vector &axis, Float angle);
/// Create a scale transformation
static Transform scale(const Vector &v);
/** \brief Create a perspective transformation.
* (Maps [near, far] to [0, 1])
* \param fov Field of view in degrees
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform perspective(Float fov, Float clipNear, Float clipFar);
/** \brief Create a perspective transformation for OpenGL.
* (Maps [near, far] to [-1, 1])
* \param fov Field of view in degrees
* \param clipNear Near clipping plane distance
* \param clipFar Far clipping plane distance
*/
static Transform glPerspective(Float fov, Float clipNear, Float clipFar);
/** \brief Create a perspective transformation for OpenGL.
* \param left Left clipping plane coordinate
* \param right Right clipping plane coordinate
* \param top Top clipping plane coordinate
* \param bottom Bottom clipping plane coordinate
* \param nearVal Near clipping plane distance
* \param farVal Far clipping plane distance
*/
static Transform glFrustum(Float left, Float right, Float bottom, Float top, Float nearVal, Float farVal);
/** \brief Create an orthographic transformation, which maps Z to [0,1]
* and leaves the X and Y coordinates untouched.
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform orthographic(Float clipNear, Float clipFar);
/** \brief Create an orthographic transformation for OpenGL
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform glOrthographic(Float clipNear, Float clipFar);
/** \brief Create a look-at camera transformation
* \param p Camera position
* \param t Target vector
* \param u Up vector
*/
static Transform lookAt(const Point &p, const Point &t, const Vector &u);
/** \brief Create an orthogonal transformation that takes
* the standard to the supplied frame
*/
static Transform fromFrame(const Frame &frame);
/// Serialize a transformation to a stream
inline void serialize(Stream *stream) const {
m_transform.serialize(stream);
m_invTransform.serialize(stream);
}
/// Return a string representation
std::string toString() const;
private:
Matrix4x4 m_transform;
Matrix4x4 m_invTransform;
};
MTS_NAMESPACE_END
#endif /* __TRANSFORM_H */