instancing support in the realtine preview
parent
77bcff3550
commit
3e316e6efd
|
@ -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()
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue