realtime preview: render triangle approximations of analytic shapes
parent
9689d85377
commit
a3842d5e2c
|
@ -55,6 +55,9 @@ public:
|
||||||
/// Release bound resources
|
/// Release bound resources
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
|
/// Return all bound triangle meshes
|
||||||
|
inline const std::vector<const TriMesh *> &getMeshes() const { return m_meshes; }
|
||||||
|
|
||||||
/// Return the shadow cube map for debugging purposes
|
/// Return the shadow cube map for debugging purposes
|
||||||
inline GPUTexture *getShadowMap() { return m_shadowMap; }
|
inline GPUTexture *getShadowMap() { return m_shadowMap; }
|
||||||
|
|
||||||
|
@ -268,6 +271,7 @@ private:
|
||||||
VPLProgramConfiguration m_targetConfig;
|
VPLProgramConfiguration m_targetConfig;
|
||||||
ref<GPUProgram> m_backgroundProgram;
|
ref<GPUProgram> m_backgroundProgram;
|
||||||
VPLDependencyNode m_backgroundDependencies;
|
VPLDependencyNode m_backgroundDependencies;
|
||||||
|
std::vector<const TriMesh *> m_meshes;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -251,10 +251,22 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual const AbstractKDTree *getKDTree() const;
|
virtual const AbstractKDTree *getKDTree() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create a triangle mesh approximation of this shape
|
||||||
|
*
|
||||||
|
* This function is used by the realtime preview and
|
||||||
|
* certain integrators, which rely on hardware rasterization.
|
||||||
|
*
|
||||||
|
* The default implementation simply returns \a NULL.
|
||||||
|
*/
|
||||||
|
virtual ref<TriMesh> createTriMesh();
|
||||||
|
|
||||||
/// Return the shape's BSDF
|
/// Return the shape's BSDF
|
||||||
inline const BSDF *getBSDF() const { return m_bsdf.get(); }
|
inline const BSDF *getBSDF() const { return m_bsdf.get(); }
|
||||||
/// Return the shape's BSDF
|
/// Return the shape's BSDF
|
||||||
inline BSDF *getBSDF() { return m_bsdf.get(); }
|
inline BSDF *getBSDF() { return m_bsdf.get(); }
|
||||||
|
/// Set the BSDF of this shape
|
||||||
|
inline void setBSDF(BSDF *bsdf) { m_bsdf = bsdf; }
|
||||||
|
|
||||||
/// Return the name of this shape
|
/// Return the name of this shape
|
||||||
virtual std::string getName() const;
|
virtual std::string getName() const;
|
||||||
|
@ -272,6 +284,8 @@ public:
|
||||||
inline Luminaire *getLuminaire() { return m_luminaire; }
|
inline Luminaire *getLuminaire() { return m_luminaire; }
|
||||||
/// Return the associated luminaire (if any)
|
/// Return the associated luminaire (if any)
|
||||||
inline const Luminaire *getLuminaire() const { return m_luminaire.get(); }
|
inline const Luminaire *getLuminaire() const { return m_luminaire.get(); }
|
||||||
|
/// Set the luminaire of this shape
|
||||||
|
inline void setLuminaire(Luminaire *luminaire) { m_luminaire = luminaire; }
|
||||||
|
|
||||||
/// Called once after parsing
|
/// Called once after parsing
|
||||||
virtual void configure();
|
virtual void configure();
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#include <mitsuba/core/triangle.h>
|
#include <mitsuba/core/triangle.h>
|
||||||
#include <mitsuba/core/pdf.h>
|
#include <mitsuba/core/pdf.h>
|
||||||
#include <mitsuba/render/shape.h>
|
#include <mitsuba/render/shape.h>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -116,6 +119,20 @@ public:
|
||||||
/// Return the number of vertices
|
/// Return the number of vertices
|
||||||
inline size_t getVertexCount() const { return m_vertexCount; }
|
inline size_t getVertexCount() const { return m_vertexCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create a triangle mesh approximation of this shape
|
||||||
|
*
|
||||||
|
* Since instances are already triangle meshes, the implementation
|
||||||
|
* just returns a pointer to \a this.
|
||||||
|
*/
|
||||||
|
ref<TriMesh> createTriMesh();
|
||||||
|
|
||||||
|
/// Export an Wavefront OBJ version of this file
|
||||||
|
void writeOBJ(const fs::path &path) const;
|
||||||
|
|
||||||
|
/// Return the shape's BSDF
|
||||||
|
inline const BSDF *getBSDF() const { return m_bsdf.get(); }
|
||||||
|
|
||||||
/// Sample a point on the mesh
|
/// Sample a point on the mesh
|
||||||
Float sampleArea(ShapeSamplingRecord &sRec, const Point2 &sample) const;
|
Float sampleArea(ShapeSamplingRecord &sRec, const Point2 &sample) const;
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
||||||
m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix());
|
m_renderer->setCamera(projectionTransform.getMatrix(), camera->getViewTransform().getMatrix());
|
||||||
Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse();
|
Transform clipToWorld = camera->getViewTransform().inverse() * projectionTransform.inverse();
|
||||||
const std::vector<TriMesh *> meshes = scene->getMeshes();
|
const std::vector<const TriMesh *> meshes = m_shaderManager->getMeshes();
|
||||||
Point camPos = scene->getCamera()->getPosition();
|
Point camPos = scene->getCamera()->getPosition();
|
||||||
|
|
||||||
m_renderer->beginDrawingMeshes();
|
m_renderer->beginDrawingMeshes();
|
||||||
|
|
|
@ -115,14 +115,19 @@ void VPLShaderManager::init() {
|
||||||
m_altShadowProgramParam_depthVec =
|
m_altShadowProgramParam_depthVec =
|
||||||
m_altShadowProgram->getParameterID("depthVec");
|
m_altShadowProgram->getParameterID("depthVec");
|
||||||
|
|
||||||
const std::vector<TriMesh *> meshes = m_scene->getMeshes();
|
const std::vector<Shape *> shapes = m_scene->getShapes();
|
||||||
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
|
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
|
||||||
|
|
||||||
for (size_t i=0; i<meshes.size(); ++i) {
|
for (size_t i=0; i<shapes.size(); ++i) {
|
||||||
m_renderer->registerGeometry(meshes[i]);
|
ref<TriMesh> triMesh = shapes[i]->createTriMesh();
|
||||||
Shader *shader = m_renderer->registerShaderForResource(meshes[i]->getBSDF());
|
if (!triMesh)
|
||||||
|
continue;
|
||||||
|
m_renderer->registerGeometry(triMesh);
|
||||||
|
Shader *shader = m_renderer->registerShaderForResource(triMesh->getBSDF());
|
||||||
if (shader != NULL && !shader->isComplete())
|
if (shader != NULL && !shader->isComplete())
|
||||||
m_renderer->unregisterShaderForResource(meshes[i]->getBSDF());
|
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
|
||||||
|
triMesh->incRef();
|
||||||
|
m_meshes.push_back(triMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i=0; i<luminaires.size(); ++i)
|
for (size_t i=0; i<luminaires.size(); ++i)
|
||||||
|
@ -581,13 +586,14 @@ void VPLShaderManager::cleanup() {
|
||||||
m_backgroundProgram = NULL;
|
m_backgroundProgram = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<TriMesh *> meshes = m_scene->getMeshes();
|
|
||||||
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
|
const std::vector<Luminaire *> luminaires = m_scene->getLuminaires();
|
||||||
|
|
||||||
for (size_t i=0; i<meshes.size(); ++i) {
|
for (size_t i=0; i<m_meshes.size(); ++i) {
|
||||||
m_renderer->unregisterGeometry(meshes[i]);
|
m_renderer->unregisterGeometry(m_meshes[i]);
|
||||||
m_renderer->unregisterShaderForResource(meshes[i]->getBSDF());
|
m_renderer->unregisterShaderForResource(m_meshes[i]->getBSDF());
|
||||||
|
m_meshes[i]->decRef();
|
||||||
}
|
}
|
||||||
|
m_meshes.clear();
|
||||||
for (size_t i=0; i<luminaires.size(); ++i)
|
for (size_t i=0; i<luminaires.size(); ++i)
|
||||||
m_renderer->unregisterShaderForResource(luminaires[i]);
|
m_renderer->unregisterShaderForResource(luminaires[i]);
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
|
|
|
@ -146,6 +146,9 @@ Float Shape::pdfArea(const ShapeSamplingRecord &sRec) const {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<TriMesh> Shape::createTriMesh() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ShapeSamplingRecord::toString() const {
|
std::string ShapeSamplingRecord::toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
|
@ -465,6 +465,10 @@ void TriMesh::computeTangentSpaceBasis() {
|
||||||
m_name.c_str(), zeroArea, zeroNormals);
|
m_name.c_str(), zeroArea, zeroNormals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<TriMesh> TriMesh::createTriMesh() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
void TriMesh::serialize(Stream *stream, InstanceManager *manager) const {
|
void TriMesh::serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
Shape::serialize(stream, manager);
|
Shape::serialize(stream, manager);
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
@ -497,6 +501,46 @@ void TriMesh::serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
m_triangleCount * sizeof(Triangle)/sizeof(uint32_t));
|
m_triangleCount * sizeof(Triangle)/sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriMesh::writeOBJ(const fs::path &path) const {
|
||||||
|
fs::ofstream os(path);
|
||||||
|
os << "o " << m_name << endl;
|
||||||
|
for (size_t i=0; i<m_vertexCount; ++i) {
|
||||||
|
os << "v "
|
||||||
|
<< m_positions[i].x << " "
|
||||||
|
<< m_positions[i].y << " "
|
||||||
|
<< m_positions[i].z << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_normals) {
|
||||||
|
for (size_t i=0; i<m_vertexCount; ++i) {
|
||||||
|
os << "vn "
|
||||||
|
<< m_normals[i].x << " "
|
||||||
|
<< m_normals[i].y << " "
|
||||||
|
<< m_normals[i].z << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_normals) {
|
||||||
|
for (size_t i=0; i<m_triangleCount; ++i) {
|
||||||
|
os << "f "
|
||||||
|
<< m_triangles[i].idx[0] + 1 << "//"
|
||||||
|
<< m_triangles[i].idx[0] + 1 << " "
|
||||||
|
<< m_triangles[i].idx[1] + 1 << "//"
|
||||||
|
<< m_triangles[i].idx[1] + 1 << " "
|
||||||
|
<< m_triangles[i].idx[2] + 1 << "//"
|
||||||
|
<< m_triangles[i].idx[2] + 1 << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i=0; i<m_triangleCount; ++i) {
|
||||||
|
os << "f "
|
||||||
|
<< m_triangles[i].idx[0] + 1 << " "
|
||||||
|
<< m_triangles[i].idx[1] + 1 << " "
|
||||||
|
<< m_triangles[i].idx[2] + 1 << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
|
||||||
void TriMesh::serialize(Stream *_stream) const {
|
void TriMesh::serialize(Stream *_stream) const {
|
||||||
ref<Stream> stream = _stream;
|
ref<Stream> stream = _stream;
|
||||||
|
|
|
@ -463,7 +463,7 @@ void PreviewThread::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||||
const std::vector<TriMesh *> meshes = m_context->scene->getMeshes();
|
const std::vector<const TriMesh *> meshes = m_shaderManager->getMeshes();
|
||||||
|
|
||||||
m_shaderManager->setVPL(vpl);
|
m_shaderManager->setVPL(vpl);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <mitsuba/render/bsdf.h>
|
#include <mitsuba/render/bsdf.h>
|
||||||
#include <mitsuba/render/subsurface.h>
|
#include <mitsuba/render/subsurface.h>
|
||||||
#include <mitsuba/render/luminaire.h>
|
#include <mitsuba/render/luminaire.h>
|
||||||
|
#include <mitsuba/render/trimesh.h>
|
||||||
#include <mitsuba/core/properties.h>
|
#include <mitsuba/core/properties.h>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
@ -373,24 +374,59 @@ public:
|
||||||
return clippedAABB;
|
return clippedAABB;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
ref<TriMesh> createTriMesh() {
|
||||||
inline AABB getAABB(Float start, Float end) const {
|
/// Choice of discretization
|
||||||
AABB result;
|
const size_t phiSteps = 20;
|
||||||
const Float r = m_radius;
|
const Float dPhi = (2*M_PI) / phiSteps;
|
||||||
const Point a = m_objectToWorld(Point(0, 0, start));
|
|
||||||
const Point b = m_objectToWorld(Point(0, 0, end));
|
|
||||||
|
|
||||||
|
ref<TriMesh> mesh = new TriMesh("Cylinder approximation",
|
||||||
|
phiSteps*2, phiSteps*2, true, false, false);
|
||||||
|
|
||||||
|
Point *vertices = mesh->getVertexPositions();
|
||||||
|
Normal *normals = mesh->getVertexNormals();
|
||||||
|
Triangle *triangles = mesh->getTriangles();
|
||||||
|
size_t triangleIdx = 0, vertexIdx = 0;
|
||||||
|
|
||||||
|
for (size_t phi=0; phi<phiSteps; ++phi) {
|
||||||
|
Float sinPhi = std::sin(phi * dPhi);
|
||||||
|
Float cosPhi = std::cos(phi * dPhi);
|
||||||
|
int idx0 = vertexIdx, idx1 = idx0+1;
|
||||||
|
int idx2 = (vertexIdx+2) % (2*phiSteps), idx3 = idx2+1;
|
||||||
|
normals[vertexIdx] = m_objectToWorld(Normal(cosPhi, sinPhi, 0));
|
||||||
|
vertices[vertexIdx++] = m_objectToWorld(Point(cosPhi*m_radius, sinPhi*m_radius, 0));
|
||||||
|
normals[vertexIdx] = m_objectToWorld(Normal(cosPhi, sinPhi, 0));
|
||||||
|
vertices[vertexIdx++] = m_objectToWorld(Point(cosPhi*m_radius, sinPhi*m_radius, m_length));
|
||||||
|
|
||||||
|
triangles[triangleIdx].idx[0] = idx0;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx1;
|
||||||
|
triangleIdx++;
|
||||||
|
triangles[triangleIdx].idx[0] = idx1;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx3;
|
||||||
|
triangleIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->setBSDF(m_bsdf);
|
||||||
|
mesh->setLuminaire(m_luminaire);
|
||||||
|
mesh->configure();
|
||||||
|
|
||||||
|
return mesh.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
AABB getAABB() const {
|
||||||
|
const Point a = m_objectToWorld(Point(0, 0, 0));
|
||||||
|
const Point b = m_objectToWorld(Point(0, 0, m_length));
|
||||||
|
|
||||||
|
const Float r = m_radius;
|
||||||
|
AABB result;
|
||||||
result.expandBy(a - Vector(r, r, r));
|
result.expandBy(a - Vector(r, r, r));
|
||||||
result.expandBy(a + Vector(r, r, r));
|
result.expandBy(a + Vector(r, r, r));
|
||||||
result.expandBy(b - Vector(r, r, r));
|
result.expandBy(b - Vector(r, r, r));
|
||||||
result.expandBy(b + Vector(r, r, r));
|
result.expandBy(b + Vector(r, r, r));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AABB getAABB() const {
|
|
||||||
/* Very approximate .. */
|
|
||||||
return getAABB(0, m_length);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Float getSurfaceArea() const {
|
Float getSurfaceArea() const {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <mitsuba/render/subsurface.h>
|
#include <mitsuba/render/subsurface.h>
|
||||||
#include <mitsuba/render/luminaire.h>
|
#include <mitsuba/render/luminaire.h>
|
||||||
#include <mitsuba/render/gkdtree.h>
|
#include <mitsuba/render/gkdtree.h>
|
||||||
|
#include <mitsuba/render/trimesh.h>
|
||||||
#include <mitsuba/core/properties.h>
|
#include <mitsuba/core/properties.h>
|
||||||
#include <mitsuba/core/fstream.h>
|
#include <mitsuba/core/fstream.h>
|
||||||
#include <mitsuba/core/fresolver.h>
|
#include <mitsuba/core/fresolver.h>
|
||||||
|
@ -46,9 +47,10 @@ public:
|
||||||
for (size_t i=0; i<m_vertices.size()-1; i++)
|
for (size_t i=0; i<m_vertices.size()-1; i++)
|
||||||
if (!m_vertexStartsFiber[i+1])
|
if (!m_vertexStartsFiber[i+1])
|
||||||
m_segIndex.push_back(i);
|
m_segIndex.push_back(i);
|
||||||
|
m_segmentCount = m_segIndex.size();
|
||||||
|
|
||||||
Log(EDebug, "Building a kd-tree for " SIZE_T_FMT " hair vertices, "
|
Log(EDebug, "Building a kd-tree for " SIZE_T_FMT " hair vertices, "
|
||||||
SIZE_T_FMT " segments,", m_vertices.size(), m_segIndex.size());
|
SIZE_T_FMT " segments,", m_vertices.size(), m_segmentCount);
|
||||||
|
|
||||||
/* Ray-cylinder intersections are expensive. Use only the
|
/* Ray-cylinder intersections are expensive. Use only the
|
||||||
SAH cost as the tree subdivision stopping criterion,
|
SAH cost as the tree subdivision stopping criterion,
|
||||||
|
@ -91,6 +93,11 @@ public:
|
||||||
return m_radius;
|
return m_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the total number of segments
|
||||||
|
inline size_t getSegmentCount() const {
|
||||||
|
return m_segmentCount;
|
||||||
|
}
|
||||||
|
|
||||||
/// Intersect a ray with all segments stored in the kd-tree
|
/// Intersect a ray with all segments stored in the kd-tree
|
||||||
inline bool rayIntersect(const Ray &ray, Float _mint, Float _maxt,
|
inline bool rayIntersect(const Ray &ray, Float _mint, Float _maxt,
|
||||||
Float &t, void *temp) const {
|
Float &t, void *temp) const {
|
||||||
|
@ -247,6 +254,7 @@ protected:
|
||||||
std::vector<Point> m_vertices;
|
std::vector<Point> m_vertices;
|
||||||
std::vector<bool> m_vertexStartsFiber;
|
std::vector<bool> m_vertexStartsFiber;
|
||||||
std::vector<index_type> m_segIndex;
|
std::vector<index_type> m_segIndex;
|
||||||
|
size_t m_segmentCount;
|
||||||
Float m_radius;
|
Float m_radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -366,6 +374,74 @@ public:
|
||||||
its.shape = this;
|
its.shape = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<TriMesh> createTriMesh() {
|
||||||
|
/// Choice of discretization
|
||||||
|
const size_t phiSteps = 6;
|
||||||
|
const Float dPhi = (2*M_PI) / phiSteps;
|
||||||
|
|
||||||
|
size_t nSegments = m_kdtree->getSegmentCount();
|
||||||
|
ref<TriMesh> mesh = new TriMesh("Hair mesh approximation",
|
||||||
|
phiSteps*2*nSegments, phiSteps*2*nSegments, true, false, false);
|
||||||
|
|
||||||
|
Point *vertices = mesh->getVertexPositions();
|
||||||
|
Normal *normals = mesh->getVertexNormals();
|
||||||
|
Triangle *triangles = mesh->getTriangles();
|
||||||
|
size_t triangleIdx = 0, vertexIdx = 0;
|
||||||
|
|
||||||
|
const std::vector<Point> &hairVertices = m_kdtree->getVertices();
|
||||||
|
const std::vector<bool> &vertexStartsFiber = m_kdtree->getStartFiber();
|
||||||
|
const Float radius = m_kdtree->getRadius();
|
||||||
|
Float *cosPhi = new Float[phiSteps];
|
||||||
|
Float *sinPhi = new Float[phiSteps];
|
||||||
|
for (size_t i=0; i<phiSteps; ++i) {
|
||||||
|
sinPhi[i] = std::sin(i*dPhi);
|
||||||
|
cosPhi[i] = std::cos(i*dPhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hairIdx = 0;
|
||||||
|
for (size_t iv=0; iv<hairVertices.size()-1; iv++) {
|
||||||
|
if (!vertexStartsFiber[iv+1]) {
|
||||||
|
for (size_t phi=0; phi<phiSteps; ++phi) {
|
||||||
|
Vector tangent = m_kdtree->tangent(iv);
|
||||||
|
Vector dir = Normal(Frame(tangent).toWorld(
|
||||||
|
Vector(cosPhi[phi], sinPhi[phi], 0)));
|
||||||
|
Normal miterNormal1 = m_kdtree->firstMiterNormal(iv);
|
||||||
|
Normal miterNormal2 = m_kdtree->secondMiterNormal(iv);
|
||||||
|
Float t1 = dot(miterNormal1, radius*dir) / dot(miterNormal1, tangent);
|
||||||
|
Float t2 = dot(miterNormal2, radius*dir) / dot(miterNormal2, tangent);
|
||||||
|
|
||||||
|
normals[vertexIdx] = Normal(dir);
|
||||||
|
vertices[vertexIdx++] = m_kdtree->firstVertex(iv) + radius*dir - tangent*t1;
|
||||||
|
normals[vertexIdx] = Normal(dir);
|
||||||
|
vertices[vertexIdx++] = m_kdtree->secondVertex(iv) + radius*dir - tangent*t2;
|
||||||
|
|
||||||
|
int idx0 = 2*(phi + hairIdx*phiSteps), idx1 = idx0+1;
|
||||||
|
int idx2 = (2*phi+2) % (2*phiSteps) + 2*hairIdx*phiSteps, idx3 = idx2+1;
|
||||||
|
triangles[triangleIdx].idx[0] = idx0;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx1;
|
||||||
|
triangleIdx++;
|
||||||
|
triangles[triangleIdx].idx[0] = idx1;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx3;
|
||||||
|
triangleIdx++;
|
||||||
|
}
|
||||||
|
hairIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert(triangleIdx == phiSteps*2*nSegments);
|
||||||
|
Assert(vertexIdx == phiSteps*2*nSegments);
|
||||||
|
|
||||||
|
delete[] cosPhi;
|
||||||
|
delete[] sinPhi;
|
||||||
|
|
||||||
|
mesh->setBSDF(m_bsdf);
|
||||||
|
mesh->setLuminaire(m_luminaire);
|
||||||
|
mesh->configure();
|
||||||
|
|
||||||
|
return mesh.get();
|
||||||
|
}
|
||||||
|
|
||||||
const AbstractKDTree *getKDTree() const {
|
const AbstractKDTree *getKDTree() const {
|
||||||
return m_kdtree.get();
|
return m_kdtree.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <mitsuba/render/bsdf.h>
|
#include <mitsuba/render/bsdf.h>
|
||||||
#include <mitsuba/render/luminaire.h>
|
#include <mitsuba/render/luminaire.h>
|
||||||
#include <mitsuba/render/subsurface.h>
|
#include <mitsuba/render/subsurface.h>
|
||||||
|
#include <mitsuba/render/trimesh.h>
|
||||||
#include <mitsuba/core/properties.h>
|
#include <mitsuba/core/properties.h>
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
@ -258,6 +259,93 @@ public:
|
||||||
return squareToConePdf(cosThetaMax);
|
return squareToConePdf(cosThetaMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<TriMesh> createTriMesh() {
|
||||||
|
/// Choice of discretization
|
||||||
|
const size_t thetaSteps = 20;
|
||||||
|
const size_t phiSteps = thetaSteps * 2;
|
||||||
|
const Float dTheta = M_PI / (thetaSteps-1);
|
||||||
|
const Float dPhi = (2*M_PI) / phiSteps;
|
||||||
|
size_t topIdx = (thetaSteps-2) * phiSteps, botIdx = topIdx+1;
|
||||||
|
|
||||||
|
/// Precompute cosine and sine tables
|
||||||
|
Float *cosPhi = new Float[phiSteps];
|
||||||
|
Float *sinPhi = new Float[phiSteps];
|
||||||
|
for (size_t i=0; i<phiSteps; ++i) {
|
||||||
|
sinPhi[i] = std::sin(i*dPhi);
|
||||||
|
cosPhi[i] = std::cos(i*dPhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numTris = 2 * phiSteps * (thetaSteps-2);
|
||||||
|
|
||||||
|
ref<TriMesh> mesh = new TriMesh("Sphere approximation",
|
||||||
|
numTris, botIdx+1, true, false, false);
|
||||||
|
|
||||||
|
Point *vertices = mesh->getVertexPositions();
|
||||||
|
Normal *normals = mesh->getVertexNormals();
|
||||||
|
Triangle *triangles = mesh->getTriangles();
|
||||||
|
size_t vertexIdx = 0;
|
||||||
|
for (size_t theta=1; theta<thetaSteps-1; ++theta) {
|
||||||
|
Float sinTheta = std::sin(theta * dTheta);
|
||||||
|
Float cosTheta = std::cos(theta * dTheta);
|
||||||
|
|
||||||
|
for (size_t phi=0; phi<phiSteps; ++phi) {
|
||||||
|
Vector v(
|
||||||
|
sinTheta * cosPhi[phi],
|
||||||
|
sinTheta * sinPhi[phi],
|
||||||
|
cosTheta
|
||||||
|
);
|
||||||
|
vertices[vertexIdx] = m_objectToWorld(Point(v*m_radius));
|
||||||
|
normals[vertexIdx++] = m_objectToWorld(Normal(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertices[vertexIdx] = m_objectToWorld(Point(0, 0, m_radius));
|
||||||
|
normals[vertexIdx++] = m_objectToWorld(Normal(0, 0, 1));
|
||||||
|
vertices[vertexIdx] = m_objectToWorld(Point(0, 0, -m_radius));
|
||||||
|
normals[vertexIdx++] = m_objectToWorld(Normal(0, 0, -1));
|
||||||
|
Assert(vertexIdx == botIdx+1);
|
||||||
|
|
||||||
|
size_t triangleIdx = 0;
|
||||||
|
for (size_t theta=1; theta<thetaSteps; ++theta) {
|
||||||
|
for (size_t phi=0; phi<phiSteps; ++phi) {
|
||||||
|
size_t nextPhi = (phi + 1) % phiSteps;
|
||||||
|
size_t idx0, idx1, idx2, idx3;
|
||||||
|
if (theta == 1) {
|
||||||
|
idx0 = idx1 = topIdx;
|
||||||
|
} else {
|
||||||
|
idx0 = phiSteps*(theta-2) + phi;
|
||||||
|
idx1 = phiSteps*(theta-2) + nextPhi;
|
||||||
|
}
|
||||||
|
if (theta == thetaSteps-1) {
|
||||||
|
idx2 = idx3 = botIdx;
|
||||||
|
} else {
|
||||||
|
idx2 = phiSteps*(theta-1) + phi;
|
||||||
|
idx3 = phiSteps*(theta-1) + nextPhi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx0 != idx1) {
|
||||||
|
triangles[triangleIdx].idx[0] = idx0;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx1;
|
||||||
|
triangleIdx++;
|
||||||
|
}
|
||||||
|
if (idx2 != idx3) {
|
||||||
|
triangles[triangleIdx].idx[0] = idx1;
|
||||||
|
triangles[triangleIdx].idx[1] = idx2;
|
||||||
|
triangles[triangleIdx].idx[2] = idx3;
|
||||||
|
triangleIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert(triangleIdx == numTris);
|
||||||
|
delete[] cosPhi;
|
||||||
|
delete[] sinPhi;
|
||||||
|
mesh->setBSDF(m_bsdf);
|
||||||
|
mesh->setLuminaire(m_luminaire);
|
||||||
|
mesh->configure();
|
||||||
|
|
||||||
|
return mesh.get();
|
||||||
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Sphere[" << endl
|
oss << "Sphere[" << endl
|
||||||
|
|
Loading…
Reference in New Issue