diff --git a/SConstruct b/SConstruct index ef00758e..89f05b0e 100644 --- a/SConstruct +++ b/SConstruct @@ -530,6 +530,7 @@ plugins += env.SharedLibrary('plugins/cylinder', ['src/shapes/cylinder.cpp']) plugins += env.SharedLibrary('plugins/hair', ['src/shapes/hair.cpp']) plugins += env.SharedLibrary('plugins/shapegroup', ['src/shapes/shapegroup.cpp']) plugins += env.SharedLibrary('plugins/instance', ['src/shapes/instance.cpp']) +plugins += env.SharedLibrary('plugins/animatedinstance', ['src/shapes/animatedinstance.cpp']) # Samplers plugins += env.SharedLibrary('plugins/independent', ['src/samplers/independent.cpp']) diff --git a/include/mitsuba/core/quat.h b/include/mitsuba/core/quat.h index 9121958f..a642e46d 100644 --- a/include/mitsuba/core/quat.h +++ b/include/mitsuba/core/quat.h @@ -295,12 +295,19 @@ template struct TQuaternion { m.m[0][0] = 1.f - 2.f * (yy + zz); m.m[0][1] = 2.f * (xy + wz); m.m[0][2] = 2.f * (xz - wy); + m.m[0][3] = 0.0f; m.m[1][0] = 2.f * (xy - wz); m.m[1][1] = 1.f - 2.f * (xx + zz); m.m[1][2] = 2.f * (yz + wx); + m.m[1][3] = 0.0f; m.m[2][0] = 2.f * (xz + wy); m.m[2][1] = 2.f * (yz - wx); m.m[2][2] = 1.f - 2.f * (xx + yy); + m.m[2][3] = 0.0f; + m.m[3][0] = 0.0f; + m.m[3][1] = 0.0f; + m.m[3][2] = 0.0f; + m.m[3][3] = 1.0f; Matrix4x4 transp; m.transpose(transp); diff --git a/include/mitsuba/render/kdtree.h b/include/mitsuba/render/kdtree.h index 796ffcf3..ab5ffa90 100644 --- a/include/mitsuba/render/kdtree.h +++ b/include/mitsuba/render/kdtree.h @@ -65,6 +65,7 @@ MTS_NAMESPACE_BEGIN class MTS_EXPORT_RENDER KDTree : public GenericKDTree { friend class GenericKDTree; friend class Instance; + friend class AnimatedInstance; public: /// Create an empty kd-tree KDTree(); diff --git a/include/mitsuba/render/track.h b/include/mitsuba/render/track.h index cd1a182e..2df8bcad 100644 --- a/include/mitsuba/render/track.h +++ b/include/mitsuba/render/track.h @@ -87,6 +87,7 @@ public: /// Serialize to a binary data stream void serialize(Stream *stream) const { + stream->writeUInt(m_type); stream->writeUInt((uint32_t) m_times.size()); stream->writeFloatArray(&m_times[0], m_times.size()); for (size_t i=0; i 0); std::vector::const_iterator entry = std::lower_bound(m_times.begin(), m_times.end(), time); int idx0 = (int) (entry - m_times.begin()) - 1; @@ -172,11 +174,25 @@ public: void addTrack(AbstractAnimationTrack *track); /// Compute the transformation at the specified time value - void eval(Float t, Transform &trafo); + void eval(Float t, Transform &trafo) const; /// Serialize to a binary data stream void serialize(Stream *stream) const; + /// Return the extents along the time axis + void computeTimeBounds(Float &min, Float &max) const { + min = std::numeric_limits::infinity(); + max = -std::numeric_limits::infinity(); + + for (size_t i=0; igetSize(); + SAssert(size > 0); + min = std::min(min, track->getTime(0)); + max = std::max(max, track->getTime(size-1)); + } + } + MTS_DECLARE_CLASS() protected: /// Virtual destructor diff --git a/src/converter/collada.cpp b/src/converter/collada.cpp index 488e2e3d..d6c69bc2 100644 --- a/src/converter/collada.cpp +++ b/src/converter/collada.cpp @@ -1504,7 +1504,7 @@ void mergeRotations(ColladaContext &ctx) { it2 != times.end(); ++it2) { Float time = *it2, rot[3]; for (int i=0; i<3; ++i) - rot[i] = tracks[i] ? tracks[i]->eval(time) : (Float) 0; + rot[i] = tracks[i] ? (tracks[i]->eval(time) * (M_PI/180)) : (Float) 0; newTrack->setTime(idx, time); newTrack->setValue(idx, Quaternion::fromEulerAngles( @@ -1532,8 +1532,7 @@ GLvoid __stdcall tessVertex(void *data) { GLvoid __stdcall tessCombine(GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData) { - const domUint **raw = (const domUint **) vertex_data; - domUint *result = new domUint[tess_nSources]; + domUint *result = new domUint[tess_nSources], size = 0; tess_cleanup.push_back(result); for (size_t i=0; itypeToOffsetInStream[j] == (int) i) { offset = tess_vdata->typeToOffset[j]; + size = tess_vdata->typeToCount[j]; found = true; break; } @@ -1549,14 +1549,16 @@ GLvoid __stdcall tessCombine(GLdouble coords[3], void *vertex_data[4], SAssert(found); // this will be very slow -- let's hope that it happens rarely - domUint size = tess_vdata->typeToCount[offset]; Vec4 *oldVec = tess_vdata->data[offset]; Vec4 *newVec = new Vec4[size+1]; memcpy(newVec, oldVec, size * sizeof(Vec4)); newVec[size] = Vec4(0.0f); for (int j=0; j<4; ++j) { - domUint idx = raw[j][i]; + void *ptr = vertex_data[j]; + if (!ptr) + continue; + domUint idx = ((domUint *) ptr)[i]; newVec[size] += newVec[idx] * weight[j]; } tess_vdata->data[offset] = newVec; diff --git a/src/librender/track.cpp b/src/librender/track.cpp index e51383f9..b30ab540 100644 --- a/src/librender/track.cpp +++ b/src/librender/track.cpp @@ -7,7 +7,7 @@ AnimatedTransform::AnimatedTransform(Stream *stream) { for (size_t i=0; ireadUInt(); - + AbstractAnimationTrack *track = NULL; switch (type) { case AbstractAnimationTrack::ETranslationX: case AbstractAnimationTrack::ETranslationY: @@ -18,18 +18,21 @@ AnimatedTransform::AnimatedTransform(Stream *stream) { case AbstractAnimationTrack::ERotationX: case AbstractAnimationTrack::ERotationY: case AbstractAnimationTrack::ERotationZ: - m_tracks.push_back(new FloatTrack(type, stream)); + track = new FloatTrack(type, stream); break; case AbstractAnimationTrack::ETranslationXYZ: case AbstractAnimationTrack::EScaleXYZ: - m_tracks.push_back(new VectorTrack(type, stream)); + track = new VectorTrack(type, stream); break; case AbstractAnimationTrack::ERotationQuat: - m_tracks.push_back(new QuatTrack(type, stream)); + track = new QuatTrack(type, stream); break; default: - Log(EError, "Encountered an unknown animation track type!"); + Log(EError, "Encountered an unknown animation track type (%i)!", type); } + + track->incRef(); + m_tracks.push_back(track); } } @@ -50,7 +53,7 @@ void AnimatedTransform::serialize(Stream *stream) const { } /// Compute the transformation at the specified time value -void AnimatedTransform::eval(Float t, Transform &trafo) { +void AnimatedTransform::eval(Float t, Transform &trafo) const { Vector translation(0.0f); Vector scale(1.0f); Quaternion rotation; @@ -90,8 +93,11 @@ void AnimatedTransform::eval(Float t, Transform &trafo) { "animation track type: %i!", track->getType()); } } + //cout << "T:" << translation.toString() << " R:" << rotation.toString() << " S:" << scale.toString() << endl; + trafo = Transform::translate(translation) * - rotation.toTransform() * Transform::scale(scale); + rotation.toTransform() * + Transform::scale(scale); } MTS_IMPLEMENT_CLASS(AbstractAnimationTrack, true, Object) diff --git a/src/shapes/animatedinstance.cpp b/src/shapes/animatedinstance.cpp new file mode 100644 index 00000000..4b9b594c --- /dev/null +++ b/src/shapes/animatedinstance.cpp @@ -0,0 +1,140 @@ +/* + This file is part of Mitsuba, a physically based rendering system. + + Copyright (c) 2007-2010 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 . +*/ + +#include +#include +#include +#include "shapegroup.h" + +MTS_NAMESPACE_BEGIN + +#define TIME 0 + +class AnimatedInstance : public Shape { +public: + AnimatedInstance(const Properties &props) : Shape(props) { + FileResolver *fResolver = Thread::getThread()->getFileResolver(); + fs::path path = fResolver->resolve(props.getString("filename")); + m_name = path.filename(); + + Log(EInfo, "Loading animation track from \"%s\"", m_name.c_str()); + ref fs = new FileStream(path, FileStream::EReadOnly); + m_transform = new AnimatedTransform(fs); + } + + AnimatedInstance(Stream *stream, InstanceManager *manager) + : Shape(stream, manager) { + m_shapeGroup = static_cast(manager->getInstance(stream)); + m_transform = new AnimatedTransform(stream); + } + + void serialize(Stream *stream, InstanceManager *manager) const { + Shape::serialize(stream, manager); + manager->serialize(stream, m_shapeGroup.get()); + m_transform->serialize(stream); + } + + void configure() { + if (!m_shapeGroup) + Log(EError, "A reference to a 'shapegroup' must be specified!"); + const KDTree *kdtree = m_shapeGroup->getKDTree(); + const AABB &aabb = kdtree->getAABB(); + Float minT, maxT; + m_transform->computeTimeBounds(minT, maxT); + + /* Compute approximate bounds */ + int nSteps = 100; + Float step = (maxT-minT) / (nSteps-1); + Transform objectToWorld; + + for (int i=0; ieval(minT + step * i, objectToWorld); + for (int j=0; j<8; ++j) + m_aabb.expandBy(objectToWorld(aabb.getCorner(j))); + } + } + + AABB getAABB() const { + return m_aabb; + } + + std::string getName() const { + return m_name; + } + + Float getSurfaceArea() const { + Log(EError, "AnimatedInstance::getSurfaceArea(): not supported!"); + return 0.0f; + } + + void addChild(const std::string &name, ConfigurableObject *child) { + const Class *cClass = child->getClass(); + if (cClass->getName() == "ShapeGroup") { + m_shapeGroup = static_cast(child); + } else { + Shape::addChild(name, child); + } + } + + bool rayIntersect(const Ray &_ray, Float mint, + Float maxt, Float &t, void *temp) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + Transform objectToWorld, worldToObject; + m_transform->eval(TIME, objectToWorld); + worldToObject = objectToWorld.inverse(); + worldToObject(_ray, ray); + return kdtree->rayIntersect(ray, mint, maxt, t, temp); + } + + bool rayIntersect(const Ray &_ray, Float mint, Float maxt) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Ray ray; + Transform objectToWorld, worldToObject; + m_transform->eval(TIME, objectToWorld); + worldToObject = objectToWorld.inverse(); + worldToObject(_ray, ray); + return kdtree->rayIntersect(ray, mint, maxt); + } + + void fillIntersectionRecord(const Ray &ray, + const void *temp, Intersection &its) const { + const KDTree *kdtree = m_shapeGroup->getKDTree(); + Transform objectToWorld; + m_transform->eval(TIME, objectToWorld); + kdtree->fillIntersectionRecord(ray, temp, its); + its.shFrame.n = normalize(objectToWorld(its.shFrame.n)); + its.shFrame.s = normalize(objectToWorld(its.shFrame.s)); + its.shFrame.t = normalize(objectToWorld(its.shFrame.t)); + its.geoFrame = Frame(normalize(objectToWorld(its.geoFrame.n))); + its.wi = its.shFrame.toLocal(-ray.d); + its.dpdu = objectToWorld(its.dpdu); + its.dpdv = objectToWorld(its.dpdv); + } + + MTS_DECLARE_CLASS() +private: + ref m_shapeGroup; + ref m_transform; + AABB m_aabb; + std::string m_name; +}; + +MTS_IMPLEMENT_CLASS_S(AnimatedInstance, false, Shape) +MTS_EXPORT_PLUGIN(AnimatedInstance, "AnimatedInstanced geometry"); +MTS_NAMESPACE_END