instancing support in the realtine preview

metadata
Wenzel Jakob 2011-03-31 00:44:20 +02:00
parent 77bcff3550
commit 3e316e6efd
17 changed files with 392 additions and 167 deletions

View File

@ -197,7 +197,9 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
exporter = MtsExporter(tempdir, matfile,
bpy.data.materials, bpy.data.textures)
exporter.adj_filename = os.path.join(tempdir, matfile)
exporter.writeHeader()
if not exporter.writeHeader():
MtsLog('Error while exporting -- check the console for details.')
return;
exporter.exportMaterial(pm)
exporter.exportPreviewMesh(pm)
exporter.writeFooter()

View File

@ -246,9 +246,14 @@ class MtsExporter:
self.stack = []
def writeHeader(self):
self.out = open(self.adj_filename, 'w')
try:
self.out = open(self.adj_filename, 'w')
except IOError:
MtsLog('Error: unable to write to file \"%s\"!' % self.adj_filename)
return False
self.out.write('<?xml version="1.0" encoding="utf-8"?>\n');
self.openElement('scene')
return True
def writeFooter(self):
self.closeElement()
@ -308,7 +313,10 @@ class MtsExporter:
size_y = lamp.data.size_y
mult = mult / (2 * size_x * size_y)
filename = "area_luminaire_%d.obj" % idx
try:
os.mkdir(self.meshes_dir)
except OSError:
pass
self.parameter('string', 'filename', { 'value' : 'meshes/%s' % filename})
self.exportWorldTrafo(lamp.matrix_world)
@ -429,9 +437,12 @@ class MtsExporter:
def exportEmission(self, obj):
lamp = obj.data.materials[0].mitsuba_emission
name = translate_id(obj.data.name)
if obj.data.users > 1:
MtsLog("Error: luminaires cannot be instantiated!")
return
mult = lamp.intensity
self.openElement('append', { 'id' : '%s-mesh_0' % name})
name = translate_id(obj.data.name) + "-mesh_0"
self.openElement('append', { 'id' : name})
self.openElement('luminaire', { 'id' : '%s-emission' % name, 'type' : 'area'})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.samplingWeight})
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
@ -486,16 +497,11 @@ class MtsExporter:
# Force scene update; NB, scene.update() doesn't work
scene.frame_set(scene.frame_current)
efutil.export_path = self.xml_filename
try:
os.mkdir(self.meshes_dir)
except OSError:
pass
MtsLog('MtsBlend: Writing COLLADA file to "%s"' % self.dae_filename)
scene.collada_export(self.dae_filename)
MtsLog('MtsBlend: Writing adjustments file to "%s"' % self.adj_filename)
self.writeHeader()
if not self.writeHeader():
return False
self.exportIntegrator(scene.mitsuba_integrator)
self.exportSampler(scene.mitsuba_sampler)
for medium in scene.mitsuba_media.media:
@ -513,6 +519,9 @@ class MtsExporter:
idx = idx+1
self.writeFooter()
(width, height) = resolution(scene)
MtsLog('MtsBlend: Writing COLLADA file to "%s"' % self.dae_filename)
scene.collada_export(self.dae_filename)
MtsLog("MtsBlend: Launching mtsimport")
command = ['mtsimport', '-r', '%dx%d' % (width, height),

View File

@ -119,7 +119,7 @@ public:
* Only transmits positions, hence this is mainly useful for
* shadow mapping.
*/
void drawAll();
void drawAll(const std::vector<std::pair<const GPUGeometry *, Transform> > &geo);
/// Blit a screen-sized quad
void blitQuad(bool flipVertically);
@ -168,6 +168,12 @@ public:
/// Set the current fixed-function pipeline color
void setColor(const Spectrum &spec);
/// Push a view transformation onto the matrix stack
void pushTransform(const Transform &trafo);
/// Pop the last view transformation from the matrix stack
void popTransform();
/// Flush outstanding rendering commands
void flush();

View File

@ -33,6 +33,9 @@ public:
/// Return the name of this geometry object
inline std::string getName() const { return m_mesh->getName(); }
/// Return the associated triangle mesh
inline const TriMesh *getTriMesh() const { return m_mesh.get(); }
/// Upload the geometry object
virtual void init() = 0;

View File

@ -154,7 +154,7 @@ public:
* Only transmits positions, hence this is mainly useful for
* shadow mapping.
*/
virtual void drawAll() = 0;
virtual void drawAll(const std::vector<std::pair<const GPUGeometry *, Transform> > &geo) = 0;
/// Draw a quad using the given texture
virtual void blitTexture(const GPUTexture *texture,
@ -217,6 +217,12 @@ public:
/// Set the current fixed-function pipeline color
virtual void setColor(const Spectrum &spec) = 0;
/// Push a view transformation onto the matrix stack
virtual void pushTransform(const Transform &trafo) = 0;
/// Pop the last view transformation from the matrix stack
virtual void popTransform() = 0;
/// Flush outstanding rendering commands
virtual void flush() = 0;
@ -246,11 +252,9 @@ public:
* will transfer the associated geometry to the GPU,
* which accelerates later calls to drawTriMesh()
*/
void registerGeometry(const TriMesh *mesh);
GPUGeometry *registerGeometry(const TriMesh *mesh);
/**
* Unregister a triangle mesh from the renderer.
*/
/// Unregister a triangle mesh from the renderer.
void unregisterGeometry(const TriMesh *mesh);
/// Set the log level

View File

@ -56,7 +56,7 @@ public:
void unbind();
/// Return all bound triangle meshes
inline const std::vector<const TriMesh *> &getMeshes() const { return m_meshes; }
inline const std::vector<std::pair<const TriMesh *, Transform> > &getMeshes() const { return m_meshes; }
/// Return the shadow cube map for debugging purposes
inline GPUTexture *getShadowMap() { return m_shadowMap; }
@ -271,7 +271,8 @@ private:
VPLProgramConfiguration m_targetConfig;
ref<GPUProgram> m_backgroundProgram;
VPLDependencyNode m_backgroundDependencies;
std::vector<const TriMesh *> m_meshes;
std::vector<std::pair<const TriMesh *, Transform> > m_meshes;
std::vector<std::pair<const GPUGeometry *, Transform> > m_drawList;
};
MTS_NAMESPACE_END

View File

@ -37,9 +37,11 @@
MTS_NAMESPACE_BEGIN
/**
* Scene data structure: holds information on surfaces, luminaires
* and participating media and coordinates rendering jobs. Also provides
* useful query routines mostly used by the integrator implementations.
* \brief Principal scene data structure
*
* Holds information on surfaces, luminaires and participating media and
* coordinates rendering jobs. This class also provides useful query routines
* that are mostly used by the \ref Integrator implementations.
*/
class MTS_EXPORT_RENDER Scene : public NetworkedObject {
public:

View File

@ -20,6 +20,7 @@
#include <mitsuba/render/trimesh.h>
#include <mitsuba/core/fresolver.h>
#include <mitsuba/core/fstream.h>
#include <mitsuba/core/timer.h>
#include <mitsuba/render/track.h>
#include <dom/domCOLLADA.h>
#include <dae.h>
@ -224,7 +225,6 @@ VertexData *fetchVertexData(Transform transform,
result->typeToOffset[EUV] = offset;
result->typeToOffsetInStream[EUV] = offsetInStream;
result->typeToCount[EUV] = size;
cout << "Got texture coordinates.." << endl;
} else {
SLog(EWarn, "Found multiple sets of texture coordinates - ignoring!");
}
@ -420,7 +420,7 @@ void writeGeometry(ColladaContext &ctx, const std::string &prefixName, std::stri
}
SAssert(triangleIdx == 0);
SLog(EInfo, "\"%s/%s\": Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT
SLog(EDebug, "\"%s/%s\": Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT
" vertices (merged " SIZE_T_FMT " vertices).", prefixName.c_str(), id.c_str(),
triangles.size(), vertexBuffer.size(), numMerged);
@ -516,7 +516,7 @@ void exportAnimation(ColladaContext &ctx, const fs::path &path, const std::strin
continue;
trafo->addTrack(track);
}
SLog(EInfo, "Writing animation track \"%s\"", path.filename().c_str());
SLog(EDebug, "Writing animation track \"%s\"", path.filename().c_str());
ref<FileStream> fs = new FileStream(path, FileStream::ETruncReadWrite);
trafo->serialize(fs);
}
@ -537,7 +537,7 @@ void loadGeometry(ColladaContext &ctx, const std::string &instanceName,
}
TriangleMap triMap;
SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(),
SLog(EDebug, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(),
prefixName == "" ? "/" : prefixName.c_str());
domMesh *mesh = geom.getMesh().cast();
if (!mesh)
@ -938,7 +938,7 @@ void loadLight(ColladaContext &ctx, Transform transform, domLight &light) {
}
}
SLog(EInfo, "Converting light \"%s\" ..", identifier.c_str());
SLog(EDebug, "Converting light \"%s\" ..", identifier.c_str());
char *end_ptr = NULL;
// Lights in Mitsuba point along the positive Z axis (COLLADA: neg. Z)
@ -1039,7 +1039,7 @@ void loadImage(ColladaContext &ctx, domImage &image) {
}
}
SLog(EInfo, "Converting texture \"%s\" ..", identifier.c_str());
SLog(EDebug, "Converting texture \"%s\" ..", identifier.c_str());
std::string filename = cdom::uriToFilePath(image.getInit_from()->getValue().str());
if (ctx.fileToId.find(filename) != ctx.fileToId.end()) {
@ -1098,7 +1098,7 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
}
}
SLog(EInfo, "Converting camera \"%s\" ..", identifier.c_str());
SLog(EDebug, "Converting camera \"%s\" ..", identifier.c_str());
Float aspect = 1.0f;
int xres=768;
@ -1188,7 +1188,7 @@ void loadNode(ColladaContext &ctx, Transform transform, domNode &node, std::stri
}
}
prefixName = prefixName + std::string("/") + identifier;
SLog(EInfo, "Converting node \"%s\" ..", identifier.c_str());
SLog(EDebug, "Converting node \"%s\" ..", identifier.c_str());
daeTArray<daeSmartRef<daeElement> > children = node.getChildren();
/* Parse transformations */
@ -1341,7 +1341,7 @@ void loadAnimation(ColladaContext &ctx, domAnimation &anim) {
identifier = formatString("unnamedAnimation_%i", unnamedCtr);
}
}
SLog(EInfo, "Loading animation \"%s\" ..", identifier.c_str());
SLog(EDebug, "Loading animation \"%s\" ..", identifier.c_str());
domChannel_Array &channels = anim.getChannel_array();
for (size_t i=0; i<channels.getCount(); ++i) {
@ -1476,7 +1476,7 @@ void mergeRotations(ColladaContext &ctx) {
continue;
}
SLog(EInfo, "Converting rotation track of \"%s\" to quaternions ..",
SLog(EDebug, "Converting rotation track of \"%s\" to quaternions ..",
key.c_str());
std::set<Float> times;
@ -1606,7 +1606,10 @@ void GeometryConverter::convertCollada(const fs::path &inputFile,
ctx.cvt = this;
ctx.trackIndex = 0;
ref<Timer> timer = new Timer();
if (m_importMaterials) {
SLog(EInfo, "Importing materials ..");
domLibrary_images_Array &libraryImages = document->getLibrary_images_array();
for (size_t i=0; i<libraryImages.getCount(); ++i) {
domImage_Array &images = libraryImages[i]->getImage_array();
@ -1623,6 +1626,7 @@ void GeometryConverter::convertCollada(const fs::path &inputFile,
}
if (m_importAnimations) {
SLog(EInfo, "Importing animations ..");
domLibrary_animations_Array &libraryAnimations = document->getLibrary_animations_array();
for (size_t i=0; i<libraryAnimations.getCount(); ++i) {
domAnimation_Array &animations = libraryAnimations[i]->getAnimation_array();
@ -1632,6 +1636,7 @@ void GeometryConverter::convertCollada(const fs::path &inputFile,
mergeRotations(ctx);
}
SLog(EInfo, "Importing scene ..");
for (size_t i=0; i<nodes.getCount(); ++i)
computeRefCounts(ctx, *nodes[i]);
@ -1642,6 +1647,8 @@ void GeometryConverter::convertCollada(const fs::path &inputFile,
it != ctx.animations.end(); ++it)
it->second->decRef();
SLog(EInfo, "Done, took %s", timeToString(timer->getMilliseconds()/1000.0f).c_str());
os << "</scene>" << endl;
gluDeleteTess(tess);

View File

@ -51,20 +51,25 @@ public:
/// Draw the full scene using additive blending and shadow maps
void drawShadowedScene(const Scene *scene, const VPL &vpl) {
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>(scene->getCamera());
Point2 jitter(0.5f - m_random->nextFloat(), 0.5f - m_random->nextFloat());
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix());
Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse();
const std::vector<const TriMesh *> meshes = m_shaderManager->getMeshes();
Point camPos = scene->getCamera()->getPosition();
m_renderer->beginDrawingMeshes();
for (unsigned int j=0; j<meshes.size(); j++) {
m_shaderManager->configure(vpl, meshes[j]->getBSDF(),
meshes[j]->getLuminaire(), camPos,
!meshes[j]->hasVertexNormals());
m_renderer->drawTriMesh(meshes[j]);
const TriMesh *mesh = meshes[j].first;
bool hasTransform = !meshes[j].second.isIdentity();
m_shaderManager->configure(vpl, mesh->getBSDF(), mesh->getLuminaire(),
camPos, !mesh->hasVertexNormals());
if (hasTransform)
m_renderer->pushTransform(meshes[j].second);
m_renderer->drawTriMesh(mesh);
if (hasTransform)
m_renderer->popTransform();
m_shaderManager->unbind();
}
m_renderer->endDrawingMeshes();

View File

@ -529,13 +529,22 @@ void GLRenderer::endDrawingMeshes() {
}
}
void GLRenderer::drawAll() {
void GLRenderer::drawAll(const std::vector<std::pair<const GPUGeometry *, Transform> > &geo) {
GLfloat temp[16];
GLRenderer::beginDrawingMeshes(true);
std::map<const TriMesh *, GPUGeometry *>::iterator it;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
std::vector<std::pair<const GPUGeometry *, Transform> >::const_iterator it;
if (m_capabilities->isSupported(RendererCapabilities::EBindless)) {
for (it = m_geometry.begin(); it != m_geometry.end(); ++it) {
const TriMesh *mesh = static_cast<const TriMesh *>((*it).first);
const GLGeometry *geometry = static_cast<const GLGeometry *>((*it).second);
for (it = geo.begin(); it != geo.end(); ++it) {
const GLGeometry *geometry = static_cast<const GLGeometry *>(it->first);
const TriMesh *mesh = geometry->getTriMesh();
int pos=0;
for (int j=0; j<4; j++)
for (int i=0; i<4; i++)
temp[pos++] = (GLfloat) it->second.getMatrix().m[i][j];
glLoadMatrixf(temp);
int stride = geometry->m_stride;
if (stride != m_stride) {
glVertexFormatNV(3, GL_FLOAT, stride);
@ -568,11 +577,17 @@ void GLRenderer::drawAll() {
finish();
}
}
glPopMatrix();
}
} else {
for (it = m_geometry.begin(); it != m_geometry.end(); ++it) {
const TriMesh *mesh = static_cast<const TriMesh *>((*it).first);
const GLGeometry *geometry = static_cast<const GLGeometry *>((*it).second);
for (it = geo.begin(); it != geo.end(); ++it) {
const GLGeometry *geometry = static_cast<const GLGeometry *>(it->first);
const TriMesh *mesh = geometry->getTriMesh();
int pos=0;
for (int j=0; j<4; j++)
for (int i=0; i<4; i++)
temp[pos++] = (GLfloat) it->second.getMatrix().m[i][j];
glLoadMatrixf(temp);
glBindBuffer(GL_ARRAY_BUFFER, geometry->m_vertexID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->m_indexID);
@ -601,9 +616,11 @@ void GLRenderer::drawAll() {
finish();
}
}
glPopMatrix();
}
}
GLRenderer::endDrawingMeshes();
glPopMatrix();
}
void GLRenderer::blitTexture(const GPUTexture *tex, bool flipVertically,
@ -965,6 +982,23 @@ void GLRenderer::setColorMask(bool value) {
glColorMask(flag, flag, flag, flag);
}
void GLRenderer::pushTransform(const Transform &trafo) {
const Matrix4x4 &matrix = trafo.getMatrix();
GLfloat temp[16];
int pos=0;
for (int j=0; j<4; j++)
for (int i=0; i<4; i++)
temp[pos++] = (GLfloat) matrix.m[i][j];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(temp);
}
void GLRenderer::popTransform() {
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void GLRenderer::flush() {
glFlush();
}

View File

@ -97,9 +97,9 @@ void Renderer::unregisterShaderForResource(const HWResource *resource) {
}
}
void Renderer::registerGeometry(const TriMesh *mesh) {
GPUGeometry *Renderer::registerGeometry(const TriMesh *mesh) {
if (!m_capabilities->isSupported(RendererCapabilities::EVertexBufferObjects))
return;
return NULL;
GPUGeometry *geometry;
if (m_geometry.find(mesh) == m_geometry.end()) {
@ -110,6 +110,7 @@ void Renderer::registerGeometry(const TriMesh *mesh) {
geometry = m_geometry[mesh];
}
geometry->incRef();
return geometry;
}
void Renderer::unregisterGeometry(const TriMesh *mesh) {

View File

@ -20,6 +20,7 @@
#include <mitsuba/hw/vpl.h>
#include <mitsuba/hw/gpuprogram.h>
#include <mitsuba/hw/gputexture.h>
#include "../shapes/instance.h"
MTS_NAMESPACE_BEGIN
@ -41,7 +42,7 @@ void VPLShaderManager::init() {
m_shadowProgram->setSource(GPUProgram::EVertexProgram,
"void main() {\n"
" gl_Position = gl_Vertex;\n"
" gl_Position = gl_ModelViewMatrix * gl_Vertex;\n"
"}"
);
@ -94,7 +95,7 @@ void VPLShaderManager::init() {
"uniform vec4 depthVec;\n"
"varying float depth;\n"
"void main() {\n"
" gl_Position = cubeMapTransform * gl_Vertex;\n"
" gl_Position = gl_ModelViewMatrix * (cubeMapTransform * gl_Vertex);\n"
" depth = dot(depthVec, gl_Vertex);\n"
"}\n"
);
@ -120,15 +121,36 @@ void VPLShaderManager::init() {
for (size_t i=0; i<shapes.size(); ++i) {
ref<TriMesh> triMesh = shapes[i]->createTriMesh();
if (!triMesh)
if (!triMesh) {
std::string shapeClass = shapes[i]->getClass()->getName();
if (shapeClass == "Instance") {
const Instance *instance = static_cast<const Instance *>(shapes[i]);
const std::vector<const Shape *> &subShapes =
instance->getShapeGroup()->getKDTree()->getShapes();
for (size_t j=0; j<subShapes.size(); ++j) {
triMesh = const_cast<Shape *>(subShapes[j])->createTriMesh();
if (!triMesh)
continue;
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
Shader *shader = triMesh->hasBSDF() ?
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
if (shader != NULL && !shader->isComplete())
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
m_meshes.push_back(std::make_pair(triMesh.get(), instance->getWorldTransform()));
if (gpuGeo)
m_drawList.push_back(std::make_pair(gpuGeo, instance->getWorldTransform()));
}
}
continue;
m_renderer->registerGeometry(triMesh);
}
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
Shader *shader = triMesh->hasBSDF() ?
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
if (shader != NULL && !shader->isComplete())
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
triMesh->incRef();
m_meshes.push_back(triMesh);
m_meshes.push_back(std::make_pair(triMesh.get(), Transform()));
if (gpuGeo)
m_drawList.push_back(std::make_pair(gpuGeo, Transform()));
}
for (size_t i=0; i<luminaires.size(); ++i)
@ -170,6 +192,37 @@ void VPLShaderManager::init() {
m_initialized = true;
}
void VPLShaderManager::cleanup() {
for (std::map<std::string, ProgramAndConfiguration>::iterator it = m_programs.begin();
it != m_programs.end(); ++it) {
(*it).second.program->cleanup();
(*it).second.program->decRef();
}
if (m_shadowMap)
m_shadowMap->cleanup();
if (m_backgroundProgram) {
m_backgroundProgram->cleanup();
m_backgroundProgram = NULL;
}
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
for (size_t i=0; i<m_meshes.size(); ++i) {
m_renderer->unregisterGeometry(m_meshes[i].first);
m_renderer->unregisterShaderForResource(m_meshes[i].first->getBSDF());
}
m_meshes.clear();
m_drawList.clear();
for (size_t i=0; i<luminaires.size(); ++i)
m_renderer->unregisterShaderForResource(luminaires[i]);
m_initialized = false;
}
void VPLShaderManager::setVPL(const VPL &vpl) {
Point p = vpl.its.p + vpl.its.shFrame.n * 0.01;
Intersection its;
@ -224,6 +277,9 @@ void VPLShaderManager::setVPL(const VPL &vpl) {
m_nearClip = nearClip;
m_invClipRange = 1/(farClip-nearClip);
Transform lightViewTrafo, lightProjTrafo = Transform::glPerspective(90.0f, nearClip, farClip);
Matrix4x4 identity;
identity.setIdentity();
m_renderer->setCamera(identity, identity);
m_shadowMap->activateTarget();
if (m_singlePass && m_shadowProgram != NULL) {
@ -252,7 +308,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) {
(-viewMatrix.m[2][3] - m_nearClip) * m_invClipRange
));
}
m_renderer->drawAll();
m_renderer->drawAll(m_drawList);
m_shadowProgram->unbind();
} else {
/* Old-fashioned: render 6 times, once for each cube map face */
@ -278,7 +334,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) {
m_shadowMap->activateSide(i);
m_shadowMap->clear();
m_renderer->drawAll();
m_renderer->drawAll(m_drawList);
}
m_altShadowProgram->unbind();
@ -572,33 +628,5 @@ void VPLShaderManager::unbind() {
}
}
void VPLShaderManager::cleanup() {
for (std::map<std::string, ProgramAndConfiguration>::iterator it = m_programs.begin();
it != m_programs.end(); ++it) {
(*it).second.program->cleanup();
(*it).second.program->decRef();
}
if (m_shadowMap)
m_shadowMap->cleanup();
if (m_backgroundProgram) {
m_backgroundProgram->cleanup();
m_backgroundProgram = NULL;
}
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
for (size_t i=0; i<m_meshes.size(); ++i) {
m_renderer->unregisterGeometry(m_meshes[i]);
m_renderer->unregisterShaderForResource(m_meshes[i]->getBSDF());
m_meshes[i]->decRef();
}
m_meshes.clear();
for (size_t i=0; i<luminaires.size(); ++i)
m_renderer->unregisterShaderForResource(luminaires[i]);
m_initialized = false;
}
MTS_IMPLEMENT_CLASS(VPLShaderManager, false, Object)
MTS_NAMESPACE_END

View File

@ -464,7 +464,7 @@ void PreviewThread::run() {
}
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
const std::vector<const TriMesh *> meshes = m_shaderManager->getMeshes();
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
m_shaderManager->setVPL(vpl);
@ -488,9 +488,15 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_framebuffer->clear();
m_renderer->beginDrawingMeshes();
for (size_t j=0; j<meshes.size(); j++) {
m_shaderManager->configure(vpl, meshes[j]->getBSDF(),
meshes[j]->getLuminaire(), camPos, !meshes[j]->hasVertexNormals());
m_renderer->drawTriMesh(meshes[j]);
const TriMesh *mesh = meshes[j].first;
bool hasTransform = !meshes[j].second.isIdentity();
m_shaderManager->configure(vpl, mesh->getBSDF(),
mesh->getLuminaire(), camPos, !mesh->hasVertexNormals());
if (hasTransform)
m_renderer->pushTransform(meshes[j].second);
m_renderer->drawTriMesh(mesh);
if (hasTransform)
m_renderer->popTransform();
m_shaderManager->unbind();
}
m_renderer->endDrawingMeshes();

View File

@ -16,93 +16,85 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "shapegroup.h"
#include "instance.h"
MTS_NAMESPACE_BEGIN
class Instance : public Shape {
public:
Instance(const Properties &props) : Shape(props) {
m_objectToWorld = props.getTransform("toWorld", Transform());
m_worldToObject = m_objectToWorld.inverse();
}
Instance::Instance(const Properties &props) : Shape(props) {
m_objectToWorld = props.getTransform("toWorld", Transform());
m_worldToObject = m_objectToWorld.inverse();
}
Instance(Stream *stream, InstanceManager *manager)
: Shape(stream, manager) {
m_shapeGroup = static_cast<ShapeGroup *>(manager->getInstance(stream));
m_objectToWorld = Transform(stream);
m_worldToObject = m_objectToWorld.inverse();
}
Instance::Instance(Stream *stream, InstanceManager *manager)
: Shape(stream, manager) {
m_shapeGroup = static_cast<ShapeGroup *>(manager->getInstance(stream));
m_objectToWorld = Transform(stream);
m_worldToObject = m_objectToWorld.inverse();
}
void serialize(Stream *stream, InstanceManager *manager) const {
Shape::serialize(stream, manager);
m_objectToWorld.serialize(stream);
manager->serialize(stream, m_shapeGroup.get());
}
void Instance::serialize(Stream *stream, InstanceManager *manager) const {
Shape::serialize(stream, manager);
m_objectToWorld.serialize(stream);
manager->serialize(stream, m_shapeGroup.get());
}
void configure() {
if (!m_shapeGroup)
Log(EError, "A reference to a 'shapegroup' must be specified!");
}
void Instance::configure() {
if (!m_shapeGroup)
Log(EError, "A reference to a 'shapegroup' must be specified!");
}
AABB getAABB() const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
const AABB &aabb = kdtree->getAABB();
if (!aabb.isValid()) // the geometry group is empty
return aabb;
AABB result;
for (int i=0; i<8; ++i)
result.expandBy(m_objectToWorld(aabb.getCorner(i)));
return result;
}
AABB Instance::getAABB() const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
const AABB &aabb = kdtree->getAABB();
if (!aabb.isValid()) // the geometry group is empty
return aabb;
AABB result;
for (int i=0; i<8; ++i)
result.expandBy(m_objectToWorld(aabb.getCorner(i)));
return result;
}
Float getSurfaceArea() const {
Log(EError, "Instance::getSurfaceArea(): not supported!");
return 0.0f;
}
Float Instance::getSurfaceArea() const {
Log(EError, "Instance::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<ShapeGroup *>(child);
} else {
Shape::addChild(name, child);
}
void Instance::addChild(const std::string &name, ConfigurableObject *child) {
const Class *cClass = child->getClass();
if (cClass->getName() == "ShapeGroup") {
m_shapeGroup = static_cast<ShapeGroup *>(child);
} else {
Shape::addChild(name, child);
}
}
bool rayIntersect(const Ray &_ray, Float mint,
Float maxt, Float &t, void *temp) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
Ray ray;
m_worldToObject(_ray, ray);
return kdtree->rayIntersect(ray, mint, maxt, t, temp);
}
bool Instance::rayIntersect(const Ray &_ray, Float mint,
Float maxt, Float &t, void *temp) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
Ray ray;
m_worldToObject(_ray, ray);
return kdtree->rayIntersect(ray, mint, maxt, t, temp);
}
bool rayIntersect(const Ray &_ray, Float mint, Float maxt) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
Ray ray;
m_worldToObject(_ray, ray);
return kdtree->rayIntersect(ray, mint, maxt);
}
bool Instance::rayIntersect(const Ray &_ray, Float mint, Float maxt) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
Ray ray;
m_worldToObject(_ray, ray);
return kdtree->rayIntersect(ray, mint, maxt);
}
void fillIntersectionRecord(const Ray &ray,
const void *temp, Intersection &its) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
kdtree->fillIntersectionRecord<false>(ray, temp, its);
its.shFrame.n = normalize(m_objectToWorld(its.shFrame.n));
its.shFrame.s = normalize(m_objectToWorld(its.shFrame.s));
its.shFrame.t = normalize(m_objectToWorld(its.shFrame.t));
its.geoFrame = Frame(normalize(m_objectToWorld(its.geoFrame.n)));
its.wi = its.shFrame.toLocal(-ray.d);
its.dpdu = m_objectToWorld(its.dpdu);
its.dpdv = m_objectToWorld(its.dpdv);
}
MTS_DECLARE_CLASS()
private:
ref<ShapeGroup> m_shapeGroup;
Transform m_objectToWorld, m_worldToObject;
};
void Instance::fillIntersectionRecord(const Ray &ray,
const void *temp, Intersection &its) const {
const ShapeKDTree *kdtree = m_shapeGroup->getKDTree();
kdtree->fillIntersectionRecord<false>(ray, temp, its);
its.shFrame.n = normalize(m_objectToWorld(its.shFrame.n));
its.shFrame.s = normalize(m_objectToWorld(its.shFrame.s));
its.shFrame.t = normalize(m_objectToWorld(its.shFrame.t));
its.geoFrame = Frame(normalize(m_objectToWorld(its.geoFrame.n)));
its.wi = its.shFrame.toLocal(-ray.d);
its.dpdu = m_objectToWorld(its.dpdu);
its.dpdv = m_objectToWorld(its.dpdv);
}
MTS_IMPLEMENT_CLASS_S(Instance, false, Shape)
MTS_EXPORT_PLUGIN(Instance, "Instanced geometry");

80
src/shapes/instance.h Normal file
View File

@ -0,0 +1,80 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include "shapegroup.h"
MTS_NAMESPACE_BEGIN
/**
* \brief Geometry instancing support (to be used in conjunction
* with the \c shapegroup plugin)
*/
class Instance : public Shape {
public:
/// Create a new instance based on properties from an XML file
Instance(const Properties &props);
/// Unserialize from a binary data stream
Instance(Stream *stream, InstanceManager *manager);
/// Serialize to a binary data stream
void serialize(Stream *stream, InstanceManager *manager) const;
/** \brief Configure this object (called _once_ after construction
and addition of all child ConfigurableObjects.) */
void configure();
/// Return the object-to-world transformation used by this instance
inline Transform getWorldTransform() const { return m_objectToWorld; }
/// Add a child ConfigurableObject
void addChild(const std::string &name, ConfigurableObject *child);
/// Return a pointer to the associated \ref ShapeGroup
inline ShapeGroup* getShapeGroup() { return m_shapeGroup; }
/// Return a pointer to the associated \ref ShapeGroup (const version)
inline const ShapeGroup* getShapeGroup() const { return m_shapeGroup.get(); }
// =============================================================
//! @{ \name Implementation of the Shape interface
// =============================================================
AABB getAABB() const;
Float getSurfaceArea() const;
bool rayIntersect(const Ray &_ray, Float mint,
Float maxt, Float &t, void *temp) const;
bool rayIntersect(const Ray &_ray, Float mint, Float maxt) const;
void fillIntersectionRecord(const Ray &ray,
const void *temp, Intersection &its) const;
//! @}
// =============================================================
MTS_DECLARE_CLASS()
private:
ref<ShapeGroup> m_shapeGroup;
Transform m_objectToWorld, m_worldToObject;
};
MTS_NAMESPACE_END

View File

@ -25,10 +25,11 @@ MTS_NAMESPACE_BEGIN
/**
* \brief "Fake" shape that groups sub-shapes into a
* separate KD-tree. When this shape is used by itself,
* it doesn't actually generate any intersectable geometry.
* Instead, the "instance" plugin must be used to create
* references to the geometry stored inside it.
* separate KD-tree.
*
* This shape doesn't actually generate any intersectable
* geometry on its own. Instead, the "instance" plugin must
* be used to create references to the geometry stored inside it.
*/
class ShapeGroup : public Shape {
public:

44
src/tests/test_quad.cpp Normal file
View File

@ -0,0 +1,44 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/testcase.h>
#include <mitsuba/core/quad.h>
#include <boost/bind.hpp>
MTS_NAMESPACE_BEGIN
class TestQuadrature : public TestCase {
public:
MTS_BEGIN_TESTCASE()
MTS_DECLARE_TEST(test01_quad)
MTS_END_TESTCASE()
Float testF(Float t) const {
return std::sin(t);
}
void test01_quad() {
GaussLobattoIntegrator quad(1024, 0, 1e-6f);
Float result = quad.integrate(boost::bind(&TestQuadrature::testF, this, _1), 0, 10);
Float ref = 2 * std::pow(std::sin(5), 2);
assertEqualsEpsilon(result, ref, 1e-6f);
}
};
MTS_EXPORT_TESTCASE(TestQuadrature, "Testcase for quadrature routines")
MTS_NAMESPACE_END