diff --git a/include/mitsuba/core/ray.h b/include/mitsuba/core/ray.h index 87c42909..5aea908f 100644 --- a/include/mitsuba/core/ray.h +++ b/include/mitsuba/core/ray.h @@ -31,24 +31,27 @@ struct Ray { Vector d; ///< Ray direction Float maxt; ///< Maximum range for intersection tests Vector dRcp; ///< Componentwise reciprocals of the ray direction + Float time; ///< Time value associated with this ray /// Construct a new ray - inline Ray() : mint(Epsilon), maxt(std::numeric_limits::infinity()) { + inline Ray() : mint(Epsilon), + maxt(std::numeric_limits::infinity()), time(0.0f) { } /// Copy constructor (1) inline Ray(const Ray &ray) - : o(ray.o), mint(ray.mint), d(ray.d), maxt(ray.maxt), dRcp(ray.dRcp) { + : o(ray.o), mint(ray.mint), d(ray.d), maxt(ray.maxt), + dRcp(ray.dRcp), time(ray.time) { } /// Copy constructor (2) inline Ray(const Ray &ray, Float mint, Float maxt) - : o(ray.o), mint(mint), d(ray.d), maxt(maxt), dRcp(ray.dRcp) { + : o(ray.o), mint(mint), d(ray.d), maxt(maxt), dRcp(ray.dRcp), time(ray.time) { } - + /// Construct a new ray - inline Ray(Point o, Vector _d) - : o(o), mint(Epsilon), d(_d), maxt(std::numeric_limits::infinity()) { + inline Ray(Point o, Vector _d, Float time) + : o(o), mint(Epsilon), d(_d), maxt(std::numeric_limits::infinity()), time(time) { #ifdef MTS_DEBUG_FP disable_fpexcept(); #endif @@ -61,8 +64,8 @@ struct Ray { } /// Construct a new ray - inline Ray(Point o, Vector _d, Float mint, Float maxt) - : o(o), mint(mint), d(_d), maxt(maxt) { + inline Ray(Point o, Vector _d, Float mint, Float maxt, Float time) + : o(o), mint(mint), d(_d), maxt(maxt), time(time) { #ifdef MTS_DEBUG_FP disable_fpexcept(); #endif @@ -76,6 +79,9 @@ struct Ray { /// Set the origin inline void setOrigin(const Point &oVal) { o = oVal; } + + /// Set the origin + inline void setTime(const Float &tval) { time = tval; } /// Set the direction and update the reciprocal inline void setDirection(const Vector &dVal) { @@ -97,7 +103,8 @@ struct Ray { /// Return a string representation of this ray inline std::string toString() const { std::ostringstream oss; - oss << "Ray[orig=" << o.toString() << ", dest=" << d.toString() << "]"; + oss << "Ray[orig=" << o.toString() << ", dest=" + << d.toString() << ", time=" << time << "]"; return oss.str(); } }; @@ -112,8 +119,8 @@ struct RayDifferential : public Ray { : hasDifferentials(false) { } - inline RayDifferential(const Point &p, const Vector &d) - : Ray(p, d), hasDifferentials(false) { + inline RayDifferential(const Point &p, const Vector &d, Float time) + : Ray(p, d, time), hasDifferentials(false) { } inline explicit RayDifferential(const Ray &ray) diff --git a/include/mitsuba/core/transform.h b/include/mitsuba/core/transform.h index 91a7e8a6..c2202081 100644 --- a/include/mitsuba/core/transform.h +++ b/include/mitsuba/core/transform.h @@ -310,6 +310,7 @@ public: 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 enable_fpexcept(); #endif diff --git a/include/mitsuba/render/camera.h b/include/mitsuba/render/camera.h index 33528b1b..31320e42 100644 --- a/include/mitsuba/render/camera.h +++ b/include/mitsuba/render/camera.h @@ -31,11 +31,11 @@ class MTS_EXPORT_RENDER Camera : public ConfigurableObject { public: /// Create a ray from the given sample virtual void generateRay(const Point2 &sample, const Point2 &lensSample, - Ray &ray) const = 0; + Float timeSample, Ray &ray) const = 0; /// Create ray differentials from the given sample void generateRayDifferential(const Point2 &sample, - const Point2 &lensSample, RayDifferential &ray) const; + const Point2 &lensSample, Float timeSample, RayDifferential &ray) const; /** * Turn a world-space position into fractional pixel coordinates. @@ -46,6 +46,9 @@ public: /// Does generateRay() expect a proper lens sample? virtual bool needsLensSample() const = 0; + + /// Does generateRay() expect a proper time sample? + inline bool needsTimeSample() const { return m_shutterOpenTime > 0; } /// Return the camera position (approximate in the case of finite sensor area) inline const Point &getPosition() const { return m_position; } @@ -81,11 +84,20 @@ public: */ inline const Sampler *getSampler() const { return m_sampler.get(); } + /// Return the time value of the shutter opening event + inline Float getShutterOpen() const { return m_shutterOpen; } + + /// Return the length, for which the shutter remains open + inline Float getShutterOpenTime() const { return m_shutterOpenTime; } + + /// Return the time value of the shutter closing event + inline Float getShutterClose() const { return m_shutterOpen; } + /// Return the image plane normal inline Normal getImagePlaneNormal() const { return Normal(normalize(m_cameraToWorld(Vector(0, 0, 1)))); } - + /// Return the view transformation inline const Transform &getViewTransform() const { return m_worldToCamera; } @@ -143,6 +155,7 @@ protected: Transform m_worldToCamera, m_cameraToWorld; Point m_position; Properties m_properties; + Float m_shutterOpen, m_shutterClose, m_shutterOpenTime; }; class MTS_EXPORT_RENDER ProjectiveCamera : public Camera { diff --git a/include/mitsuba/render/gkdtree.h b/include/mitsuba/render/gkdtree.h index f1799131..c6317cfd 100644 --- a/include/mitsuba/render/gkdtree.h +++ b/include/mitsuba/render/gkdtree.h @@ -3163,7 +3163,7 @@ template sample2(random->nextFloat(), random->nextFloat()); Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius; Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius; - Ray ray(p1, normalize(p2-p1)); + Ray ray(p1, normalize(p2-p1), 0.0f); Float mint, maxt, t; if (this->m_aabb.rayIntersect(ray, mint, maxt)) { if (ray.mint > mint) mint = ray.mint; diff --git a/include/mitsuba/render/integrator.h b/include/mitsuba/render/integrator.h index 1bb79903..7a2eeff3 100644 --- a/include/mitsuba/render/integrator.h +++ b/include/mitsuba/render/integrator.h @@ -288,7 +288,7 @@ public: * cosine-weighted sampling and a configurable number of rays. */ virtual Spectrum E(const Scene *scene, const Point &p, const - Normal &n, Sampler *sampler) const; + Normal &n, Float time, Sampler *sampler) const; /** * Perform the main rendering task. The work is automatically diff --git a/include/mitsuba/render/kdtree.h b/include/mitsuba/render/kdtree.h index ab5ffa90..182d95b8 100644 --- a/include/mitsuba/render/kdtree.h +++ b/include/mitsuba/render/kdtree.h @@ -353,6 +353,7 @@ protected: shape->fillIntersectionRecord(ray, reinterpret_cast(temp) + 8, its); } + its.time = ray.time; } /// Plain shadow ray query (used by the 'instance' plugin) diff --git a/include/mitsuba/render/particleproc.h b/include/mitsuba/render/particleproc.h index 1011376b..43c7481d 100644 --- a/include/mitsuba/render/particleproc.h +++ b/include/mitsuba/render/particleproc.h @@ -106,7 +106,7 @@ public: * which occurred while tracing particles. */ virtual void handleMediumInteraction(int depth, bool caustic, - const MediumSamplingRecord &mRec, const Vector &wi, + const MediumSamplingRecord &mRec, Float time, const Vector &wi, const Spectrum &weight); MTS_DECLARE_CLASS() diff --git a/include/mitsuba/render/records.inl b/include/mitsuba/render/records.inl index 02215b2f..9592695c 100644 --- a/include/mitsuba/render/records.inl +++ b/include/mitsuba/render/records.inl @@ -64,7 +64,7 @@ inline bool RadianceQueryRecord::rayIntersect(const RayDifferential &ray) { /* Only search for an intersection if this was explicitly requested */ if (type & EIntersection) { scene->rayIntersect(ray, its); - attenuation = scene->getAttenuation(Ray(ray.o, ray.d, 0, its.t)); + attenuation = scene->getAttenuation(Ray(ray.o, ray.d, 0, its.t, ray.time)); if (type & EOpacity) alpha = its.isValid() ? 1 : (1 - attenuation.average()); if (type & EDistance) diff --git a/include/mitsuba/render/scene.h b/include/mitsuba/render/scene.h index cd952289..c04422ba 100644 --- a/include/mitsuba/render/scene.h +++ b/include/mitsuba/render/scene.h @@ -131,8 +131,8 @@ public: } /// Cast a shadow ray - inline bool isOccluded(const Point &p1, const Point &p2) const { - Ray ray(p1, p2-p1); + inline bool isOccluded(const Point &p1, const Point &p2, Float time) const { + Ray ray(p1, p2-p1, time); ray.mint = ShadowEpsilon; ray.maxt = 1-ShadowEpsilon; return m_kdtree->rayIntersect(ray); @@ -155,6 +155,9 @@ public: * @param lRec * A luminaire sampling record, which will hold information such as the * probability density, associated measure etc. + * @param time + * Associated time value -- this is needed to check the visibility when + * objects are potentially moving over time * @param testVisibility * If this is true, a shadow-ray will be cast to ensure that no surface * blocks the path lRec.sRec.p <-> p. @@ -162,7 +165,8 @@ public: * true if sampling was successful */ bool sampleLuminaire(const Point &p, - LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const; + LuminaireSamplingRecord &lRec, Float time, + const Point2 &sample, bool testVisibility = true) const; /** * Sample a visible point on a luminaire (ideally uniform wrt. the solid angle of p). Takes @@ -186,9 +190,10 @@ public: * lRec.Le by the integrated extinction coefficient on the path lRec.sRec.p <-> p. */ inline bool sampleLuminaireAttenuated(const Point &p, - LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const { - if (sampleLuminaire(p, lRec, sample, testVisibility)) { - lRec.Le *= getAttenuation(Ray(p, lRec.sRec.p-p, 0, 1)); + LuminaireSamplingRecord &lRec, Float time, + const Point2 &sample, bool testVisibility = true) const { + if (sampleLuminaire(p, lRec, time, sample, testVisibility)) { + lRec.Le *= getAttenuation(Ray(p, lRec.sRec.p-p, 0, 1, 0)); return true; } return false; @@ -201,7 +206,7 @@ public: inline bool sampleLuminaireAttenuated(const Intersection &its, LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const { if (sampleLuminaire(its, lRec, sample, testVisibility)) { - lRec.Le *= getAttenuation(Ray(its.p, lRec.sRec.p-its.p, 0, 1)); + lRec.Le *= getAttenuation(Ray(its.p, lRec.sRec.p-its.p, 0, 1, 0)); return true; } return false; diff --git a/include/mitsuba/render/shape.h b/include/mitsuba/render/shape.h index 4edc19fe..a90f3275 100644 --- a/include/mitsuba/render/shape.h +++ b/include/mitsuba/render/shape.h @@ -132,6 +132,9 @@ public: /// Texture coordinate mapping partials wrt. changes in screen-space Float dudx, dudy, dvdx, dvdy; + /// Time value associated with the intersection + Float time; + /// Interpolated vertex color Spectrum color; diff --git a/src/cameras/orthographic.cpp b/src/cameras/orthographic.cpp index c9f88c75..765b7cf1 100644 --- a/src/cameras/orthographic.cpp +++ b/src/cameras/orthographic.cpp @@ -104,13 +104,14 @@ public: } void generateRay(const Point2 &dirSample, const Point2 &lensSample, - Ray &ray) const { + Float timeSample, Ray &ray) const { Point rasterCoords(dirSample.x, dirSample.y, 0); Point imageCoords; m_rasterToCamera(rasterCoords, imageCoords); /* Construct ray in camera space */ - Ray localRay(imageCoords, Vector(0, 0, 1)); + Ray localRay(imageCoords, Vector(0, 0, 1), + m_shutterOpen + m_shutterOpenTime * timeSample); localRay.mint = 0; localRay.maxt = m_farClip - m_nearClip; @@ -154,6 +155,8 @@ public: << " aspect = " << m_aspect << "," << std::endl << " nearClip = " << m_nearClip << "," << std::endl << " farClip = " << m_farClip << "," << std::endl + << " shutterOpen = " << m_shutterOpen << "," << std::endl + << " shutterClose = " << m_shutterClose << "," << std::endl << " areaDensity = " << m_areaDensity << "," << std::endl << " cameraToWorld = " << indent(m_cameraToWorld.toString()) << "," << std::endl << " cameraToScreen = " << indent(m_cameraToScreen.toString()) << "," << std::endl diff --git a/src/cameras/perspective.cpp b/src/cameras/perspective.cpp index bfc6fd4d..56908e5e 100644 --- a/src/cameras/perspective.cpp +++ b/src/cameras/perspective.cpp @@ -109,15 +109,16 @@ public: return m_lensRadius > 0.0f; } - void generateRay(const Point2 &dirSample, const Point2 &lensSample, - Ray &ray) const { + void generateRay(const Point2 &dirSample, const Point2 &lensSample, + Float timeSample, Ray &ray) const { /* Calculate intersection on the image plane */ Point rasterCoords(dirSample.x, dirSample.y, 0); Point imageCoords; m_rasterToCamera(rasterCoords, imageCoords); /* Construct ray in camera space */ - Ray localRay(Point(0, 0, 0), Vector(imageCoords)); + Ray localRay(Point(0, 0, 0), Vector(imageCoords), + m_shutterOpen + m_shutterOpenTime * timeSample); if (m_lensRadius > 0.0f) { /* Sample a point on the aperture */ @@ -184,6 +185,8 @@ public: << " yfov = " << m_yfov << "," << std::endl << " nearClip = " << m_nearClip << "," << std::endl << " farClip = " << m_farClip << "," << std::endl + << " shutterOpen = " << m_shutterOpen << "," << std::endl + << " shutterClose = " << m_shutterClose << "," << std::endl << " lensRadius = " << m_lensRadius << "," << std::endl << " focalDistance = " << m_focalDistance << "," << std::endl << " cameraToWorld = " << indent(m_cameraToWorld.toString()) << "," << std::endl diff --git a/src/integrators/direct/direct.cpp b/src/integrators/direct/direct.cpp index f4749baa..3665920c 100644 --- a/src/integrators/direct/direct.cpp +++ b/src/integrators/direct/direct.cpp @@ -168,7 +168,7 @@ public: bsdfVal /= bsdfPdf; /* Trace a ray in this direction */ - Ray bsdfRay(its.p, its.toWorld(bRec.wo)); + Ray bsdfRay(its.p, its.toWorld(bRec.wo), ray.time); bool hitLuminaire = false; if (scene->rayIntersect(bsdfRay, bsdfIts)) { bsdfRay.mint = 0; bsdfRay.maxt = bsdfIts.t; diff --git a/src/integrators/misc/errctrl.cpp b/src/integrators/misc/errctrl.cpp index 96d3a2fe..80c57230 100644 --- a/src/integrators/misc/errctrl.cpp +++ b/src/integrators/misc/errctrl.cpp @@ -103,8 +103,9 @@ public: Vector2i filmSize = camera->getFilm()->getSize(); bool needsLensSample = camera->needsLensSample(); + bool needsTimeSample = camera->needsTimeSample(); const int nSamples = 10000; - Float luminance = 0; + Float luminance = 0, timeSample = 0; RadianceQueryRecord rRec(scene, sampler); for (int i=0; igenerateRayDifferential(sample, lensSample, eyeRay); + camera->generateRayDifferential(sample, lensSample, timeSample, eyeRay); luminance += m_subIntegrator->Li(eyeRay, rRec).getLuminance(); } @@ -130,13 +133,14 @@ public: void renderBlock(const Scene *scene, const Camera *camera, Sampler *sampler, ImageBlock *block, const bool &stop) const { bool needsLensSample = camera->needsLensSample(); + bool needsTimeSample = camera->needsTimeSample(); const TabulatedFilter *filter = camera->getFilm()->getTabulatedFilter(); Float mean, meanSqr; Point2 sample, lensSample; RayDifferential eyeRay; int x, y; - Float sampleLuminance; + Float sampleLuminance, timeSample = 0; RadianceQueryRecord rRec(scene, sampler); int sampleIndex; @@ -157,10 +161,12 @@ public: rRec.newQuery(RadianceQueryRecord::ECameraRay); if (needsLensSample) lensSample = rRec.nextSample2D(); + if (needsTimeSample) + timeSample = rRec.nextSample1D(); sample = rRec.nextSample2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, - lensSample, eyeRay); + lensSample, timeSample, eyeRay); Spectrum sampleValue = m_subIntegrator->Li(eyeRay, rRec); @@ -217,8 +223,8 @@ public: return m_subIntegrator->Li(ray, rRec); } - Spectrum E(const Scene *scene, const Point &p, const Normal &n, Sampler *sampler) const { - return m_subIntegrator->E(scene, p, n, sampler); + Spectrum E(const Scene *scene, const Point &p, const Normal &n, Float time, Sampler *sampler) const { + return m_subIntegrator->E(scene, p, n, time, sampler); } void serialize(Stream *stream, InstanceManager *manager) const { diff --git a/src/integrators/misc/irrcache.cpp b/src/integrators/misc/irrcache.cpp index a6635c89..7fb348b1 100644 --- a/src/integrators/misc/irrcache.cpp +++ b/src/integrators/misc/irrcache.cpp @@ -277,7 +277,7 @@ public: RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance); rRec2.extra = 1; rRec2.sampler = sampler; - entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d), rRec2); + entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d, ray.time), rRec2); entry.dist = rRec2.dist; sampler->advance(); } @@ -288,7 +288,7 @@ public: E = hs->getIrradiance(); } - Spectrum E(const Scene *scene, const Point &p, const Normal &n, Sampler *sampler) const { + Spectrum E(const Scene *scene, const Point &p, const Normal &n, Float time, Sampler *sampler) const { Spectrum EDir(0.0f), EIndir(0.0f); RadianceQueryRecord rRec(scene, sampler); LuminaireSamplingRecord lRec; @@ -297,7 +297,7 @@ public: for (unsigned int i=0; isampleLuminaireAttenuated(p, lRec, rRec.nextSample2D())) { + if (scene->sampleLuminaireAttenuated(p, lRec, time, rRec.nextSample2D())) { Float dp = dot(lRec.d, n); if (dp < 0) EDir -= lRec.Le * dp; diff --git a/src/integrators/misc/irrcache_proc.cpp b/src/integrators/misc/irrcache_proc.cpp index 621259d6..1bbac7bc 100644 --- a/src/integrators/misc/irrcache_proc.cpp +++ b/src/integrators/misc/irrcache_proc.cpp @@ -104,7 +104,7 @@ public: if (stop) break; Point2 sample(x + .5f, y + .5f); - m_camera->generateRayDifferential(sample, lensSample, eyeRay); + m_camera->generateRayDifferential(sample, lensSample, 0.0f, eyeRay); if (m_scene->rayIntersect(eyeRay, its)) { const BSDF *bsdf = its.shape->getBSDF(); if (!bsdf->getType() == BSDF::EDiffuseReflection) @@ -125,7 +125,7 @@ public: rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance); rRec.depth = 2; rRec.extra = 1; // mark as irradiance cache query - entry.L = integrator->Li(RayDifferential(its.p, entry.d), rRec); + entry.L = integrator->Li(RayDifferential(its.p, entry.d, 0.0f), rRec); entry.dist = rRec.dist; m_sampler->advance(); } diff --git a/src/integrators/path/path.cpp b/src/integrators/path/path.cpp index 79258939..1dcc1807 100644 --- a/src/integrators/path/path.cpp +++ b/src/integrators/path/path.cpp @@ -115,7 +115,7 @@ public: prevIts = its; /* Trace a ray in this direction */ - ray = Ray(its.p, its.toWorld(bRec.wo)); + ray = Ray(its.p, its.toWorld(bRec.wo), ray.time); bool hitLuminaire = false; if (scene->rayIntersect(ray, its)) { /* Intersected something - check if it was a luminaire */ diff --git a/src/integrators/path/ptracer_proc.cpp b/src/integrators/path/ptracer_proc.cpp index 9ed7fbc8..0afdf2ea 100644 --- a/src/integrators/path/ptracer_proc.cpp +++ b/src/integrators/path/ptracer_proc.cpp @@ -77,7 +77,7 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool, if (m_camera->positionToSample(its.p, screenSample)) { Point cameraPosition = m_camera->getPosition(screenSample); - if (m_scene->isOccluded(cameraPosition, its.p)) + if (m_scene->isOccluded(cameraPosition, its.p, its.time)) return; const BSDF *bsdf = its.shape->getBSDF(); @@ -94,7 +94,7 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool, importance = 1/m_camera->areaDensity(screenSample); /* Compute Le * importance and store it in an accumulation buffer */ - Ray ray(its.p, d, 0, dist); + Ray ray(its.p, d, 0, dist, its.time); Spectrum sampleVal = weight * bsdf->fCos(bRec) * m_scene->getAttenuation(ray) * importance; @@ -103,13 +103,13 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool, } void CaptureParticleWorker::handleMediumInteraction(int, bool, - const MediumSamplingRecord &mRec, const Vector &wi, + const MediumSamplingRecord &mRec, Float time, const Vector &wi, const Spectrum &weight) { Point2 screenSample; if (m_camera->positionToSample(mRec.p, screenSample)) { Point cameraPosition = m_camera->getPosition(screenSample); - if (m_scene->isOccluded(cameraPosition, mRec.p)) + if (m_scene->isOccluded(cameraPosition, mRec.p, time)) return; Vector wo = cameraPosition - mRec.p; @@ -122,7 +122,7 @@ void CaptureParticleWorker::handleMediumInteraction(int, bool, importance = 1/m_camera->areaDensity(screenSample); /* Compute Le * importance and store in accumulation buffer */ - Ray ray(mRec.p, wo, 0, dist); + Ray ray(mRec.p, wo, 0, dist, time); Spectrum sampleVal = weight * mRec.medium->getPhaseFunction()->f(mRec, wi, wo) * m_scene->getAttenuation(ray) * importance; diff --git a/src/integrators/path/ptracer_proc.h b/src/integrators/path/ptracer_proc.h index 6d6186f6..6079b6d3 100644 --- a/src/integrators/path/ptracer_proc.h +++ b/src/integrators/path/ptracer_proc.h @@ -103,7 +103,7 @@ public: * pixel of the accumulation buffer. */ void handleMediumInteraction(int depth, bool caustic, - const MediumSamplingRecord &mRec, const Vector &wi, + const MediumSamplingRecord &mRec, Float time, const Vector &wi, const Spectrum &weight); MTS_DECLARE_CLASS() diff --git a/src/integrators/path/volpath.cpp b/src/integrators/path/volpath.cpp index 3ba27287..ded564c2 100644 --- a/src/integrators/path/volpath.cpp +++ b/src/integrators/path/volpath.cpp @@ -81,7 +81,7 @@ public: /* Estimate the single scattering component if this is requested */ if (rRec.type & RadianceQueryRecord::EInscatteredDirectRadiance && - scene->sampleLuminaireAttenuated(mRec.p, lRec, rRec.nextSample2D())) { + scene->sampleLuminaireAttenuated(mRec.p, lRec, ray.time, rRec.nextSample2D())) { /* Evaluate the phase function */ Spectrum phaseVal = phase->f(mRec, -ray.d, -lRec.d); @@ -111,7 +111,7 @@ public: prevIts = its; /* Trace a ray in this direction */ - ray = Ray(mRec.p, wo); + ray = Ray(mRec.p, wo, ray.time); bool hitLuminaire = false; if (scene->rayIntersect(ray, its)) { /* Intersected something - check if it was a luminaire */ @@ -230,7 +230,7 @@ public: prevIts = its; /* Trace a ray in this direction */ - ray = Ray(its.p, its.toWorld(bRec.wo)); + ray = Ray(its.p, its.toWorld(bRec.wo), ray.time); bool hitLuminaire = false; if (scene->rayIntersect(ray, its)) { /* Intersected something - check if it was a luminaire */ diff --git a/src/integrators/path/volpath_simple.cpp b/src/integrators/path/volpath_simple.cpp index 164f07e7..2080fdac 100644 --- a/src/integrators/path/volpath_simple.cpp +++ b/src/integrators/path/volpath_simple.cpp @@ -77,7 +77,7 @@ public: /* Estimate the single scattering component if this is requested */ if (rRec.type & RadianceQueryRecord::EInscatteredDirectRadiance && - scene->sampleLuminaireAttenuated(mRec.p, lRec, rRec.nextSample2D())) { + scene->sampleLuminaireAttenuated(mRec.p, lRec, ray.time, rRec.nextSample2D())) { Li += pathThroughput * lRec.Le * phase->f(mRec, -ray.d, -lRec.d); } @@ -92,7 +92,7 @@ public: prevIts = its; /* Trace a ray in this direction */ - ray = Ray(mRec.p, wo); + ray = Ray(mRec.p, wo, ray.time); computeIntersection = true; /* ==================================================================== */ @@ -179,7 +179,7 @@ public: prevIts = its; /* Trace a ray in this direction */ - ray = Ray(its.p, its.toWorld(bRec.wo)); + ray = Ray(its.p, its.toWorld(bRec.wo), ray.time); computeIntersection = true; /* ==================================================================== */ diff --git a/src/integrators/photonmapper/photonmapper.cpp b/src/integrators/photonmapper/photonmapper.cpp index 61400b67..2fc15337 100644 --- a/src/integrators/photonmapper/photonmapper.cpp +++ b/src/integrators/photonmapper/photonmapper.cpp @@ -353,7 +353,7 @@ public: continue; rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadiance); - recursiveRay = Ray(its.p, its.toWorld(bRec.wo)); + recursiveRay = Ray(its.p, its.toWorld(bRec.wo), ray.time); Li += m_parentIntegrator->Li(recursiveRay, rRec2) * bsdfVal; } } @@ -370,7 +370,7 @@ public: Spectrum bsdfVal = bsdf->sampleCos(bRec); rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadianceNoEmission); - recursiveRay = Ray(its.p, its.toWorld(bRec.wo)); + recursiveRay = Ray(its.p, its.toWorld(bRec.wo), ray.time); Li += m_parentIntegrator->Li(recursiveRay, rRec2) * bsdfVal * weight; } } else { diff --git a/src/integrators/photonmapper/ppm.cpp b/src/integrators/photonmapper/ppm.cpp index 34021687..af942ccd 100644 --- a/src/integrators/photonmapper/ppm.cpp +++ b/src/integrators/photonmapper/ppm.cpp @@ -135,9 +135,11 @@ public: m_totalEmitted = 0; bool needsLensSample = camera->needsLensSample(); + bool needsTimeSample = camera->needsTimeSample(); Log(EInfo, "Creating approximately %i gather points", cropSize.x*cropSize.y*sampleCount); Point2 lensSample, sample; RayDifferential eyeRay; + Float timeSample = 0; m_filter = camera->getFilm()->getTabulatedFilter(); Vector2 filterSize = m_filter->getFilterSize(); int borderSize = (int) std::ceil(std::max(filterSize.x, filterSize.y)); @@ -179,10 +181,12 @@ public: for (uint64_t j = 0; jnext2D(); + if (needsTimeSample) + timeSample = cameraSampler->next1D(); sample = cameraSampler->next2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, - lensSample, eyeRay); + lensSample, timeSample, eyeRay); size_t offset = gatherPoints.size(); int count = createGatherPoints(scene, eyeRay, sample, Spectrum(1.0f), gatherPoints, 1); @@ -240,7 +244,7 @@ public: continue; bsdfVal = bsdf->fDelta(bRec); - RayDifferential recursiveRay(p.its.p, p.its.toWorld(bRec.wo)); + RayDifferential recursiveRay(p.its.p, p.its.toWorld(bRec.wo), ray.time); count += createGatherPoints(scene, recursiveRay, sample, weight * bsdfVal, gatherPoints, depth+1); } diff --git a/src/integrators/photonmapper/sppm.cpp b/src/integrators/photonmapper/sppm.cpp index 378ad3e3..476651a3 100644 --- a/src/integrators/photonmapper/sppm.cpp +++ b/src/integrators/photonmapper/sppm.cpp @@ -169,6 +169,7 @@ public: void distributedRTPass(Scene *scene, std::vector &samplers) { ref camera = scene->getCamera(); bool needsLensSample = camera->needsLensSample(); + bool needsTimeSample = camera->needsTimeSample(); ref film = camera->getFilm(); Vector2i cropSize = film->getCropSize(); Point2i cropOffset = film->getCropOffset(); @@ -191,16 +192,19 @@ public: for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) { if (xofsInt + xofs - cropOffset.x >= cropSize.x) continue; - Point2 lensSample, sample; + Point2 lensSample, sample; + Float timeSample = 0.0f; GatherPoint &gatherPoint = gatherPoints[index++]; sampler->generate(); if (needsLensSample) lensSample = sampler->next2D(); + if (needsTimeSample) + timeSample = sampler->next1D(); gatherPoint.pos = Point2i(xofs + xofsInt, yofs + yofsInt); sample = sampler->next2D(); sample += Vector2((Float) gatherPoint.pos.x, (Float) gatherPoint.pos.y); RayDifferential ray; - camera->generateRayDifferential(sample, lensSample, ray); + camera->generateRayDifferential(sample, lensSample, timeSample, ray); Spectrum weight(1.0f); int depth = 1; @@ -232,7 +236,7 @@ public: gatherPoint.depth = -1; break; } - ray = RayDifferential(gatherPoint.its.p, gatherPoint.its.toWorld(bRec.wo)); + ray = RayDifferential(gatherPoint.its.p, gatherPoint.its.toWorld(bRec.wo), ray.time); ++depth; } } else { diff --git a/src/libcore/wavelet.cpp b/src/libcore/wavelet.cpp index 3b74854b..c75b57bd 100644 --- a/src/libcore/wavelet.cpp +++ b/src/libcore/wavelet.cpp @@ -844,7 +844,7 @@ Float SparseWaveletOctree::lineIntegral(Point start, Point end) const { start /= (Float) m_size; end /= (Float) m_size; - Ray ray(start, normalize(end-start)); + Ray ray(start, normalize(end-start), 0.0f); uint8_t a = 0; if (ray.d.x < 0) { diff --git a/src/librender/camera.cpp b/src/librender/camera.cpp index a329b2a0..3657b587 100644 --- a/src/librender/camera.cpp +++ b/src/librender/camera.cpp @@ -24,8 +24,14 @@ MTS_NAMESPACE_BEGIN Camera::Camera(const Properties &props) : ConfigurableObject(props), m_properties(props) { m_cameraToWorld = props.getTransform("toWorld", Transform()); + m_shutterOpen = props.getFloat("shutterOpen", 0.0f); + m_shutterClose = props.getFloat("shutterClose", 5.0f); + if (m_shutterOpen > m_shutterClose) + Log(EError, "Shutter opening time must be less than " + "or equal to the shutter closing time!"); m_worldToCamera = m_cameraToWorld.inverse(); m_position = m_cameraToWorld(Point(0,0,0)); + m_shutterOpenTime = m_shutterClose - m_shutterOpen; } Camera::Camera(Stream *stream, InstanceManager *manager) @@ -34,7 +40,10 @@ Camera::Camera(Stream *stream, InstanceManager *manager) m_sampler = static_cast(manager->getInstance(stream)); m_worldToCamera = Transform(stream); m_cameraToWorld = Transform(stream); + m_shutterOpen = stream->readFloat(); + m_shutterClose = stream->readFloat(); m_position = m_cameraToWorld(Point(0,0,0)); + m_shutterOpenTime = m_shutterClose - m_shutterOpen; } Camera::~Camera() { @@ -60,16 +69,18 @@ void Camera::serialize(Stream *stream, InstanceManager *manager) const { manager->serialize(stream, m_sampler.get()); m_worldToCamera.serialize(stream); m_cameraToWorld.serialize(stream); + stream->writeFloat(m_shutterOpen); + stream->writeFloat(m_shutterClose); } void Camera::generateRayDifferential(const Point2 &sample, - const Point2 &lensSample, RayDifferential &ray) const { + const Point2 &lensSample, Float timeSample, RayDifferential &ray) const { - generateRay(sample, lensSample, ray); + generateRay(sample, lensSample, timeSample, ray); Point2 temp = sample; temp.x += 1; - generateRay(temp, lensSample, ray.rx); + generateRay(temp, lensSample, timeSample, ray.rx); temp = sample; temp.y += 1; - generateRay(temp, lensSample, ray.ry); + generateRay(temp, lensSample, timeSample, ray.ry); ray.hasDifferentials = true; } diff --git a/src/librender/integrator.cpp b/src/librender/integrator.cpp index 51776a42..689152db 100644 --- a/src/librender/integrator.cpp +++ b/src/librender/integrator.cpp @@ -68,7 +68,7 @@ void SampleIntegrator::serialize(Stream *stream, InstanceManager *manager) const stream->writeBool(m_irrIndirect); } -Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n, +Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n, Float time, Sampler *sampler) const { Spectrum E(0.0f); LuminaireSamplingRecord lRec; @@ -80,7 +80,7 @@ Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission); /* Direct */ - if (scene->sampleLuminaireAttenuated(p, lRec, rRec.nextSample2D())) { + if (scene->sampleLuminaireAttenuated(p, lRec, time, rRec.nextSample2D())) { Float dp = dot(lRec.d, n); if (dp < 0) E -= lRec.Le * dp; @@ -90,7 +90,7 @@ Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n if (m_irrIndirect) { Vector d = frame.toWorld(squareToHemispherePSA(rRec.nextSample2D())); ++rRec.depth; - E += Li(RayDifferential(p, d), rRec) * M_PI; + E += Li(RayDifferential(p, d, time), rRec) * M_PI; } sampler->advance(); } @@ -150,6 +150,7 @@ void SampleIntegrator::renderBlock(const Scene *scene, const Camera *camera, Sampler *sampler, ImageBlock *block, const bool &stop) const { Point2 sample, lensSample; RayDifferential eyeRay; + Float timeSample = 0; Spectrum spec; int x, y; uint64_t j; @@ -162,6 +163,7 @@ void SampleIntegrator::renderBlock(const Scene *scene, block->clear(); RadianceQueryRecord rRec(scene, sampler); bool needsLensSample = camera->needsLensSample(); + bool needsTimeSample = camera->needsTimeSample(); const TabulatedFilter *filter = camera->getFilm()->getTabulatedFilter(); Float scaleFactor = 1.0f/std::sqrt((Float) sampler->getSampleCount()); @@ -175,10 +177,12 @@ void SampleIntegrator::renderBlock(const Scene *scene, rRec.newQuery(RadianceQueryRecord::ECameraRay); if (needsLensSample) lensSample = rRec.nextSample2D(); + if (needsTimeSample) + timeSample = rRec.nextSample1D(); sample = rRec.nextSample2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, - lensSample, eyeRay); + lensSample, timeSample, eyeRay); eyeRay.scaleDifferential(scaleFactor); ++cameraRays; spec = Li(eyeRay, rRec); @@ -199,10 +203,12 @@ void SampleIntegrator::renderBlock(const Scene *scene, rRec.newQuery(RadianceQueryRecord::ECameraRay); if (needsLensSample) lensSample = rRec.nextSample2D(); + if (needsTimeSample) + timeSample = rRec.nextSample1D(); sample = rRec.nextSample2D(); sample.x += x; sample.y += y; camera->generateRayDifferential(sample, - lensSample, eyeRay); + lensSample, timeSample, eyeRay); eyeRay.scaleDifferential(scaleFactor); ++cameraRays; spec = Li(eyeRay, rRec); diff --git a/src/librender/intersection.cpp b/src/librender/intersection.cpp index 69bdd4ef..87419b3c 100644 --- a/src/librender/intersection.cpp +++ b/src/librender/intersection.cpp @@ -86,6 +86,7 @@ std::string Intersection::toString() const { << " uv = " << uv.toString() << "," << std::endl << " dpdu = " << dpdu.toString() << "," << std::endl << " dpdv = " << dpdv.toString() << "," << std::endl + << " time = " << time << "," << std::endl << " shape = " << indent(((Object *)shape)->toString()) << std::endl << "]"; return oss.str(); diff --git a/src/librender/mipmap3d.cpp b/src/librender/mipmap3d.cpp index d044f8e9..cb1cccd5 100644 --- a/src/librender/mipmap3d.cpp +++ b/src/librender/mipmap3d.cpp @@ -262,7 +262,7 @@ inline int new_node(Float t1, int a, Float t2, int b, Float t3, int c) { Float SparseMipmap3D::lineIntegral(const Ray &r) const { Float length = r.d.length(); - Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length); + Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length, 0.0f); uint8_t a = 0; if (ray.d.x < 0) { @@ -304,7 +304,7 @@ bool SparseMipmap3D::invertLineIntegral(const Ray &r, Float desiredDensity, Float &accumDensity, Float &samplePos, Float &sampleDensity) const { Float length = r.d.length(); - Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length); + Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length, 0.0f); uint8_t a = 0; if (ray.d.x < 0) { diff --git a/src/librender/particleproc.cpp b/src/librender/particleproc.cpp index de400993..a9a02211 100644 --- a/src/librender/particleproc.cpp +++ b/src/librender/particleproc.cpp @@ -98,6 +98,9 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult, Spectrum weight, bsdfVal; int depth; bool caustic; + ref camera = m_scene->getCamera(); + Float shutterOpen = camera->getShutterOpen(), + shutterOpenTime = camera->getShutterOpenTime(); m_sampler->generate(); for (size_t index = range->getRangeStart(); index <= range->getRangeEnd() && !stop; ++index) { @@ -108,7 +111,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult, /* Sample an emitted particle */ m_scene->sampleEmission(eRec, areaSample, dirSample); - ray = Ray(eRec.sRec.p, eRec.d); + ray = Ray(eRec.sRec.p, eRec.d, shutterOpen + shutterOpenTime * m_sampler->next1D()); weight = eRec.P; depth = 1; caustic = true; @@ -126,7 +129,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult, */ weight *= mRec.sigmaS * mRec.attenuation / mRec.pdf; - handleMediumInteraction(depth, caustic, mRec, -ray.d, weight); + handleMediumInteraction(depth, caustic, mRec, ray.time, -ray.d, weight); if (!m_multipleScattering) break; @@ -144,7 +147,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult, weight /= mRec.albedo; } - ray = Ray(mRec.p, wo); + ray = Ray(mRec.p, wo, ray.time); } else if (its.t == std::numeric_limits::infinity()) { /* There is no surface in this direction */ break; @@ -179,7 +182,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult, weight *= bsdfVal; Vector wi = -ray.d, wo = its.toWorld(bRec.wo); - ray = Ray(its.p, wo); + ray = Ray(its.p, wo, ray.time); /* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */ Float wiDotGeoN = dot(its.geoFrame.n, wi), @@ -206,7 +209,7 @@ void ParticleTracer::handleSurfaceInteraction(int depth, bool caustic, } void ParticleTracer::handleMediumInteraction(int depth, bool caustic, - const MediumSamplingRecord &mRec, const Vector &wi, + const MediumSamplingRecord &mRec, Float time, const Vector &wi, const Spectrum &weight) { } diff --git a/src/librender/preview.cpp b/src/librender/preview.cpp index 33fe08a5..391593de 100644 --- a/src/librender/preview.cpp +++ b/src/librender/preview.cpp @@ -74,7 +74,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work /* Generate a camera ray without normalization */ primary = Ray(m_cameraO, m_cameraTL + m_cameraDx * (Float) x - + m_cameraDy * (Float) y); + + m_cameraDy * (Float) y, 0.0f); ++numRays; if (!m_kdtree->rayIntersect(primary, its)) { @@ -88,7 +88,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work value = Spectrum(0.0f); toVPL = m_vpl.its.p - its.p; - secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon); + secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon, 0.0f); ++numRays; if (m_kdtree->rayIntersect(secondary)) { block->setPixel(pos++, value); @@ -281,7 +281,8 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe secItv4.maxt.f[idx] = 0; emitted[idx] = m_scene->LeBackground(Ray( Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]), - Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]) + Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]), + 0.0f )); memset(&direct[idx], 0, sizeof(Spectrum)); continue; @@ -346,7 +347,8 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe } else { Ray ray( Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]), - Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]) + Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]), + 0.0f ); its.t = its4.t.f[idx]; shape->fillIntersectionRecord(ray, temp + idx * MTS_KD_INTERSECTION_TEMP + 8, its); diff --git a/src/librender/scene.cpp b/src/librender/scene.cpp index 8f70da9e..5a75d8e8 100644 --- a/src/librender/scene.cpp +++ b/src/librender/scene.cpp @@ -383,7 +383,7 @@ Float Scene::pdfLuminaire(const Intersection &its, } bool Scene::sampleLuminaire(const Point &p, - LuminaireSamplingRecord &lRec, const Point2 &s, + LuminaireSamplingRecord &lRec, Float time, const Point2 &s, bool testVisibility) const { Point2 sample(s); Float lumPdf; @@ -392,7 +392,7 @@ bool Scene::sampleLuminaire(const Point &p, luminaire->sample(p, lRec, sample); if (lRec.pdf != 0) { - if (testVisibility && isOccluded(p, lRec.sRec.p)) + if (testVisibility && isOccluded(p, lRec.sRec.p, time)) return false; lRec.pdf *= lumPdf; lRec.Le /= lRec.pdf; @@ -413,7 +413,7 @@ bool Scene::sampleLuminaire(const Intersection &its, luminaire->sample(its, lRec, sample); if (lRec.pdf != 0) { - if (testVisibility && isOccluded(its.p, lRec.sRec.p)) + if (testVisibility && isOccluded(its.p, lRec.sRec.p, its.time)) return false; lRec.pdf *= lumPdf; lRec.Le /= lRec.pdf; diff --git a/src/librender/track.cpp b/src/librender/track.cpp index b30ab540..922ed6ce 100644 --- a/src/librender/track.cpp +++ b/src/librender/track.cpp @@ -93,8 +93,6 @@ void AnimatedTransform::eval(Float t, Transform &trafo) const { "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); diff --git a/src/librender/vpl.cpp b/src/librender/vpl.cpp index 6cc4270b..4d9be3cc 100644 --- a/src/librender/vpl.cpp +++ b/src/librender/vpl.cpp @@ -55,7 +55,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept weight *= scene->sampleEmissionDirection(eRec, dirSample); Float cosTheta = (eRec.luminaire->getType() & Luminaire::EOnSurface) ? absDot(eRec.sRec.n, eRec.d) : 1; weight *= cosTheta / eRec.pdfDir; - ray = Ray(eRec.sRec.p, eRec.d); + ray = Ray(eRec.sRec.p, eRec.d, 0.0f); depth = 2; while (!weight.isBlack() && depth < maxDepth) { @@ -85,7 +85,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept weight *= bsdfVal; Vector wi = -ray.d, wo = its.toWorld(bRec.wo); - ray = Ray(its.p, wo); + ray = Ray(its.p, wo, 0.0f); /* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */ Float wiDotGeoN = dot(its.geoFrame.n, wi), diff --git a/src/medium/flake.cpp b/src/medium/flake.cpp index 2a6b3bdb..cfecf10f 100644 --- a/src/medium/flake.cpp +++ b/src/medium/flake.cpp @@ -377,7 +377,7 @@ public: } bool isInside(const Ray &r) const { - Ray ray(r(r.mint + Epsilon), r.d); + Ray ray(r(r.mint + Epsilon), r.d, 0.0f); Intersection its; if (!m_kdTree->rayIntersect(ray, its)) return false; @@ -386,7 +386,7 @@ public: Spectrum tau(const Ray &r) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength); + Ray ray(r(r.mint), r.d / dLength, 0.0f); Float coveredLength = 0, remaining = (r.maxt - r.mint) * dLength; bool inside = isInside(r); Intersection its; @@ -416,7 +416,7 @@ public: bool sampleDistance(const Ray &theRay, Float distSurf, MediumSamplingRecord &mRec, Sampler *sampler) const { Intersection its; - Ray ray(theRay.o, theRay.d); + Ray ray(theRay.o, theRay.d, 0.0f); int iterations = 0; /* Check if the start of the ray is already inside the medium */ diff --git a/src/medium/heterogeneous-flake.cpp b/src/medium/heterogeneous-flake.cpp index 7031d4b3..ad509a69 100644 --- a/src/medium/heterogeneous-flake.cpp +++ b/src/medium/heterogeneous-flake.cpp @@ -364,7 +364,7 @@ public: Spectrum tau(const Ray &r) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength); + Ray ray(r(r.mint), r.d / dLength, 0.0f); Float remaining = (r.maxt - r.mint) * dLength; Float integral = 0.0f; int iterations = 0; @@ -462,7 +462,7 @@ public: bool sampleDistance(const Ray &r, Float maxDist, MediumSamplingRecord &mRec, Sampler *sampler) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength); + Ray ray(r(r.mint), r.d / dLength, 0.0f); Float remaining = (maxDist - r.mint) * dLength, desiredTau = -std::log(1-sampler->next1D())/m_sizeMultiplier, accumulatedTau = 0.0f, diff --git a/src/medium/heterogeneous-stencil.cpp b/src/medium/heterogeneous-stencil.cpp index d3b8508a..f39cfbfe 100644 --- a/src/medium/heterogeneous-stencil.cpp +++ b/src/medium/heterogeneous-stencil.cpp @@ -168,7 +168,7 @@ public: Spectrum tau(const Ray &r) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength); + Ray ray(r(r.mint), r.d / dLength, 0.0f); Float remaining = (r.maxt - r.mint) * dLength; Float integral = 0.0f; int iterations = 0; @@ -266,7 +266,7 @@ public: bool sampleDistance(const Ray &r, Float maxDist, MediumSamplingRecord &mRec, Sampler *sampler) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength); + Ray ray(r(r.mint), r.d / dLength, 0.0f); Float remaining = (maxDist - r.mint) * dLength, desiredTau = -std::log(1-sampler->next1D())/m_sizeMultiplier, accumulatedTau = 0.0f, diff --git a/src/medium/homogeneous.cpp b/src/medium/homogeneous.cpp index 1ea62178..f44597c4 100644 --- a/src/medium/homogeneous.cpp +++ b/src/medium/homogeneous.cpp @@ -112,7 +112,7 @@ public: } bool isInside(const Ray &r) const { - Ray ray(r(r.mint + Epsilon), r.d); + Ray ray(r(r.mint + Epsilon), r.d, 0.0f); Intersection its; if (!m_kdTree->rayIntersect(ray, its)) return false; @@ -121,7 +121,7 @@ public: Spectrum tau(const Ray &r) const { Float dLength = r.d.length(); - Ray ray(r(r.mint), r.d / dLength, Epsilon, std::numeric_limits::infinity()); + Ray ray(r(r.mint), r.d / dLength, Epsilon, std::numeric_limits::infinity(), 0.0f); Float coveredLength = 0, remaining = (r.maxt - r.mint) * dLength; bool inside = isInside(r); Intersection its; @@ -147,7 +147,7 @@ public: bool sampleDistance(const Ray &theRay, Float distSurf, MediumSamplingRecord &mRec, Sampler *sampler) const { Intersection its; - Ray ray(theRay.o, theRay.d); + Ray ray(theRay.o, theRay.d, 0.0f); int iterations = 0; /* Check if the start of the ray is already inside the medium */ diff --git a/src/qtgui/preview_proc.cpp b/src/qtgui/preview_proc.cpp index b0080bf8..bd71f7a8 100644 --- a/src/qtgui/preview_proc.cpp +++ b/src/qtgui/preview_proc.cpp @@ -92,11 +92,12 @@ void PreviewProcess::configure(const VPL &vpl, Float minDist, const Point2 &jitt const Point2 right(topLeft.x + m_film->getSize().x, topLeft.y); const Point2 bottom(topLeft.x, topLeft.y + m_film->getSize().y); const Point2 lens(0, 0); + Float time = 0.0f; const Camera *camera = m_scene->getCamera(); - camera->generateRay(topLeft, lens, topLeftRay); - camera->generateRay(right, lens, rightRay); - camera->generateRay(bottom, lens, bottomRay); + camera->generateRay(topLeft, lens, time, topLeftRay); + camera->generateRay(right, lens, time, rightRay); + camera->generateRay(bottom, lens, time, bottomRay); m_cameraTL = Vector(topLeftRay.d); m_cameraO = camera->getPosition(); m_cameraDx = (rightRay.d - topLeftRay.d) diff --git a/src/shapes/animatedinstance.cpp b/src/shapes/animatedinstance.cpp index 4b9b594c..b9614f69 100644 --- a/src/shapes/animatedinstance.cpp +++ b/src/shapes/animatedinstance.cpp @@ -23,8 +23,6 @@ MTS_NAMESPACE_BEGIN -#define TIME 0 - class AnimatedInstance : public Shape { public: AnimatedInstance(const Properties &props) : Shape(props) { @@ -96,7 +94,7 @@ public: const KDTree *kdtree = m_shapeGroup->getKDTree(); Ray ray; Transform objectToWorld, worldToObject; - m_transform->eval(TIME, objectToWorld); + m_transform->eval(_ray.time, objectToWorld); worldToObject = objectToWorld.inverse(); worldToObject(_ray, ray); return kdtree->rayIntersect(ray, mint, maxt, t, temp); @@ -106,7 +104,7 @@ public: const KDTree *kdtree = m_shapeGroup->getKDTree(); Ray ray; Transform objectToWorld, worldToObject; - m_transform->eval(TIME, objectToWorld); + m_transform->eval(_ray.time, objectToWorld); worldToObject = objectToWorld.inverse(); worldToObject(_ray, ray); return kdtree->rayIntersect(ray, mint, maxt); @@ -116,7 +114,7 @@ public: const void *temp, Intersection &its) const { const KDTree *kdtree = m_shapeGroup->getKDTree(); Transform objectToWorld; - m_transform->eval(TIME, objectToWorld); + m_transform->eval(ray.time, objectToWorld); kdtree->fillIntersectionRecord(ray, temp, its); its.shFrame.n = normalize(objectToWorld(its.shFrame.n)); its.shFrame.s = normalize(objectToWorld(its.shFrame.s)); diff --git a/src/shapes/sphere.cpp b/src/shapes/sphere.cpp index a0478d5f..a5fe1558 100644 --- a/src/shapes/sphere.cpp +++ b/src/shapes/sphere.cpp @@ -209,7 +209,7 @@ public: Vector d = Frame(w*invDistW).toWorld( squareToCone(cosThetaMax, sample)); - Ray ray(p, d); + Ray ray(p, d, 0.0f); Float t; if (!rayIntersect(ray, 0, std::numeric_limits::infinity(), t, NULL)) { // This can happen sometimes due to roundoff errors - just fail to diff --git a/src/subsurface/irrproc.cpp b/src/subsurface/irrproc.cpp index 087026e9..b25eef29 100644 --- a/src/subsurface/irrproc.cpp +++ b/src/subsurface/irrproc.cpp @@ -72,6 +72,7 @@ public: const RangeWorkUnit *range = static_cast(workUnit); IrradianceRecordVector *result = static_cast(workResult); const SampleIntegrator *integrator = m_integrator.get(); + ref camera = m_scene->getCamera(); result->clear(); for (size_t i=range->getRangeStart(); igetRangeEnd(); ++i) { @@ -83,10 +84,11 @@ public: expSamples *= m_sampleCount; ShapeSamplingRecord sRec; Float pdf = m_shapes[index]->sampleArea(sRec, sample) * expSamples; + Float time = camera->getShutterOpen() + m_sampler->next1D() * camera->getShutterOpenTime(); result->put(IrradianceSample( sRec.p, - integrator->E(m_scene.get(), sRec.p, sRec.n, m_independentSampler), + integrator->E(m_scene.get(), sRec.p, sRec.n, time, m_independentSampler), 1/pdf )); } diff --git a/src/tests/test_kd.cpp b/src/tests/test_kd.cpp index b2569c73..f7bb4181 100644 --- a/src/tests/test_kd.cpp +++ b/src/tests/test_kd.cpp @@ -110,7 +110,7 @@ public: sample2(random->nextFloat(), random->nextFloat()); Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius; Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius; - Ray r(p1, normalize(p2-p1)); + Ray r(p1, normalize(p2-p1), 0.0f); Intersection its; if (tree->rayIntersect(r)) diff --git a/src/utils/kdbench.cpp b/src/utils/kdbench.cpp index 1aa805cc..c45a2be8 100644 --- a/src/utils/kdbench.cpp +++ b/src/utils/kdbench.cpp @@ -225,7 +225,7 @@ public: sample2(random->nextFloat(), random->nextFloat()); Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius; Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius; - Ray r(p1, normalize(p2-p1)); + Ray r(p1, normalize(p2-p1), 0.0f); Intersection its; if (kdtree->rayIntersect(r, its))