some work towards animated transformation support
parent
3885a4c6f9
commit
544080e808
|
@ -6,7 +6,7 @@ CCFLAGS = ['-arch', 'x86_64', '-mmacosx-version-min=10.7', '-march=nocona
|
||||||
LINKFLAGS = ['-framework', 'OpenGL', '-framework', 'Cocoa', '-arch', 'x86_64', '-mmacosx-version-min=10.7', '-Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk', '-Wl,-headerpad,128']
|
LINKFLAGS = ['-framework', 'OpenGL', '-framework', 'Cocoa', '-arch', 'x86_64', '-mmacosx-version-min=10.7', '-Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk', '-Wl,-headerpad,128']
|
||||||
BASEINCLUDE = ['#include', '#dependencies/include']
|
BASEINCLUDE = ['#include', '#dependencies/include']
|
||||||
BASELIBDIR = ['#dependencies/lib']
|
BASELIBDIR = ['#dependencies/lib']
|
||||||
BASELIB = ['m', 'pthread', 'gomp', 'Half']
|
BASELIB = ['m', 'pthread', 'Half']
|
||||||
OEXRINCLUDE = ['#dependencies/include/OpenEXR']
|
OEXRINCLUDE = ['#dependencies/include/OpenEXR']
|
||||||
OEXRLIB = ['IlmImf', 'Imath', 'Iex', 'z']
|
OEXRLIB = ['IlmImf', 'Imath', 'Iex', 'z']
|
||||||
PNGLIB = ['png']
|
PNGLIB = ['png']
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
<xsd:element name="vector" type="point"/>
|
<xsd:element name="vector" type="point"/>
|
||||||
<xsd:element name="boolean" type="boolean"/>
|
<xsd:element name="boolean" type="boolean"/>
|
||||||
<xsd:element name="transform" type="transform"/>
|
<xsd:element name="transform" type="transform"/>
|
||||||
|
<xsd:element name="animation" type="animation"/>
|
||||||
<xsd:element name="string" type="string"/>
|
<xsd:element name="string" type="string"/>
|
||||||
<xsd:element name="spectrum" type="spectrum"/>
|
<xsd:element name="spectrum" type="spectrum"/>
|
||||||
<xsd:element name="rgb" type="rgb"/>
|
<xsd:element name="rgb" type="rgb"/>
|
||||||
|
@ -314,6 +315,23 @@
|
||||||
</xsd:choice>
|
</xsd:choice>
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="animationTransform">
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="translate" type="translate"/>
|
||||||
|
<xsd:element name="rotate" type="rotate"/>
|
||||||
|
<xsd:element name="lookAt" type="lookAt"/>
|
||||||
|
<xsd:element name="lookat" type="lookAt"/>
|
||||||
|
<xsd:element name="scale" type="scale"/>
|
||||||
|
<xsd:element name="matrix" type="matrix"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="time" type="doubleType" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="animation">
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="transform" type="animationTransform"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
<xsd:complexType name="translate">
|
<xsd:complexType name="translate">
|
||||||
<xsd:attribute name="x" type="doubleType"/>
|
<xsd:attribute name="x" type="doubleType"/>
|
||||||
<xsd:attribute name="y" type="doubleType"/>
|
<xsd:attribute name="y" type="doubleType"/>
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
This file is part of Mitsuba, a physically based rendering system.
|
||||||
|
|
||||||
|
Copyright (c) 2007-2012 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(__MITSUBA_CORE_MATH_H_)
|
||||||
|
#define __MITSUBA_CORE_MATH_H_
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace math {
|
||||||
|
#if defined(__LINUX__) && defined(__x86_64__)
|
||||||
|
/*
|
||||||
|
The Linux/x86_64 single precision implementations of 'exp'
|
||||||
|
and 'log' suffer from a serious performance regression.
|
||||||
|
It is about 5x faster to use the double-precision versions
|
||||||
|
with the extra overhead of the involved FP conversion.
|
||||||
|
|
||||||
|
Until this is fixed, the following aliases make sure that
|
||||||
|
the fastest implementation is used in every case.
|
||||||
|
*/
|
||||||
|
inline float fastexp(float value) {
|
||||||
|
return (float) ::exp((double) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double fastexp(double value) {
|
||||||
|
return ::exp(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float fastlog(float value) {
|
||||||
|
return (float) ::log((double) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double fastlog(double value) {
|
||||||
|
return ::log(value);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
inline float fastexp(float value) {
|
||||||
|
return ::expf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double fastexp(double value) {
|
||||||
|
return ::exp(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float fastlog(float value) {
|
||||||
|
return ::logf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double fastlog(double value) {
|
||||||
|
return ::log(value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_GNU_SOURCE)
|
||||||
|
inline void sincos(float theta, float *sin, float *cos) {
|
||||||
|
::sincosf(theta, sin, cos);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sincos(double theta, double *sin, double *cos) {
|
||||||
|
::sincos(theta, sin, cos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
inline void sincos(float theta, float *_sin, float *_cos) {
|
||||||
|
*_sin = sinf(theta);
|
||||||
|
*_cos = cosf(theta);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sincos(double theta, double *_sin, double *_cos) {
|
||||||
|
*_sin = sin(theta);
|
||||||
|
*_cos = cos(theta);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Arcsine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
||||||
|
inline float safe_asin(float value) {
|
||||||
|
return std::asin(std::min(1.0f, std::max(-1.0f, value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arcsine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
||||||
|
inline double safe_asin(double value) {
|
||||||
|
return std::asin(std::min(1.0, std::max(-1.0, value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arccosine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
||||||
|
inline float safe_acos(float value) {
|
||||||
|
return std::acos(std::min(1.0f, std::max(-1.0f, value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arccosine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
||||||
|
inline double safe_acos(double value) {
|
||||||
|
return std::acos(std::min(1.0, std::max(-1.0, value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Square root variant that gracefully handles arguments < 0 that are due to roundoff errors
|
||||||
|
inline float safe_sqrt(float value) {
|
||||||
|
return std::sqrt(std::max(0.0f, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Square root variant that gracefully handles arguments < 0 that are due to roundoff errors
|
||||||
|
inline double safe_sqrt(double value) {
|
||||||
|
return std::sqrt(std::max(0.0, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simple signum function -- note that it returns the FP sign of the input (and never zero)
|
||||||
|
inline Float signum(Float value) {
|
||||||
|
#if defined(__WINDOWS__)
|
||||||
|
return (Float) _copysign(1.0, value);
|
||||||
|
#elif defined(SINGLE_PRECISION)
|
||||||
|
return copysignf((float) 1.0, value);
|
||||||
|
#elif defined(DOUBLE_PRECISION)
|
||||||
|
return copysign((double) 1.0, value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}; /* namespace math */
|
||||||
|
|
||||||
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
extern "C" {
|
||||||
|
extern MTS_EXPORT_CORE float nextafterf(float x, float y);
|
||||||
|
extern MTS_EXPORT_CORE double nextafter(double x, double y);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __MITSUBA_CORE_MATH_H_ */
|
|
@ -132,12 +132,17 @@ template <typename T> struct TQuaternion {
|
||||||
|
|
||||||
/// Equality test
|
/// Equality test
|
||||||
bool operator==(const TQuaternion &q) const {
|
bool operator==(const TQuaternion &q) const {
|
||||||
return v == q.v && v.w == q.w;
|
return v == q.v && w == q.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inequality test
|
/// Inequality test
|
||||||
bool operator!=(const TQuaternion &q) const {
|
bool operator!=(const TQuaternion &q) const {
|
||||||
return v != q.v || v.w != q.w;
|
return v != q.v || w != q.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identity test
|
||||||
|
bool isIdentity() const {
|
||||||
|
return v.isZero() && w == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the rotation axis of this quaternion
|
/// Return the rotation axis of this quaternion
|
||||||
|
@ -216,39 +221,42 @@ template <typename T> struct TQuaternion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static TQuaternion fromTransform(const Transform &trafo) {
|
||||||
|
return fromMatrix(trafo.getMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Construct an unit quaternion matching the supplied
|
* \brief Construct an unit quaternion matching the supplied
|
||||||
* rotation matrix.
|
* rotation matrix.
|
||||||
*/
|
*/
|
||||||
static TQuaternion fromTransform(const Transform trafo) {
|
static TQuaternion fromMatrix(const Matrix4x4 &m) {
|
||||||
/// Implementation from PBRT
|
/// Implementation from PBRT
|
||||||
const Matrix4x4 &m = trafo.getMatrix();
|
T trace = m(0, 0) + m(1, 1) + m(2, 2);
|
||||||
T trace = m.m[0][0] + m.m[1][1] + m.m[2][2];
|
|
||||||
TVector3<T> v; T w;
|
TVector3<T> v; T w;
|
||||||
if (trace > 0.f) {
|
if (trace > 0.f) {
|
||||||
// Compute w from matrix trace, then xyz
|
// Compute w from matrix trace, then xyz
|
||||||
// 4w^2 = m[0][0] + m[1][1] + m[2][2] + m[3][3] (but m[3][3] == 1)
|
// 4w^2 = m[0, 0] + m[1, 1] + m[2, 2] + m[3, 3] (but m[3, 3] == 1)
|
||||||
T s = std::sqrt(trace + 1.0f);
|
T s = std::sqrt(trace + 1.0f);
|
||||||
w = s / 2.0f;
|
w = s / 2.0f;
|
||||||
s = 0.5f / s;
|
s = 0.5f / s;
|
||||||
v.x = (m.m[2][1] - m.m[1][2]) * s;
|
v.x = (m(2, 1) - m(1, 2)) * s;
|
||||||
v.y = (m.m[0][2] - m.m[2][0]) * s;
|
v.y = (m(0, 2) - m(2, 0)) * s;
|
||||||
v.z = (m.m[1][0] - m.m[0][1]) * s;
|
v.z = (m(1, 0) - m(0, 1)) * s;
|
||||||
} else {
|
} else {
|
||||||
// Compute largest of $x$, $y$, or $z$, then remaining components
|
// Compute largest of $x$, $y$, or $z$, then remaining components
|
||||||
const int nxt[3] = {1, 2, 0};
|
const int nxt[3] = {1, 2, 0};
|
||||||
T q[3];
|
T q[3];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (m.m[1][1] > m.m[0][0]) i = 1;
|
if (m(1, 1) > m(0, 0)) i = 1;
|
||||||
if (m.m[2][2] > m.m[i][i]) i = 2;
|
if (m(2, 2) > m(i, i)) i = 2;
|
||||||
int j = nxt[i];
|
int j = nxt[i];
|
||||||
int k = nxt[j];
|
int k = nxt[j];
|
||||||
T s = std::sqrt((m.m[i][i] - (m.m[j][j] + m.m[k][k])) + 1.0);
|
T s = std::sqrt((m(i, i) - (m(j, j) + m(k, k))) + 1.0f);
|
||||||
q[i] = s * 0.5f;
|
q[i] = s * 0.5f;
|
||||||
if (s != 0.f) s = 0.5f / s;
|
if (s != 0.f) s = 0.5f / s;
|
||||||
w = (m.m[k][j] - m.m[j][k]) * s;
|
w = (m(k, j) - m(j, k)) * s;
|
||||||
q[j] = (m.m[j][i] + m.m[i][j]) * s;
|
q[j] = (m(j, i) + m(i, j)) * s;
|
||||||
q[k] = (m.m[k][i] + m.m[i][k]) * s;
|
q[k] = (m(k, i) + m(i, k)) * s;
|
||||||
v.x = q[0];
|
v.x = q[0];
|
||||||
v.y = q[1];
|
v.y = q[1];
|
||||||
v.z = q[2];
|
v.z = q[2];
|
||||||
|
|
|
@ -103,121 +103,6 @@ namespace std {
|
||||||
using std::select2nd;
|
using std::select2nd;
|
||||||
using std::compose1;
|
using std::compose1;
|
||||||
#endif
|
#endif
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
namespace mitsuba {
|
|
||||||
namespace math {
|
|
||||||
#if defined(__LINUX__) && defined(__x86_64__)
|
|
||||||
/*
|
|
||||||
The Linux/x86_64 single precision implementations of 'exp'
|
|
||||||
and 'log' suffer from a serious performance regression.
|
|
||||||
It is about 5x faster to use the double-precision versions
|
|
||||||
with the extra overhead of the involved FP conversion.
|
|
||||||
|
|
||||||
Until this is fixed, the following aliases make sure that
|
|
||||||
the fastest implementation is used in every case.
|
|
||||||
*/
|
|
||||||
inline float fastexp(float value) {
|
|
||||||
return (float) ::exp((double) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double fastexp(double value) {
|
|
||||||
return ::exp(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float fastlog(float value) {
|
|
||||||
return (float) ::log((double) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double fastlog(double value) {
|
|
||||||
return ::log(value);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inline float fastexp(float value) {
|
|
||||||
return ::expf(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double fastexp(double value) {
|
|
||||||
return ::exp(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float fastlog(float value) {
|
|
||||||
return ::logf(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double fastlog(double value) {
|
|
||||||
return ::log(value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_GNU_SOURCE)
|
|
||||||
inline void sincos(float theta, float *sin, float *cos) {
|
|
||||||
::sincosf(theta, sin, cos);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sincos(double theta, double *sin, double *cos) {
|
|
||||||
::sincos(theta, sin, cos);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
inline void sincos(float theta, float *_sin, float *_cos) {
|
|
||||||
*_sin = sinf(theta);
|
|
||||||
*_cos = cosf(theta);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sincos(double theta, double *_sin, double *_cos) {
|
|
||||||
*_sin = sin(theta);
|
|
||||||
*_cos = cos(theta);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Arcsine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
|
||||||
inline float safe_asin(float value) {
|
|
||||||
return std::asin(std::min(1.0f, std::max(-1.0f, value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Arcsine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
|
||||||
inline double safe_asin(double value) {
|
|
||||||
return std::asin(std::min(1.0, std::max(-1.0, value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Arccosine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
|
||||||
inline float safe_acos(float value) {
|
|
||||||
return std::acos(std::min(1.0f, std::max(-1.0f, value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Arccosine variant that gracefully handles arguments > 1 that are due to roundoff errors
|
|
||||||
inline double safe_acos(double value) {
|
|
||||||
return std::acos(std::min(1.0, std::max(-1.0, value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Square root variant that gracefully handles arguments < 0 that are due to roundoff errors
|
|
||||||
inline float safe_sqrt(float value) {
|
|
||||||
return std::sqrt(std::max(0.0f, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Square root variant that gracefully handles arguments < 0 that are due to roundoff errors
|
|
||||||
inline double safe_sqrt(double value) {
|
|
||||||
return std::sqrt(std::max(0.0, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simple signum function -- note that it returns the FP sign of the input (and never zero)
|
|
||||||
inline Float signum(Float value) {
|
|
||||||
#if defined(__WINDOWS__)
|
|
||||||
return (Float) _copysign(1.0, value);
|
|
||||||
#elif defined(SINGLE_PRECISION)
|
|
||||||
return copysignf((float) 1.0, value);
|
|
||||||
#elif defined(DOUBLE_PRECISION)
|
|
||||||
return copysign((double) 1.0, value);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}; /* namespace math */
|
|
||||||
}; /* namespace mitsuba */
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
extern "C" {
|
|
||||||
extern MTS_EXPORT_CORE float nextafterf(float x, float y);
|
|
||||||
extern MTS_EXPORT_CORE double nextafter(double x, double y);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
/// @endcond
|
|
||||||
#endif /* __MITSUBA_CORE_STL_H_ */
|
#endif /* __MITSUBA_CORE_STL_H_ */
|
||||||
|
|
|
@ -46,6 +46,7 @@ using std::endl;
|
||||||
#include <mitsuba/core/fwd.h>
|
#include <mitsuba/core/fwd.h>
|
||||||
#include <mitsuba/render/fwd.h>
|
#include <mitsuba/render/fwd.h>
|
||||||
#include <mitsuba/core/stl.h>
|
#include <mitsuba/core/stl.h>
|
||||||
|
#include <mitsuba/core/math.h>
|
||||||
#include <mitsuba/core/object.h>
|
#include <mitsuba/core/object.h>
|
||||||
#include <mitsuba/core/ref.h>
|
#include <mitsuba/core/ref.h>
|
||||||
#include <mitsuba/core/tls.h>
|
#include <mitsuba/core/tls.h>
|
||||||
|
|
|
@ -155,7 +155,8 @@ private:
|
||||||
EBoolean, EString, ETranslate, ERotate,
|
EBoolean, EString, ETranslate, ERotate,
|
||||||
ELookAt, EScale, EMatrix, EPoint,
|
ELookAt, EScale, EMatrix, EPoint,
|
||||||
EVector, ERGB, ESRGB, EBlackBody,
|
EVector, ERGB, ESRGB, EBlackBody,
|
||||||
ESpectrum, ETransform, EInclude, EAlias
|
ESpectrum, ETransform, EAnimation,
|
||||||
|
EInclude, EAlias
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::pair<ETag, const Class *> TagEntry;
|
typedef std::pair<ETag, const Class *> TagEntry;
|
||||||
|
@ -170,6 +171,7 @@ private:
|
||||||
std::stack<ParseContext> m_context;
|
std::stack<ParseContext> m_context;
|
||||||
TagMap m_tags;
|
TagMap m_tags;
|
||||||
Transform m_transform;
|
Transform m_transform;
|
||||||
|
ref<AnimatedTransform> m_animatedTransform;
|
||||||
bool m_isIncludedFile;
|
bool m_isIncludedFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,9 +82,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
template <typename T> class AnimationTrack : public AbstractAnimationTrack {
|
template <typename T> class AnimationTrack : public AbstractAnimationTrack {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
typedef T ValueType;
|
||||||
|
|
||||||
AnimationTrack(EType type, size_t nKeyframes)
|
AnimationTrack(EType type, size_t nKeyframes = 0)
|
||||||
: AbstractAnimationTrack(type, nKeyframes), m_values(nKeyframes) { }
|
: AbstractAnimationTrack(type, nKeyframes), m_values(nKeyframes) { }
|
||||||
|
|
||||||
AnimationTrack(EType type, Stream *stream)
|
AnimationTrack(EType type, Stream *stream)
|
||||||
|
@ -96,10 +96,19 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the value of a certain keyframe
|
/// Set the value of a certain keyframe
|
||||||
inline void setValue(size_t idx, const value_type &value) { m_values[idx] = value; }
|
inline void setValue(size_t idx, const ValueType &value) { m_values[idx] = value; }
|
||||||
|
|
||||||
/// Return the value of a certain keyframe
|
/// Return the value of a certain keyframe
|
||||||
inline const value_type &getValue(size_t idx) const { return m_values[idx]; }
|
inline const ValueType &getValue(size_t idx) const { return m_values[idx]; }
|
||||||
|
|
||||||
|
/// Reserve space for a certain number of entries
|
||||||
|
inline void reserve(size_t count) { m_times.reserve(count); m_values.reserve(count); }
|
||||||
|
|
||||||
|
/// Append a value
|
||||||
|
inline void append(Float time, const ValueType &value) {
|
||||||
|
m_times.push_back(time);
|
||||||
|
m_values.push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
/// Serialize to a binary data stream
|
/// Serialize to a binary data stream
|
||||||
inline void serialize(Stream *stream) const {
|
inline void serialize(Stream *stream) const {
|
||||||
|
@ -111,7 +120,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the animation track at an arbitrary time value
|
/// Evaluate the animation track at an arbitrary time value
|
||||||
inline value_type eval(Float time) const {
|
inline ValueType eval(Float time) const {
|
||||||
SAssert(m_times.size() > 0);
|
SAssert(m_times.size() > 0);
|
||||||
std::vector<Float>::const_iterator entry =
|
std::vector<Float>::const_iterator entry =
|
||||||
std::lower_bound(m_times.begin(), m_times.end(), time);
|
std::lower_bound(m_times.begin(), m_times.end(), time);
|
||||||
|
@ -126,19 +135,61 @@ public:
|
||||||
}
|
}
|
||||||
return lerp(idx0, idx1, t);
|
return lerp(idx0, idx1, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SortPredicate {
|
||||||
|
inline bool operator()(const std::pair<Float, ValueType> &p1,
|
||||||
|
const std::pair<Float, ValueType> &p2) const {
|
||||||
|
return p1.first < p2.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MatchPredicate {
|
||||||
|
inline bool operator()(const std::pair<Float, ValueType> &p1,
|
||||||
|
const std::pair<Float, ValueType> &p2) const {
|
||||||
|
return p1.first == p2.first || p1.second == p2.second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief Sort all animation tracks and remove
|
||||||
|
* unnecessary data (for user-provided input)
|
||||||
|
*
|
||||||
|
* \return \c false if this animation track was deemed to be unnecessary
|
||||||
|
* after the cleanup (for instance, it only contains (0,0,0) translation operations)
|
||||||
|
*/
|
||||||
|
bool sortAndSimplify() {
|
||||||
|
SAssert(m_values.size() == m_times.size());
|
||||||
|
std::vector< std::pair<Float, ValueType> > temp(m_values.size());
|
||||||
|
for (size_t i=0; i<m_values.size(); ++i)
|
||||||
|
temp[i] = std::make_pair(m_times[i], m_values[i]);
|
||||||
|
std::sort(temp.begin(), temp.end(), SortPredicate());
|
||||||
|
temp.erase(std::unique(temp.begin(), temp.end(), MatchPredicate()));
|
||||||
|
m_times.resize(temp.size()); m_values.resize(temp.size());
|
||||||
|
for (size_t i=0; i<temp.size(); ++i) {
|
||||||
|
m_times[i] = temp[i].first;
|
||||||
|
m_values[i] = temp[i].second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_values.size() > 0 || !isNoOp(m_values[0]);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
/// Evaluate the animation track using linear interpolation
|
/// Evaluate the animation track using linear interpolation
|
||||||
inline value_type lerp(size_t idx0, size_t idx1, Float t) const;
|
inline ValueType lerp(size_t idx0, size_t idx1, Float t) const;
|
||||||
|
|
||||||
inline void unserialize(Stream *stream, value_type &value) {
|
/// Is this a "no-op" transformation?
|
||||||
value = stream->readElement<value_type>();
|
inline bool isNoOp(const ValueType &value) const;
|
||||||
|
|
||||||
|
inline void unserialize(Stream *stream, ValueType &value) {
|
||||||
|
value = stream->readElement<ValueType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void serialize(Stream *stream, const value_type &value) const {
|
inline void serialize(Stream *stream, const ValueType &value) const {
|
||||||
stream->writeElement<value_type>(value);
|
stream->writeElement<ValueType>(value);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::vector<value_type> m_values;
|
std::vector<ValueType> m_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> inline T AnimationTrack<T>::lerp(size_t idx0, size_t idx1, Float t) const {
|
template<typename T> inline T AnimationTrack<T>::lerp(size_t idx0, size_t idx1, Float t) const {
|
||||||
|
@ -150,6 +201,32 @@ template<> inline Quaternion AnimationTrack<Quaternion>::lerp(size_t idx0, size_
|
||||||
return slerp(m_values[idx0], m_values[idx1], t);
|
return slerp(m_values[idx0], m_values[idx1], t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T> inline bool AnimationTrack<T>::isNoOp(const ValueType &value) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool AnimationTrack<Float>::isNoOp(const Float &value) const {
|
||||||
|
if ((m_type == ETranslationX || m_type == ETranslationY || m_type == ETranslationZ) && value == 0)
|
||||||
|
return true;
|
||||||
|
else if ((m_type == ERotationX || m_type == ERotationY || m_type == ERotationZ) && value == 0)
|
||||||
|
return true;
|
||||||
|
else if ((m_type == EScaleX || m_type == EScaleY || m_type == EScaleZ) && value == 1)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool AnimationTrack<Vector>::isNoOp(const Vector &value) const {
|
||||||
|
if (m_type == ETranslationXYZ && value.isZero())
|
||||||
|
return true;
|
||||||
|
else if (m_type == EScaleXYZ && (value.x == 1 && value.y == 1 && value.z == 1))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool AnimationTrack<Quaternion>::isNoOp(const Quaternion &value) const {
|
||||||
|
return value.isIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
template<> inline void AnimationTrack<Point>::unserialize(Stream *stream, Point &value) {
|
template<> inline void AnimationTrack<Point>::unserialize(Stream *stream, Point &value) {
|
||||||
value = Point(stream);
|
value = Point(stream);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +256,7 @@ template<> inline void AnimationTrack<Quaternion>::serialize(Stream *stream, con
|
||||||
* \ingroup librender
|
* \ingroup librender
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_RENDER AnimatedTransform : public Object {
|
class MTS_EXPORT_RENDER AnimatedTransform : public Object {
|
||||||
protected:
|
private:
|
||||||
/// Internal functor used by \ref eval() and \ref SimpleCache
|
/// Internal functor used by \ref eval() and \ref SimpleCache
|
||||||
struct MTS_EXPORT_RENDER TransformFunctor {
|
struct MTS_EXPORT_RENDER TransformFunctor {
|
||||||
public:
|
public:
|
||||||
|
@ -221,7 +298,7 @@ public:
|
||||||
* to this function.
|
* to this function.
|
||||||
*/
|
*/
|
||||||
inline const Transform &eval(Float t) const {
|
inline const Transform &eval(Float t) const {
|
||||||
if (m_tracks.size() == 0)
|
if (EXPECT_TAKEN(m_tracks.size() == 0))
|
||||||
return m_transform;
|
return m_transform;
|
||||||
else
|
else
|
||||||
return m_cache.get(TransformFunctor(m_tracks), t);
|
return m_cache.get(TransformFunctor(m_tracks), t);
|
||||||
|
@ -230,6 +307,12 @@ public:
|
||||||
/// Is the animation static?
|
/// Is the animation static?
|
||||||
inline bool isStatic() const { return m_tracks.size() == 0; }
|
inline bool isStatic() const { return m_tracks.size() == 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sort all animation tracks and remove unnecessary
|
||||||
|
* data (for user-provided input)
|
||||||
|
*/
|
||||||
|
void sortAndSimplify();
|
||||||
|
|
||||||
/// Transform a point by an affine / non-projective matrix
|
/// Transform a point by an affine / non-projective matrix
|
||||||
inline Point transformAffine(Float t, const Point &p) const {
|
inline Point transformAffine(Float t, const Point &p) const {
|
||||||
return eval(t).transformAffine(p);
|
return eval(t).transformAffine(p);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <mitsuba/core/fresolver.h>
|
#include <mitsuba/core/fresolver.h>
|
||||||
#include <mitsuba/render/scene.h>
|
#include <mitsuba/render/scene.h>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <Eigen/SVD>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
XERCES_CPP_NAMESPACE_USE
|
XERCES_CPP_NAMESPACE_USE
|
||||||
|
@ -97,6 +98,7 @@ SceneHandler::SceneHandler(const SAXParser *parser,
|
||||||
m_tags["blackbody"] = TagEntry(EBlackBody, (Class *) NULL);
|
m_tags["blackbody"] = TagEntry(EBlackBody, (Class *) NULL);
|
||||||
m_tags["spectrum"] = TagEntry(ESpectrum, (Class *) NULL);
|
m_tags["spectrum"] = TagEntry(ESpectrum, (Class *) NULL);
|
||||||
m_tags["transform"] = TagEntry(ETransform, (Class *) NULL);
|
m_tags["transform"] = TagEntry(ETransform, (Class *) NULL);
|
||||||
|
m_tags["animation"] = TagEntry(EAnimation, (Class *) NULL);
|
||||||
m_tags["include"] = TagEntry(EInclude, (Class *) NULL);
|
m_tags["include"] = TagEntry(EInclude, (Class *) NULL);
|
||||||
m_tags["alias"] = TagEntry(EAlias, (Class *) NULL);
|
m_tags["alias"] = TagEntry(EAlias, (Class *) NULL);
|
||||||
|
|
||||||
|
@ -167,11 +169,12 @@ void SceneHandler::characters(const XMLCh* const name,
|
||||||
Float SceneHandler::parseFloat(const std::string &name,
|
Float SceneHandler::parseFloat(const std::string &name,
|
||||||
const std::string &str, Float defVal) const {
|
const std::string &str, Float defVal) const {
|
||||||
char *end_ptr = NULL;
|
char *end_ptr = NULL;
|
||||||
if (str == "") {
|
if (str.empty()) {
|
||||||
if (defVal == -1)
|
if (defVal == -1)
|
||||||
XMLLog(EError, "Missing floating point value (in <%s>)", name.c_str());
|
XMLLog(EError, "Missing floating point value (in <%s>)", name.c_str());
|
||||||
return defVal;
|
return defVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Float result = (Float) std::strtod(str.c_str(), &end_ptr);
|
Float result = (Float) std::strtod(str.c_str(), &end_ptr);
|
||||||
if (*end_ptr != '\0')
|
if (*end_ptr != '\0')
|
||||||
XMLLog(EError, "Invalid floating point value specified (in <%s>)", name.c_str());
|
XMLLog(EError, "Invalid floating point value specified (in <%s>)", name.c_str());
|
||||||
|
@ -240,6 +243,19 @@ void SceneHandler::startElement(const XMLCh* const xmlName,
|
||||||
case ETransform:
|
case ETransform:
|
||||||
m_transform = Transform();
|
m_transform = Transform();
|
||||||
break;
|
break;
|
||||||
|
case EAnimation: {
|
||||||
|
m_animatedTransform = new AnimatedTransform();
|
||||||
|
ref<VectorTrack> translation = new VectorTrack(VectorTrack::ETranslationXYZ);
|
||||||
|
ref<QuatTrack> rotation = new QuatTrack(VectorTrack::ERotationQuat);
|
||||||
|
ref<VectorTrack> scaling = new VectorTrack(VectorTrack::EScaleXYZ);
|
||||||
|
translation->reserve(2);
|
||||||
|
rotation->reserve(2);
|
||||||
|
scaling->reserve(2);
|
||||||
|
m_animatedTransform->addTrack(translation);
|
||||||
|
m_animatedTransform->addTrack(rotation);
|
||||||
|
m_animatedTransform->addTrack(scaling);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -575,9 +591,56 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EAnimation: {
|
||||||
|
m_animatedTransform->sortAndSimplify();
|
||||||
|
// context.parent->properties.setAnimatedTransform(
|
||||||
|
// context.attributes["name"], m_animatedTransform);//XXX
|
||||||
|
m_animatedTransform = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case ETransform: {
|
case ETransform: {
|
||||||
|
if (!m_animatedTransform.get()) {
|
||||||
context.parent->properties.setTransform(
|
context.parent->properties.setTransform(
|
||||||
context.attributes["name"], m_transform);
|
context.attributes["name"], m_transform);
|
||||||
|
} else {
|
||||||
|
/* Compute the polar decomposition and insert into the animated transform
|
||||||
|
uh oh.. we have to get rid of 2 matrix libraries at some point :) */
|
||||||
|
typedef Eigen::Matrix<Float, 3, 3> EMatrix;
|
||||||
|
const Matrix4x4 m = m_transform.getMatrix();
|
||||||
|
|
||||||
|
EMatrix A;
|
||||||
|
A << m(0, 0), m(0, 1), m(0, 2),
|
||||||
|
m(1, 0), m(1, 1), m(1, 2),
|
||||||
|
m(2, 0), m(2, 1), m(2, 2);
|
||||||
|
|
||||||
|
Eigen::JacobiSVD<EMatrix> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
EMatrix U = svd.matrixU(), V = svd.matrixV(), S = svd.singularValues().asDiagonal();
|
||||||
|
|
||||||
|
if (svd.singularValues().prod() < 0) {
|
||||||
|
S = -S; U = -U;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMatrix Q = U*V.transpose();
|
||||||
|
EMatrix P = V*S*V.transpose();
|
||||||
|
|
||||||
|
VectorTrack *translation = (VectorTrack *) m_animatedTransform->getTrack(0);
|
||||||
|
QuatTrack *rotation = (QuatTrack *) m_animatedTransform->getTrack(1);
|
||||||
|
VectorTrack *scaling = (VectorTrack *) m_animatedTransform->getTrack(2);
|
||||||
|
|
||||||
|
Float time = parseFloat("time", context.attributes["time"]);
|
||||||
|
rotation->append(time, Quaternion::fromMatrix(
|
||||||
|
Matrix4x4(
|
||||||
|
Q(0, 0), Q(0, 1), Q(0, 2), 0.0f,
|
||||||
|
Q(1, 0), Q(1, 1), Q(1, 2), 0.0f,
|
||||||
|
Q(2, 0), Q(2, 1), Q(2, 2), 0.0f,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
scaling->append(time, Vector(P(0, 0), P(1, 1), P(2, 2)));
|
||||||
|
translation->append(time, Vector(m(0, 3), m(1, 3), m(2, 3)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -48,16 +48,7 @@ void AnimatedTransform::addTrack(AbstractAnimationTrack *track) {
|
||||||
|
|
||||||
AABB1 AnimatedTransform::getTimeBounds() const {
|
AABB1 AnimatedTransform::getTimeBounds() const {
|
||||||
if (m_tracks.size() == 0)
|
if (m_tracks.size() == 0)
|
||||||
#if !defined(__clang__)
|
|
||||||
return AABB1(0.0f, 0.0f);
|
return AABB1(0.0f, 0.0f);
|
||||||
#else
|
|
||||||
// HACK Workaround for clang
|
|
||||||
{
|
|
||||||
AABB1 b;
|
|
||||||
b.min = b.max = 0.0f;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Float min = std::numeric_limits<Float>::infinity();
|
Float min = std::numeric_limits<Float>::infinity();
|
||||||
Float max = -std::numeric_limits<Float>::infinity();
|
Float max = -std::numeric_limits<Float>::infinity();
|
||||||
|
@ -70,15 +61,7 @@ AABB1 AnimatedTransform::getTimeBounds() const {
|
||||||
max = std::max(max, track->getTime(size-1));
|
max = std::max(max, track->getTime(size-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__clang__)
|
|
||||||
return AABB1(min, max);
|
return AABB1(min, max);
|
||||||
#else
|
|
||||||
// HACK Workaround for clang
|
|
||||||
AABB1 b;
|
|
||||||
b.min = min;
|
|
||||||
b.max = max;
|
|
||||||
return b;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AABB AnimatedTransform::getTranslationBounds() const {
|
AABB AnimatedTransform::getTranslationBounds() const {
|
||||||
|
@ -152,6 +135,53 @@ AnimatedTransform::~AnimatedTransform() {
|
||||||
m_tracks[i]->decRef();
|
m_tracks[i]->decRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimatedTransform::sortAndSimplify() {
|
||||||
|
bool isStatic = true;
|
||||||
|
|
||||||
|
for (size_t i=0; i<m_tracks.size(); ++i) {
|
||||||
|
AbstractAnimationTrack *track = m_tracks[i];
|
||||||
|
bool success = false;
|
||||||
|
switch (track->getType()) {
|
||||||
|
case AbstractAnimationTrack::ETranslationX:
|
||||||
|
case AbstractAnimationTrack::ETranslationY:
|
||||||
|
case AbstractAnimationTrack::ETranslationZ:
|
||||||
|
case AbstractAnimationTrack::ERotationX:
|
||||||
|
case AbstractAnimationTrack::ERotationY:
|
||||||
|
case AbstractAnimationTrack::ERotationZ:
|
||||||
|
case AbstractAnimationTrack::EScaleX:
|
||||||
|
case AbstractAnimationTrack::EScaleY:
|
||||||
|
case AbstractAnimationTrack::EScaleZ:
|
||||||
|
success = static_cast<FloatTrack *>(track)->sortAndSimplify();
|
||||||
|
break;
|
||||||
|
case AbstractAnimationTrack::ETranslationXYZ:
|
||||||
|
case AbstractAnimationTrack::EScaleXYZ:
|
||||||
|
success = static_cast<VectorTrack *>(track)->sortAndSimplify();
|
||||||
|
break;
|
||||||
|
case AbstractAnimationTrack::ERotationQuat:
|
||||||
|
success = static_cast<QuatTrack *>(track)->sortAndSimplify();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log(EError, "Encountered an unsupported "
|
||||||
|
"animation track type: %i!", track->getType());
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
isStatic &= track->getSize() == 1;
|
||||||
|
} else {
|
||||||
|
m_tracks.erase(m_tracks.begin() + i);
|
||||||
|
track->decRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStatic) {
|
||||||
|
Transform temp;
|
||||||
|
temp = eval(0);
|
||||||
|
m_transform = temp;
|
||||||
|
for (size_t i=0; i<m_tracks.size(); ++i)
|
||||||
|
m_tracks[i]->decRef();
|
||||||
|
m_tracks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AnimatedTransform::serialize(Stream *stream) const {
|
void AnimatedTransform::serialize(Stream *stream) const {
|
||||||
stream->writeSize(m_tracks.size());
|
stream->writeSize(m_tracks.size());
|
||||||
if (m_tracks.size() == 0) {
|
if (m_tracks.size() == 0) {
|
||||||
|
|
|
@ -495,7 +495,7 @@ public:
|
||||||
|
|
||||||
void getNormalDerivative(const Intersection &its,
|
void getNormalDerivative(const Intersection &its,
|
||||||
Vector &dndu, Vector &dndv, bool shadingFrame) const {
|
Vector &dndu, Vector &dndv, bool shadingFrame) const {
|
||||||
dndu = its.dpdu / (m_radius * m_flipNormals ? -1 : 1);
|
dndu = its.dpdu / (m_radius * (m_flipNormals ? -1 : 1));
|
||||||
dndv = Vector(0.0f);
|
dndv = Vector(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue