Text archives Help
- From: sparker@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [Manta] r1855 - in trunk: Engine/Factory Engine/Renderers Interface Model/Materials
- Date: Mon, 19 Nov 2007 23:50:52 -0700 (MST)
Author: sparker
Date: Mon Nov 19 23:50:48 2007
New Revision: 1855
Added:
trunk/Engine/Renderers/KajiyaPathtracer.cc
trunk/Engine/Renderers/KajiyaPathtracer.h
Modified:
trunk/Engine/Factory/RegisterKnownComponents.cc
trunk/Engine/Renderers/CMakeLists.txt
trunk/Interface/Material.cc
trunk/Interface/Material.h
trunk/Interface/RayPacket.h
trunk/Model/Materials/Lambertian.cc
trunk/Model/Materials/Lambertian.h
Log:
Added the beginnings of a kajiya-style pathtracer based on packet sorting.
I am not convinced it is correct - in fact, I am convinced it is not.
Numerous opportunities for performance improvement exist once it is correct.
Modified: trunk/Engine/Factory/RegisterKnownComponents.cc
==============================================================================
--- trunk/Engine/Factory/RegisterKnownComponents.cc (original)
+++ trunk/Engine/Factory/RegisterKnownComponents.cc Mon Nov 19 23:50:48
2007
@@ -46,6 +46,7 @@
#include <Engine/PixelSamplers/NullSampler.h>
#include <Engine/PixelSamplers/SingleSampler.h>
#include <Engine/PixelSamplers/JitterSampler.h>
+#include <Engine/Renderers/KajiyaPathtracer.h>
#include <Engine/Renderers/Moire.h>
#include <Engine/Renderers/Noise.h>
#include <Engine/Renderers/NullRenderer.h>
@@ -111,6 +112,7 @@
engine->registerComponent("jittersample", &JitterSampler::create);
// Register renderers
+ engine->registerComponent("pathtracer", &KajiyaPathtracer::create);
engine->registerComponent("null", &NullRenderer::create);
engine->registerComponent("raygen", &RayGen::create);
engine->registerComponent("moire", &Moire::create);
Modified: trunk/Engine/Renderers/CMakeLists.txt
==============================================================================
--- trunk/Engine/Renderers/CMakeLists.txt (original)
+++ trunk/Engine/Renderers/CMakeLists.txt Mon Nov 19 23:50:48 2007
@@ -1,5 +1,7 @@
SET (Manta_Renderers_SRCS
+ Renderers/KajiyaPathtracer.h
+ Renderers/KajiyaPathtracer.cc
Renderers/Moire.h
Renderers/Moire.cc
Renderers/Noise.h
Added: trunk/Engine/Renderers/KajiyaPathtracer.cc
==============================================================================
--- (empty file)
+++ trunk/Engine/Renderers/KajiyaPathtracer.cc Mon Nov 19 23:50:48 2007
@@ -0,0 +1,377 @@
+// TODO
+// If single pixel, use a single accumulator
+// Put background rays at end to make alignment easier - DO BACKGROUND RAYS
ALL AT ONCE!!!
+// Try sorting after MC by direction/origin and do not sort by matl
+// shadow rays with important sampling?
+// Russian roulette for shadow rays?
+#include <Engine/Renderers/KajiyaPathtracer.h>
+#include <Interface/Background.h>
+#include <Interface/Camera.h>
+#include <Interface/Context.h>
+#include <Interface/Material.h>
+#include <Interface/Object.h>
+#include <Interface/RayPacket.h>
+#include <Interface/SampleGenerator.h>
+#include <Interface/Scene.h>
+#include <Interface/ShadowAlgorithm.h>
+#include <Core/Math/MiscMath.h>
+#include <Core/Util/Assert.h>
+#include <Core/Util/NotFinished.h>
+#include <Core/Color/ColorSpace_fancy.h>
+#include <iostream>
+using namespace std;
+
+using namespace Manta;
+using SCIRun::Abs;
+
+Renderer* KajiyaPathtracer::create(const vector<string>& args)
+{
+ return new KajiyaPathtracer(args);
+}
+
+KajiyaPathtracer::KajiyaPathtracer(const vector<string>& /*args*/)
+{
+}
+
+KajiyaPathtracer::~KajiyaPathtracer()
+{
+}
+
+void KajiyaPathtracer::setupBegin(const SetupContext&, int)
+{
+}
+
+void KajiyaPathtracer::setupDisplayChannel(SetupContext&)
+{
+}
+
+void KajiyaPathtracer::setupFrame(const RenderContext&)
+{
+}
+
+static inline bool sort_needs_swap(const RayPacketData* data, int i, int j)
+{
+ return (long)data->hitMatl[i] > (long)data->hitMatl[j];
+}
+
+template<class T>
+static inline void swap(T* array, int i, int j)
+{
+ T tmp = array[i];
+ array[i] = array[j];
+ array[j] = tmp;
+}
+
+void KajiyaPathtracer::traceEyeRays(const RenderContext& context, RayPacket&
rays)
+{
+ ASSERT(rays.getFlag(RayPacket::HaveImageCoordinates));
+ context.camera->makeRays(context, rays);
+ rays.initializeImportance();
+
+ Packet<Color> result;
+ result.fill(rays.begin(), rays.end(), Color::black());
+ Packet<Color> total_attenuation;
+ total_attenuation.fill(rays.begin(), rays.end(), Color::white());
+ Packet<Color> reflectance;
+
+ Packet<int> permute;
+ if(!rays.getFlag(RayPacket::ConstantPixel)){
+ for(int i=rays.begin();i<rays.end();i++)
+ permute.data[i] = i;
+ }
+
+ int originalBegin = rays.begin();
+ int originalEnd = rays.end();
+
+ RayPacketData* data = rays.data;
+ int depth = 0;
+ int maxdepth = context.scene->getRenderParameters().maxDepth;
+ for(;;){
+
+ rays.resetHits();
+ context.scene->getObject()->intersect(context, rays);
+
+ // Sort the rays based on the material that they hit
+ // Simple bubble sort for now - performance will come later
+ // This may not be worthwhile if we sort by directions, but
+ // we would still need to sort out the background rays (one pass)
+ // Another option is to use a sort that picks one unique value and then
+ // searches for all pointers of this type. It could probably be SSEd.
+ for(int i=rays.begin();i<rays.end()-1;i++){
+ for(int j=i+1;j<rays.end();j++){
+ if(sort_needs_swap(data, i, j)){
+ // Move hitPrim, hitMatl, hitTex, origin, direction, minT, time
+ swap(data->hitPrim, i, j);
+ swap(data->hitMatl, i, j);
+ swap(data->hitTex, i, j);
+ for(int k=0;k<3;k++)
+ swap(data->origin[k], i, j);
+ for(int k=0;k<3;k++)
+ swap(data->direction[k], i, j);
+ swap(data->minT, i, j);
+ swap(data->time, i, j);
+
+ // Conditionally: normal
+ for(int k=0;k<3;k++)
+ swap(data->normal[k], i, j);
+
+ // Conditionally: ffnormal,
+ for(int k=0;k<3;k++)
+ swap(data->ffnormal[k], i, j);
+
+ // Conditionally: hitPosition,
+ for(int k=0;k<3;k++)
+ swap(data->hitPosition[k], i, j);
+
+ // Conditionally: texCoords, dPdu, dpDv
+ for(int k=0;k<3;k++)
+ swap(data->texCoords[k], i, j);
+ for(int k=0;k<3;k++)
+ swap(data->dPdu[k], i, j);
+ for(int k=0;k<3;k++)
+ swap(data->dPdv[k], i, j);
+
+ // Move sample_id, region_id
+ swap(data->sample_id, i, j);
+ swap(data->region_id, i, j);
+
+ // Move scratchpads???
+ // Move result
+ for(int k=0;k<3;k++)
+ swap(result.colordata[k], i, j);
+
+ // Move total attenuation
+ for(int k=0;k<3;k++)
+ swap(total_attenuation.colordata[k], i, j);
+
+ // Move permute
+ swap(permute.data, i, j);
+ }
+ }
+ }
+ // Skip background rays - they will be shaded all at once below
+ int newBegin = rays.begin();
+ while(!rays.wasHit(newBegin))
+ newBegin++;
+ rays.resize(newBegin, rays.end());
+ if(rays.begin() == rays.end())
+ break;
+
+ // Clear inverseDirection, corner_dir, signs
+ rays.flags &= ~(RayPacket::HaveCornerRays |
RayPacket::HaveInverseDirections | RayPacket::HaveSigns);
+
+ rays.computeFFNormals(context); // Must do this before writing over the
ray direction
+
+ // Compute new rays and reflectance for anything that hit a surface
+ for(int i = rays.begin();i<rays.end();){
+ const Material* hit_matl = rays.getHitMaterial(i);
+ int end = i+1;
+ while(end < rays.end() && rays.getHitMaterial(end) == hit_matl)
+ end++;
+ RayPacket subPacket(rays, i, end);
+ hit_matl->sampleBSDF(context, subPacket, reflectance);
+ i=end;
+ }
+
+ // Russian roulette and collapse
+ bool do_russian_roulette = true;
+ if(do_russian_roulette){
+ Packet<Real> rr;
+ context.sample_generator->nextSeeds(context, rr, rays);
+ int newEnd = rays.end();
+ for(int i=rays.begin();i<newEnd;i++){
+ if(rr.get(i) > reflectance.get(i).luminance()){
+ // Kill it by swapping with the last ray
+ // We may not need to move origin/direction back....
+ --newEnd;
+ // Move origin, direction
+ // Look at one-way move optimization
+ for(int j=0;j<3;j++)
+ swap(data->origin[j], i, newEnd);
+ for(int j=0;j<3;j++)
+ swap(data->direction[j], i, newEnd);
+
+ // Move time
+ // Look at one-way move optimization
+ swap(data->time, i, newEnd);
+
+ // Move sample_id, region_id
+ // Look at one-way move optimization
+ swap(data->sample_id, i, newEnd);
+ swap(data->region_id, i, newEnd);
+
+ // Move result
+ for(int j=0;j<3;j++)
+ swap(result.colordata[j], i, newEnd);
+
+ // Move reflectance
+ // Look at one-way move optimization
+ for(int j=0;j<3;j++)
+ swap(reflectance.colordata[j], i, newEnd);
+
+ // Move total attenuation
+ // Look at one-way move optimization
+ for(int j=0;j<3;j++)
+ swap(total_attenuation.colordata[j], i, newEnd);
+
+ // Move rr
+ // Look at one-way move optimization
+ swap(rr.data, i, newEnd);
+
+ // Move permute
+ swap(permute.data, i, newEnd);
+
+ --i;
+ } else {
+ Real scale = 1./reflectance.get(i).luminance();
+ for(int j=0;j<3;j++)
+ reflectance.colordata[j][i] *= scale;
+ for(int j=0;j<3;j++)
+ total_attenuation.colordata[j][i] *= reflectance.colordata[j][i];
+ }
+
+ rays.resize(rays.begin(), newEnd);
+ if(rays.begin() == rays.end())
+ break;
+ }
+ } else {
+ for(int i=rays.begin();i<rays.end();i++){
+ for(int j=0;j<3;j++)
+ total_attenuation.colordata[j][i] *= reflectance.colordata[j][i];
+ }
+ }
+
+
+ // Cast shadow rays
+ ShadowAlgorithm::StateBuffer shadowState;
+ do {
+ RayPacketData shadowData;
+ RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0, depth,
false);
+
+ // Call the shadowalgorithm(sa) to generate shadow rays. We may not be
+ // able to compute all of them, so we pass along a buffer for the sa
+ // object to store it's state.
+ context.shadowAlgorithm->computeShadows(context, shadowState,
context.scene->getLights(),
+ rays, shadowRays);
+
+ // We need normalized directions for proper dot product computation.
+ shadowRays.normalizeDirections();
+
+ for(int i=shadowRays.begin(); i < shadowRays.end(); i++){
+ if(!shadowRays.wasHit(i)){
+ // Not in shadow, so compute the direct lighting contributions.
+ Vector normal = rays.getFFNormal(i);
+ Vector light_dir = shadowRays.getDirection(i);
+ double dist = light_dir.normalize();
+ // This should be retrieved from the light somehow - probably put
into the light color
+ double A = 20;
+ //NOT_FINISHED("Light source area and normal");
+ Vector light_normal = Vector(0, -1, 0);
+ double weight=Dot(normal, light_dir) * Abs(Dot(light_normal,
light_dir)) * A / (M_PI*dist*dist);
+ Color light_color = shadowRays.getColor(i);
+ result.set(i, result.get(i) + total_attenuation.get(i) *
light_color * weight);
+ }
+ }
+ } while(!shadowState.done());
+
+ depth++;
+ if(depth >= maxdepth)
+ break;
+
+ rays.flags &= RayPacket::ConstantEye | RayPacket::ConstantPixel |
RayPacket::ConstantSampleRegion;
+ }
+
+ // Add contribution from background rays, which will be at the beginning.
+ if(rays.begin() != originalBegin){
+ RayPacket subPacket(rays, originalBegin, rays.begin());
+ context.scene->getBackground()->shade(context, subPacket);
+ for(int i=originalBegin;i<rays.begin();i++){
+ for(int j=0;j<3;j++)
+ result.colordata[j][i] += data->color[j][i] *
total_attenuation.colordata[j][i];
+ }
+ }
+
+ rays.resize(originalBegin, originalEnd);
+ rays.resetHits();
+ rays.flags &= RayPacket::ConstantEye | RayPacket::ConstantPixel |
RayPacket::ConstantSampleRegion;
+ rays.flags |= RayPacket::NormalizedDirections;
+ rays.shape = RayPacket::UnknownShape;
+
+ for(int i=rays.begin();i<rays.end();i++){
+ rays.setColor(permute.get(i), result.get(i));
+ }
+
+}
+
+void KajiyaPathtracer::traceRays(const RenderContext& context, RayPacket&
rays)
+{
+ int debugFlag = rays.getAllFlags() & RayPacket::DebugPacket;
+ rays.resetHits();
+ context.scene->getObject()->intersect(context, rays);
+
+ // Go through the ray packet and shade them. Group rays that hit the
+ // same object and material to shade with a single shade call
+ for(int i = rays.begin();i<rays.end();){
+ if(rays.wasHit(i)){
+ const Material* hit_matl = rays.getHitMaterial(i);
+ int end = i+1;
+ while(end < rays.end() && rays.wasHit(end) &&
+ rays.getHitMaterial(end) == hit_matl)
+ end++;
+ if (debugFlag) {
+ rays.computeHitPositions();
+ for (int j = i; j < end; ++j) {
+ cerr << "raytree: ray_index "<<j
+ << " depth " << rays.getDepth()
+ << " origin "<< rays.getOrigin(j)
+ << " direction "<< rays.getDirection(j)
+ << " hitpos " << rays.getHitPosition(j)
+ << "\n";
+ }
+ }
+ RayPacket subPacket(rays, i, end);
+ hit_matl->shade(context, subPacket);
+ i=end;
+ } else {
+ int end = i+1;
+ while(end < rays.end() && !rays.wasHit(end))
+ end++;
+ if (debugFlag) {
+ for (int j = i; j < end; ++j) {
+ cerr << "raytree: ray_index "<<j
+ << " depth " << rays.getDepth()
+ << " origin "<< rays.getOrigin(j)
+ << " direction "<< rays.getDirection(j)
+ << "\n";
+ }
+ }
+ RayPacket subPacket(rays, i, end);
+ context.scene->getBackground()->shade(context, subPacket);
+ i=end;
+ }
+ }
+}
+
+void KajiyaPathtracer::traceRays(const RenderContext& context, RayPacket&
rays, Real cutoff)
+{
+ for(int i = rays.begin(); i != rays.end();) {
+ if(rays.getImportance(i).luminance() > cutoff) {
+ int end = i + 1;
+ while(end < rays.end() && rays.getImportance(end).luminance() > cutoff)
+ end++;
+
+ RayPacket subPacket(rays, i, end);
+ traceRays(context, subPacket);
+ i = end;
+ } else {
+ // need to set the color to black
+ rays.setColor(i, Color::black());
+ int end = i + 1;
+ while(end < rays.end() && rays.getImportance(end).luminance() <=
cutoff) {
+ rays.setColor(end, Color::black());
+ end++;
+ }
+ i = end;
+ }
+ }
+}
Added: trunk/Engine/Renderers/KajiyaPathtracer.h
==============================================================================
--- (empty file)
+++ trunk/Engine/Renderers/KajiyaPathtracer.h Mon Nov 19 23:50:48 2007
@@ -0,0 +1,35 @@
+
+#ifndef Manta_Engine_KajiyaPathtracer_h
+#define Manta_Engine_KajiyaPathtracer_h
+
+#include <Interface/Renderer.h>
+#include <sgi_stl_warnings_off.h>
+#include <string>
+#include <vector>
+#include <sgi_stl_warnings_on.h>
+
+namespace Manta {
+ using namespace std;
+ class ShadowAlgorithm;
+
+ class KajiyaPathtracer : public Renderer {
+ public:
+ KajiyaPathtracer() {}
+ KajiyaPathtracer(const vector<string>& args);
+ virtual ~KajiyaPathtracer();
+ virtual void setupBegin(const SetupContext&, int numChannels);
+ virtual void setupDisplayChannel(SetupContext&);
+ virtual void setupFrame(const RenderContext& context);
+
+ virtual void traceEyeRays(const RenderContext&, RayPacket& rays);
+ virtual void traceRays(const RenderContext&, RayPacket& rays);
+ virtual void traceRays(const RenderContext&, RayPacket& rays, Real
cutoff);
+
+ static Renderer* create(const vector<string>& args);
+ private:
+ KajiyaPathtracer(const KajiyaPathtracer&);
+ KajiyaPathtracer& operator=(const KajiyaPathtracer&);
+ };
+}
+
+#endif
Modified: trunk/Interface/Material.cc
==============================================================================
--- trunk/Interface/Material.cc (original)
+++ trunk/Interface/Material.cc Mon Nov 19 23:50:48 2007
@@ -1,5 +1,6 @@
#include <Interface/Material.h>
+#include <Core/Exceptions/InternalError.h>
using namespace Manta;
@@ -9,5 +10,11 @@
Material::~Material()
{
+}
+
+void Material::sampleBSDF(const RenderContext& context,
+ RayPacket& rays, Packet<Color>& reflectance) const
+{
+ throw SCIRun::InternalError("computeBSDF not implemented for this
material", __FILE__, __LINE__);
}
Modified: trunk/Interface/Material.h
==============================================================================
--- trunk/Interface/Material.h (original)
+++ trunk/Interface/Material.h Mon Nov 19 23:50:48 2007
@@ -31,11 +31,14 @@
*/
#include <Interface/Interpolable.h>
+#include <Core/Color/Color.h>
namespace Manta {
class PreprocessContext;
class RayPacket;
class RenderContext;
+ class Vector;
+ template<class T> class Packet;
class Material : public Interpolable {
public:
@@ -50,6 +53,8 @@
// represent no light.
virtual void attenuateShadows(const RenderContext& context,
RayPacket& shadowRays) const = 0;
+ virtual void sampleBSDF(const RenderContext& context,
+ RayPacket& rays, Packet<Color>& reflectance)
const;
private:
// Material(const Material&);
Modified: trunk/Interface/RayPacket.h
==============================================================================
--- trunk/Interface/RayPacket.h (original)
+++ trunk/Interface/RayPacket.h Mon Nov 19 23:50:48 2007
@@ -156,6 +156,8 @@
HaveSurfaceDerivatives = 0x00008000,
ConstantSampleRegion = 0x00010000,
+ ConstantPixel = 0x00020000,
+
DebugPacket = 0x80000000,
};
Modified: trunk/Model/Materials/Lambertian.cc
==============================================================================
--- trunk/Model/Materials/Lambertian.cc (original)
+++ trunk/Model/Materials/Lambertian.cc Mon Nov 19 23:50:48 2007
@@ -33,13 +33,17 @@
#include <Interface/RayPacket.h>
#include <Interface/AmbientLight.h>
#include <Interface/Context.h>
+#include <Interface/SampleGenerator.h>
#include <Interface/ShadowAlgorithm.h>
+#include <Core/Math/Expon.h>
+#include <Core/Math/Trig.h>
#include <Core/Persistent/MantaRTTI.h>
#include <Core/Persistent/ArchiveElement.h>
#include <Interface/InterfaceRTTI.h>
#include <Model/Textures/Constant.h>
#include <iostream>
using namespace Manta;
+using namespace SCIRun;
using std::cerr;
Lambertian::Lambertian(const Color& color)
@@ -235,6 +239,33 @@
#endif
}
+
+void Lambertian::sampleBSDF(const RenderContext& context,
+ RayPacket& rays, Packet<Color>& reflectance) const
+{
+ rays.computeHitPositions();
+ Packet<Real> r1;
+ context.sample_generator->nextSeeds(context, r1, rays);
+ Packet<Real> r2;
+ context.sample_generator->nextSeeds(context, r2, rays);
+ rays.computeFFNormals(context);
+ rays.computeSurfaceDerivatives(context);
+ for(int i=rays.begin();i<rays.end();i++){
+ Real sintheta2 = r1.get(i);
+ Real sintheta=Sqrt(sintheta2);
+ Real costheta=Sqrt(1-sintheta2);
+ Real phi=2*M_PI*r2.get(i);
+ Real cosphi=Cos(phi)*sintheta;
+ Real sinphi=Sin(phi)*sintheta;
+ Vector normal = rays.getFFNormal(i);
+ Vector v1 = rays.getSurfaceDerivativeU(i);
+ Vector v2 = rays.getSurfaceDerivativeV(i);
+ rays.setDirection(i, normal * costheta + v1 * cosphi + v2 * sinphi);
+ rays.setOrigin(i, rays.getHitPosition(i));
+ }
+ colortex->mapValues(reflectance, context, rays);
+}
+
namespace Manta {
MANTA_DECLARE_RTTI_DERIVEDCLASS(Lambertian, LitMaterial, ConcreteClass,
readwriteMethod);
Modified: trunk/Model/Materials/Lambertian.h
==============================================================================
--- trunk/Model/Materials/Lambertian.h (original)
+++ trunk/Model/Materials/Lambertian.h Mon Nov 19 23:50:48 2007
@@ -46,6 +46,9 @@
virtual ~Lambertian();
virtual void shade(const RenderContext& context, RayPacket& rays) const;
+ virtual void sampleBSDF(const RenderContext& context,
+ RayPacket& rays, Packet<Color>& reflectance)
const;
+
void readwrite(ArchiveElement* archive);
private:
const Texture<Color>* colortex;
- [Manta] r1855 - in trunk: Engine/Factory Engine/Renderers Interface Model/Materials, sparker, 11/20/2007
Archive powered by MHonArc 2.6.16.