some work towards animated transformation support

metadata
Wenzel Jakob 2012-10-26 02:15:32 -04:00
parent 3885a4c6f9
commit 544080e808
18 changed files with 420 additions and 188 deletions

View File

@ -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']
BASEINCLUDE = ['#include', '#dependencies/include']
BASELIBDIR = ['#dependencies/lib']
BASELIB = ['m', 'pthread', 'gomp', 'Half']
BASELIB = ['m', 'pthread', 'Half']
OEXRINCLUDE = ['#dependencies/include/OpenEXR']
OEXRLIB = ['IlmImf', 'Imath', 'Iex', 'z']
PNGLIB = ['png']

View File

@ -26,7 +26,7 @@
<xsd:element name="rgb" type="rgb"/>
<xsd:element name="srgb" type="string"/>
<xsd:element name="blackbody" type="blackbody"/>
<xsd:element name="alias" type="alias"/>
</xsd:choice>
<xsd:attribute name="version" type="xsd:string"/>
@ -43,6 +43,7 @@
<xsd:element name="vector" type="point"/>
<xsd:element name="boolean" type="boolean"/>
<xsd:element name="transform" type="transform"/>
<xsd:element name="animation" type="animation"/>
<xsd:element name="string" type="string"/>
<xsd:element name="spectrum" type="spectrum"/>
<xsd:element name="rgb" type="rgb"/>
@ -50,14 +51,14 @@
<xsd:element name="blackbody" type="blackbody"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="objectBase">
<xsd:attribute name="type" type="xsd:string" use="required"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="id" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="object">
<xsd:complexContent>
<xsd:extension base="objectBase">
@ -140,7 +141,7 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- MEDIUM Element -->
<xsd:complexType name="medium">
<xsd:complexContent>
@ -297,7 +298,7 @@
<xsd:complexType name="include">
<xsd:attribute name="filename" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="alias">
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="as" type="xsd:string" use="required"/>
@ -314,6 +315,23 @@
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</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:attribute name="x" type="doubleType"/>
<xsd:attribute name="y" type="doubleType"/>

142
include/mitsuba/core/math.h Normal file
View File

@ -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_ */

View File

@ -132,12 +132,17 @@ template <typename T> struct TQuaternion {
/// Equality test
bool operator==(const TQuaternion &q) const {
return v == q.v && v.w == q.w;
return v == q.v && w == q.w;
}
/// Inequality test
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
@ -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
* rotation matrix.
*/
static TQuaternion fromTransform(const Transform trafo) {
static TQuaternion fromMatrix(const Matrix4x4 &m) {
/// Implementation from PBRT
const Matrix4x4 &m = trafo.getMatrix();
T trace = m.m[0][0] + m.m[1][1] + m.m[2][2];
T trace = m(0, 0) + m(1, 1) + m(2, 2);
TVector3<T> v; T w;
if (trace > 0.f) {
// 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);
w = s / 2.0f;
s = 0.5f / s;
v.x = (m.m[2][1] - m.m[1][2]) * s;
v.y = (m.m[0][2] - m.m[2][0]) * s;
v.z = (m.m[1][0] - m.m[0][1]) * s;
v.x = (m(2, 1) - m(1, 2)) * s;
v.y = (m(0, 2) - m(2, 0)) * s;
v.z = (m(1, 0) - m(0, 1)) * s;
} else {
// Compute largest of $x$, $y$, or $z$, then remaining components
const int nxt[3] = {1, 2, 0};
T q[3];
int i = 0;
if (m.m[1][1] > m.m[0][0]) i = 1;
if (m.m[2][2] > m.m[i][i]) i = 2;
if (m(1, 1) > m(0, 0)) i = 1;
if (m(2, 2) > m(i, i)) i = 2;
int j = nxt[i];
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;
if (s != 0.f) s = 0.5f / s;
w = (m.m[k][j] - m.m[j][k]) * s;
q[j] = (m.m[j][i] + m.m[i][j]) * s;
q[k] = (m.m[k][i] + m.m[i][k]) * s;
w = (m(k, j) - m(j, k)) * s;
q[j] = (m(j, i) + m(i, j)) * s;
q[k] = (m(k, i) + m(i, k)) * s;
v.x = q[0];
v.y = q[1];
v.z = q[2];

View File

@ -103,121 +103,6 @@ namespace std {
using std::select2nd;
using std::compose1;
#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_ */

View File

@ -46,6 +46,7 @@ using std::endl;
#include <mitsuba/core/fwd.h>
#include <mitsuba/render/fwd.h>
#include <mitsuba/core/stl.h>
#include <mitsuba/core/math.h>
#include <mitsuba/core/object.h>
#include <mitsuba/core/ref.h>
#include <mitsuba/core/tls.h>

View File

@ -155,7 +155,8 @@ private:
EBoolean, EString, ETranslate, ERotate,
ELookAt, EScale, EMatrix, EPoint,
EVector, ERGB, ESRGB, EBlackBody,
ESpectrum, ETransform, EInclude, EAlias
ESpectrum, ETransform, EAnimation,
EInclude, EAlias
};
typedef std::pair<ETag, const Class *> TagEntry;
@ -170,6 +171,7 @@ private:
std::stack<ParseContext> m_context;
TagMap m_tags;
Transform m_transform;
ref<AnimatedTransform> m_animatedTransform;
bool m_isIncludedFile;
};

View File

@ -82,9 +82,9 @@ protected:
*/
template <typename T> class AnimationTrack : public AbstractAnimationTrack {
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) { }
AnimationTrack(EType type, Stream *stream)
@ -96,10 +96,19 @@ public:
}
/// 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
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
inline void serialize(Stream *stream) const {
@ -111,7 +120,7 @@ public:
}
/// 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);
std::vector<Float>::const_iterator entry =
std::lower_bound(m_times.begin(), m_times.end(), time);
@ -126,19 +135,61 @@ public:
}
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:
/// 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) {
value = stream->readElement<value_type>();
/// Is this a "no-op" transformation?
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 {
stream->writeElement<value_type>(value);
inline void serialize(Stream *stream, const ValueType &value) const {
stream->writeElement<ValueType>(value);
}
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 {
@ -150,6 +201,32 @@ template<> inline Quaternion AnimationTrack<Quaternion>::lerp(size_t idx0, size_
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) {
value = Point(stream);
}
@ -179,7 +256,7 @@ template<> inline void AnimationTrack<Quaternion>::serialize(Stream *stream, con
* \ingroup librender
*/
class MTS_EXPORT_RENDER AnimatedTransform : public Object {
protected:
private:
/// Internal functor used by \ref eval() and \ref SimpleCache
struct MTS_EXPORT_RENDER TransformFunctor {
public:
@ -221,7 +298,7 @@ public:
* to this function.
*/
inline const Transform &eval(Float t) const {
if (m_tracks.size() == 0)
if (EXPECT_TAKEN(m_tracks.size() == 0))
return m_transform;
else
return m_cache.get(TransformFunctor(m_tracks), t);
@ -230,6 +307,12 @@ public:
/// Is the animation static?
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
inline Point transformAffine(Float t, const Point &p) const {
return eval(t).transformAffine(p);

View File

@ -18,7 +18,7 @@ if hasCollada:
colladaEnv.StaticObject('obj.cpp'),
colladaEnv.StaticObject('converter.cpp')
]
colladaEnv.Program('mtsimport', stubs + ['mtsimport.cpp']
colladaEnv.Program('mtsimport', stubs + ['mtsimport.cpp']
+ converter_objects)
Return('converter_objects')

View File

@ -9,7 +9,7 @@ bidirEnv.Append(CPPDEFINES = [['MTS_BUILD_MODULE', 'MTS_MODULE_BIDIR']])
libbidir = bidirEnv.SharedLibrary('mitsuba-bidir', [
'common.cpp', 'rsampler.cpp', 'vertex.cpp', 'edge.cpp',
'path.cpp', 'verification.cpp', 'util.cpp', 'pathsampler.cpp',
'mut_bidir.cpp', 'mut_lens.cpp', 'mut_caustic.cpp',
'mut_bidir.cpp', 'mut_lens.cpp', 'mut_caustic.cpp',
'mut_mchain.cpp', 'manifold.cpp', 'mut_manifold.cpp'
])

View File

@ -28,10 +28,10 @@ libcore_objects = [
'class.cpp', 'object.cpp', 'statistics.cpp', 'thread.cpp', 'brent.cpp',
'logger.cpp', 'appender.cpp', 'formatter.cpp', 'lock.cpp', 'qmc.cpp',
'random.cpp', 'timer.cpp', 'util.cpp', 'properties.cpp', 'half.cpp',
'transform.cpp', 'spectrum.cpp', 'aabb.cpp', 'stream.cpp',
'transform.cpp', 'spectrum.cpp', 'aabb.cpp', 'stream.cpp',
'fstream.cpp', 'plugin.cpp', 'triangle.cpp', 'bitmap.cpp',
'fmtconv.cpp', 'serialization.cpp', 'sstream.cpp', 'cstream.cpp',
'mstream.cpp', 'sched.cpp', 'sched_remote.cpp', 'sshstream.cpp',
'fmtconv.cpp', 'serialization.cpp', 'sstream.cpp', 'cstream.cpp',
'mstream.cpp', 'sched.cpp', 'sched_remote.cpp', 'sshstream.cpp',
'zstream.cpp', 'shvector.cpp', 'fresolver.cpp', 'rfilter.cpp',
'quad.cpp', 'mmap.cpp', 'chisquare.cpp', 'warp.cpp', 'vmf.cpp',
'tls.cpp', 'ssemath.cpp'

View File

@ -1,8 +1,8 @@
Import('env', 'sys', 'os')
libhw_objects = [
'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp',
'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.cpp',
'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp',
'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.cpp',
'glgeometry.cpp', 'gltexture.cpp', 'gpusync.cpp', 'glsync.cpp',
'vpl.cpp', 'font.cpp', 'viewer.cpp', 'basicshader.cpp', 'shadow.cpp']
@ -14,7 +14,7 @@ if sys.platform == 'win32':
elif sys.platform == 'linux2':
libhw_objects += ['x11session.cpp',
'x11device.cpp',
'glxdevice.cpp',
'glxdevice.cpp',
'glxrenderer.cpp']
glEnv = env.Clone()

View File

@ -11,12 +11,12 @@ if renderEnv.has_key('XERCESLIB'):
librender = renderEnv.SharedLibrary('mitsuba-render', [
'bsdf.cpp', 'film.cpp', 'integrator.cpp', 'emitter.cpp', 'sensor.cpp',
'skdtree.cpp', 'medium.cpp', 'renderjob.cpp', 'imageproc.cpp',
'skdtree.cpp', 'medium.cpp', 'renderjob.cpp', 'imageproc.cpp',
'rectwu.cpp', 'renderproc.cpp', 'imageblock.cpp', 'particleproc.cpp',
'renderqueue.cpp', 'scene.cpp', 'subsurface.cpp', 'texture.cpp',
'shape.cpp', 'trimesh.cpp', 'sampler.cpp', 'util.cpp', 'irrcache.cpp',
'testcase.cpp', 'photonmap.cpp', 'gatherproc.cpp', 'volume.cpp',
'vpl.cpp', 'shader.cpp', 'scenehandler.cpp', 'intersection.cpp',
'renderqueue.cpp', 'scene.cpp', 'subsurface.cpp', 'texture.cpp',
'shape.cpp', 'trimesh.cpp', 'sampler.cpp', 'util.cpp', 'irrcache.cpp',
'testcase.cpp', 'photonmap.cpp', 'gatherproc.cpp', 'volume.cpp',
'vpl.cpp', 'shader.cpp', 'scenehandler.cpp', 'intersection.cpp',
'track.cpp', 'common.cpp', 'phase.cpp', 'noise.cpp', 'photon.cpp'
])

View File

@ -31,6 +31,7 @@
#include <mitsuba/core/fresolver.h>
#include <mitsuba/render/scene.h>
#include <boost/algorithm/string.hpp>
#include <Eigen/SVD>
MTS_NAMESPACE_BEGIN
XERCES_CPP_NAMESPACE_USE
@ -97,6 +98,7 @@ SceneHandler::SceneHandler(const SAXParser *parser,
m_tags["blackbody"] = TagEntry(EBlackBody, (Class *) NULL);
m_tags["spectrum"] = TagEntry(ESpectrum, (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["alias"] = TagEntry(EAlias, (Class *) NULL);
@ -167,11 +169,12 @@ void SceneHandler::characters(const XMLCh* const name,
Float SceneHandler::parseFloat(const std::string &name,
const std::string &str, Float defVal) const {
char *end_ptr = NULL;
if (str == "") {
if (str.empty()) {
if (defVal == -1)
XMLLog(EError, "Missing floating point value (in <%s>)", name.c_str());
return defVal;
}
Float result = (Float) std::strtod(str.c_str(), &end_ptr);
if (*end_ptr != '\0')
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:
m_transform = Transform();
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:
break;
}
@ -575,9 +591,56 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
}
break;
case EAnimation: {
m_animatedTransform->sortAndSimplify();
// context.parent->properties.setAnimatedTransform(
// context.attributes["name"], m_animatedTransform);//XXX
m_animatedTransform = NULL;
}
break;
case ETransform: {
context.parent->properties.setTransform(
context.attributes["name"], m_transform);
if (!m_animatedTransform.get()) {
context.parent->properties.setTransform(
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;

View File

@ -48,16 +48,7 @@ void AnimatedTransform::addTrack(AbstractAnimationTrack *track) {
AABB1 AnimatedTransform::getTimeBounds() const {
if (m_tracks.size() == 0)
#if !defined(__clang__)
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 max = -std::numeric_limits<Float>::infinity();
@ -70,15 +61,7 @@ AABB1 AnimatedTransform::getTimeBounds() const {
max = std::max(max, track->getTime(size-1));
}
#if !defined(__clang__)
return AABB1(min, max);
#else
// HACK Workaround for clang
AABB1 b;
b.min = min;
b.max = max;
return b;
#endif
}
AABB AnimatedTransform::getTranslationBounds() const {
@ -152,6 +135,53 @@ AnimatedTransform::~AnimatedTransform() {
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 {
stream->writeSize(m_tracks.size());
if (m_tracks.size() == 0) {

View File

@ -1,4 +1,4 @@
Import('env', 'os', 'glob', 'sys', 'hasQt', 'hasCollada', 'hasBreakpad', 'mainEnv',
Import('env', 'os', 'glob', 'sys', 'hasQt', 'hasCollada', 'hasBreakpad', 'mainEnv',
'resources', 'converter_objects')
# For running Uic & Moc (below)
@ -59,7 +59,7 @@ if hasQt:
qtEnv.Prepend(LIBPATH=env['COLLADALIBDIR'])
if env.has_key('COLLADALIB'):
qtEnv.Prepend(LIBS=env['COLLADALIB'])
if sys.platform == 'darwin':
mainEnv_osx = mainEnv.Clone()
qtEnv_osx = qtEnv.Clone()

View File

@ -495,7 +495,7 @@ public:
void getNormalDerivative(const Intersection &its,
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);
}

View File

@ -9,7 +9,7 @@ bidirEnv.Append(LIBPATH=['#src/libbidir'])
for plugin in glob.glob(GetBuildPath('test_*.cpp')):
name = os.path.basename(plugin)
if "bidir" in name:
if "bidir" in name:
lib = bidirEnv.SharedLibrary(name[0:len(name)-4], name)
else:
lib = testEnv.SharedLibrary(name[0:len(name)-4], name)