support for constructing triangle meshes from within python
parent
b68a38ed9a
commit
0ee249c434
|
@ -395,3 +395,40 @@ A useful property of this approach is that scene loading and initialization
|
|||
must only take place once. Performance-wise, this compares favourably with
|
||||
running many separate rendering jobs, e.g. using the \code{mitsuba}
|
||||
command-line executable.
|
||||
|
||||
\subsection{Creating triangle-based shapes}
|
||||
It is possible to create new triangle-based shapes directly in Python, though
|
||||
doing so is discouraged: because Python is an interpreted programming language,
|
||||
the construction of large meshes will run very slowly. The builtin shapes
|
||||
and shape loaders are to be preferred when this is an option. That said, the
|
||||
following snippet shows how to create \code{TriMesh} objects from within Python:
|
||||
\begin{python}
|
||||
# Create a new mesh with 1 triangle, 3 vertices,
|
||||
# and allocate buffers for normals and texture coordinates
|
||||
mesh = TriMesh('Name of this mesh', 1, 3, True, True)
|
||||
|
||||
v = mesh.getVertexPositions()
|
||||
v[0] = Point3(0, 0, 0)
|
||||
v[1] = Point3(1, 0, 0)
|
||||
v[2] = Point3(0, 1, 0)
|
||||
|
||||
n = mesh.getVertexNormals()
|
||||
n[0] = Normal(0, 0, 1)
|
||||
n[1] = Normal(0, 0, 1)
|
||||
n[2] = Normal(0, 0, 1)
|
||||
|
||||
t = mesh.getTriangles() # Indexed triangle list: tri 1 references vertices 0,1,2
|
||||
t[0] = 0
|
||||
t[1] = 1
|
||||
t[2] = 2
|
||||
|
||||
uv = mesh.getTexcoords()
|
||||
uv[0] = Point2(0, 0)
|
||||
uv[1] = Point2(1, 0)
|
||||
uv[2] = Point2(0, 1)
|
||||
|
||||
mesh.configure()
|
||||
|
||||
# Add to a scene (assumes 'scene' is available)
|
||||
sensor.addChild(mesh)
|
||||
\end{python}
|
||||
|
|
|
@ -501,6 +501,14 @@ public:
|
|||
return value;
|
||||
}
|
||||
|
||||
/// Component-wise logarithm
|
||||
inline TSpectrum log() const {
|
||||
TSpectrum value;
|
||||
for (int i=0; i<N; i++)
|
||||
value.s[i] = math::fastlog(s[i]);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Component-wise exponentation
|
||||
inline TSpectrum exp() const {
|
||||
TSpectrum value;
|
||||
|
@ -591,6 +599,7 @@ protected:
|
|||
/** \brief RGB color data type
|
||||
*
|
||||
* \ingroup libcore
|
||||
* \ingroup libpython
|
||||
*/
|
||||
struct MTS_EXPORT_CORE Color3 : public TSpectrum<Float, 3> {
|
||||
public:
|
||||
|
@ -616,6 +625,11 @@ public:
|
|||
inline Color3(Float r, Float g, Float b) {
|
||||
s[0] = r; s[1] = g; s[2] = b;
|
||||
}
|
||||
|
||||
/// Return the luminance (assuming the color value is expressed in linear sRGB)
|
||||
inline Float getLuminance() const {
|
||||
return s[0] * 0.212671f + s[1] * 0.715160f + s[2] * 0.072169f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* necessarily orthogonal.
|
||||
*
|
||||
* \ingroup librender
|
||||
* \ingroup libpython
|
||||
*/
|
||||
struct TangentSpace {
|
||||
/// Position partial with respect to the U parameter of the local chart
|
||||
|
@ -42,6 +43,8 @@ struct TangentSpace {
|
|||
Vector dpdv;
|
||||
|
||||
inline TangentSpace() { }
|
||||
inline TangentSpace(const Vector &dpdu, const Vector &dpdv)
|
||||
: dpdu(dpdu), dpdv(dpdv) { }
|
||||
inline TangentSpace(Stream *stream) :
|
||||
dpdu(stream), dpdv(stream) {
|
||||
}
|
||||
|
@ -50,6 +53,12 @@ struct TangentSpace {
|
|||
dpdu.serialize(stream);
|
||||
dpdv.serialize(stream);
|
||||
}
|
||||
|
||||
inline std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "TangentSpace[dpdu=" << dpdu.toString() << ", dpdv=" << dpdv.toString() << "]";
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief Abstract triangle mesh base class
|
||||
|
|
|
@ -184,7 +184,7 @@ public:
|
|||
using namespace mitsuba;
|
||||
|
||||
if (i < 0 || i >= Size) {
|
||||
SLog(EError, "Index %i is out of range!", i);
|
||||
SLog(mitsuba::EError, "Index %i is out of range!", i);
|
||||
return (Scalar) 0;
|
||||
}
|
||||
return value[i];
|
||||
|
@ -194,7 +194,7 @@ public:
|
|||
using namespace mitsuba;
|
||||
|
||||
if (i < 0 || i >= Size)
|
||||
SLog(EError, "Index %i is out of range!", i);
|
||||
SLog(mitsuba::EError, "Index %i is out of range!", i);
|
||||
else
|
||||
value[i] = arg;
|
||||
}
|
||||
|
@ -204,6 +204,37 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Value> struct InternalArray {
|
||||
public:
|
||||
InternalArray(mitsuba::Object *obj, Value *ptr, size_t length) : obj(obj), ptr(ptr), length(length) { }
|
||||
InternalArray(const InternalArray &a) : obj(a.obj), ptr(a.ptr), length(a.length) { }
|
||||
|
||||
inline int len() { return (int) this->length; }
|
||||
|
||||
Value get(int i) {
|
||||
if (i < 0 || (size_t) i >= length)
|
||||
SLog(mitsuba::EError, "Index %i is out of range!", i);
|
||||
return ptr[i];
|
||||
}
|
||||
|
||||
void set(int i, Value value) {
|
||||
if (i < 0 || (size_t) i >= length)
|
||||
SLog(mitsuba::EError, "Index %i is out of range!", i);
|
||||
ptr[i] = value;
|
||||
}
|
||||
private:
|
||||
mitsuba::ref<mitsuba::Object> obj;
|
||||
Value *ptr;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
#define BP_INTERNAL_ARRAY(Name) \
|
||||
BP_STRUCT(Name, bp::no_init) \
|
||||
.def("__len__", &Name::len) \
|
||||
.def("__getitem__", &Name::get) \
|
||||
.def("__setitem__", &Name::set)
|
||||
|
||||
|
||||
namespace mitsuba {
|
||||
class SerializableObject;
|
||||
class ConfigurableObject;
|
||||
|
|
|
@ -56,25 +56,25 @@ void shutdownFramework() {
|
|||
Class::staticShutdown();
|
||||
}
|
||||
|
||||
class spectrum_wrapper {
|
||||
template <typename SpectrumType> class SpectrumWrapper {
|
||||
public:
|
||||
static Float get(const Spectrum &spec, int i) {
|
||||
if (i < 0 || i >= SPECTRUM_SAMPLES) {
|
||||
static Float get(const SpectrumType &spec, int i) {
|
||||
if (i < 0 || i >= SpectrumType::dim) {
|
||||
SLog(EError, "Index %i is out of range!", i);
|
||||
return 0.0f;
|
||||
}
|
||||
return spec[i];
|
||||
}
|
||||
|
||||
static void set(Spectrum &spec, int i, Float value) {
|
||||
if (i < 0 || i >= SPECTRUM_SAMPLES)
|
||||
static void set(SpectrumType &spec, int i, Float value) {
|
||||
if (i < 0 || i >= SpectrumType::dim)
|
||||
SLog(EError, "Index %i is out of range!", i);
|
||||
else
|
||||
spec[i] = value;
|
||||
}
|
||||
|
||||
static int len(Spectrum &) {
|
||||
return SPECTRUM_SAMPLES;
|
||||
static int len(SpectrumType &) {
|
||||
return SpectrumType::dim;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1092,6 +1092,41 @@ void export_core() {
|
|||
.def("getSpatialBounds", &AnimatedTransform::getSpatialBounds, BP_RETURN_VALUE)
|
||||
.def("eval", &AnimatedTransform::eval, BP_RETURN_VALUE);
|
||||
|
||||
BP_STRUCT(Color3, bp::init<>())
|
||||
.def(bp::init<Float>())
|
||||
.def(bp::init<Float, Float, Float>())
|
||||
.def(bp::self != bp::self)
|
||||
.def(bp::self == bp::self)
|
||||
.def(-bp::self)
|
||||
.def(bp::self + bp::self)
|
||||
.def(bp::self += bp::self)
|
||||
.def(bp::self - bp::self)
|
||||
.def(bp::self -= bp::self)
|
||||
.def(bp::self *= Float())
|
||||
.def(bp::self * Float())
|
||||
.def(bp::self *= bp::self)
|
||||
.def(bp::self * bp::self)
|
||||
.def(bp::self / Float())
|
||||
.def(bp::self /= Float())
|
||||
.def(bp::self /= bp::self)
|
||||
.def(bp::self / bp::self)
|
||||
.def("isValid", &Color3::isValid)
|
||||
.def("isNaN", &Color3::isNaN)
|
||||
.def("average", &Color3::average)
|
||||
.def("sqrt", &Color3::sqrt)
|
||||
.def("exp", &Color3::exp)
|
||||
.def("log", &Color3::log)
|
||||
.def("pow", &Color3::pow)
|
||||
.def("clampNegative", &Color3::clampNegative)
|
||||
.def("min", &Color3::min)
|
||||
.def("max", &Color3::max)
|
||||
.def("isZero", &Color3::isZero)
|
||||
.def("getLuminance", &Color3::getLuminance)
|
||||
.def("__repr__", &Color3::toString)
|
||||
.def("__len__", &SpectrumWrapper<Color3>::len)
|
||||
.def("__getitem__", &SpectrumWrapper<Color3>::get)
|
||||
.def("__setitem__", &SpectrumWrapper<Color3>::set);
|
||||
|
||||
BP_STRUCT(Spectrum, bp::init<>())
|
||||
.def("__init__", bp::make_constructor(spectrum_array_constructor))
|
||||
.def(bp::init<Float>())
|
||||
|
@ -1115,7 +1150,9 @@ void export_core() {
|
|||
.def("isNaN", &Spectrum::isNaN)
|
||||
.def("average", &Spectrum::average)
|
||||
.def("sqrt", &Spectrum::sqrt)
|
||||
.def("safe_sqrt", &Spectrum::safe_sqrt)
|
||||
.def("exp", &Spectrum::exp)
|
||||
.def("log", &Spectrum::log)
|
||||
.def("pow", &Spectrum::pow)
|
||||
.def("clampNegative", &Spectrum::clampNegative)
|
||||
.def("min", &Spectrum::min)
|
||||
|
@ -1134,9 +1171,9 @@ void export_core() {
|
|||
.def("fromContinuousSpectrum", &Spectrum::fromContinuousSpectrum)
|
||||
.def("serialize", &Spectrum::serialize)
|
||||
.def("__repr__", &Spectrum::toString)
|
||||
.def("__len__", &spectrum_wrapper::len)
|
||||
.def("__getitem__", &spectrum_wrapper::get)
|
||||
.def("__setitem__", &spectrum_wrapper::set);
|
||||
.def("__len__", &SpectrumWrapper<Spectrum>::len)
|
||||
.def("__getitem__", &SpectrumWrapper<Spectrum>::get)
|
||||
.def("__setitem__", &SpectrumWrapper<Spectrum>::set);
|
||||
|
||||
BP_SETSCOPE(Spectrum_struct);
|
||||
bp::enum_<Spectrum::EConversionIntent>("EConversionIntent")
|
||||
|
|
|
@ -125,6 +125,39 @@ bp::list scene_getMedia(Scene *scene) {
|
|||
return list;
|
||||
}
|
||||
|
||||
|
||||
typedef InternalArray<uint32_t> InternalUInt32Array;
|
||||
typedef InternalArray<Point3> InternalPoint3Array;
|
||||
typedef InternalArray<Normal> InternalNormalArray;
|
||||
typedef InternalArray<Point2> InternalPoint2Array;
|
||||
typedef InternalArray<Color3> InternalColor3Array;
|
||||
typedef InternalArray<TangentSpace> InternalTangentSpaceArray;
|
||||
|
||||
InternalUInt32Array trimesh_getTriangles(TriMesh *triMesh) {
|
||||
BOOST_STATIC_ASSERT(sizeof(Triangle) == 3*sizeof(uint32_t));
|
||||
return InternalUInt32Array(triMesh, (uint32_t *) triMesh->getTriangles(), triMesh->getTriangleCount()*3);
|
||||
}
|
||||
|
||||
InternalPoint3Array trimesh_getVertexPositions(TriMesh *triMesh) {
|
||||
return InternalPoint3Array(triMesh, triMesh->getVertexPositions(), triMesh->getVertexCount());
|
||||
}
|
||||
|
||||
InternalNormalArray trimesh_getVertexNormals(TriMesh *triMesh) {
|
||||
return InternalNormalArray(triMesh, triMesh->getVertexNormals(), triMesh->getVertexCount());
|
||||
}
|
||||
|
||||
InternalPoint2Array trimesh_getVertexTexcoords(TriMesh *triMesh) {
|
||||
return InternalPoint2Array(triMesh, triMesh->getVertexTexcoords(), triMesh->getVertexCount());
|
||||
}
|
||||
|
||||
InternalColor3Array trimesh_getVertexColors(TriMesh *triMesh) {
|
||||
return InternalColor3Array(triMesh, triMesh->getVertexColors(), triMesh->getVertexCount());
|
||||
}
|
||||
|
||||
InternalTangentSpaceArray trimesh_getUVTangents(TriMesh *triMesh) {
|
||||
return InternalTangentSpaceArray(triMesh, triMesh->getUVTangents(), triMesh->getVertexCount());
|
||||
}
|
||||
|
||||
void export_render() {
|
||||
bp::object renderModule(
|
||||
bp::handle<>(bp::borrowed(PyImport_AddModule("mitsuba.render"))));
|
||||
|
@ -133,6 +166,13 @@ void export_render() {
|
|||
|
||||
BP_SETSCOPE(renderModule);
|
||||
|
||||
BP_INTERNAL_ARRAY(InternalUInt32Array);
|
||||
BP_INTERNAL_ARRAY(InternalPoint3Array);
|
||||
BP_INTERNAL_ARRAY(InternalPoint2Array);
|
||||
BP_INTERNAL_ARRAY(InternalColor3Array);
|
||||
BP_INTERNAL_ARRAY(InternalNormalArray);
|
||||
BP_INTERNAL_ARRAY(InternalTangentSpaceArray);
|
||||
|
||||
bp::enum_<ETransportMode>("ETransportMode")
|
||||
.value("ERadiance", ERadiance)
|
||||
.value("EImportance", EImportance)
|
||||
|
@ -230,9 +270,7 @@ void export_render() {
|
|||
.staticmethod("loadScene");
|
||||
|
||||
BP_CLASS(RenderJob, Thread, (bp::init<const std::string &, Scene *, RenderQueue *>()))
|
||||
.def(bp::init<const std::string &, Scene *, RenderQueue *, int>())
|
||||
.def(bp::init<const std::string &, Scene *, RenderQueue *, int, int>())
|
||||
.def(bp::init<const std::string &, Scene *, RenderQueue *, int, int, int>())
|
||||
.def(bp::init<const std::string &, Scene *, RenderQueue *, int, bp::optional<int, int> >())
|
||||
.def("flush", &RenderJob::flush)
|
||||
.def("cancel", &RenderJob::cancel)
|
||||
.def("wait", &RenderJob::wait);
|
||||
|
@ -275,6 +313,14 @@ void export_render() {
|
|||
.def("LoSub", &Intersection::LoSub)
|
||||
.def("__repr__", &Intersection::toString);
|
||||
|
||||
BP_STRUCT(TangentSpace, bp::init<>())
|
||||
.def(bp::init<Vector, Vector>())
|
||||
.def(bp::init<Stream *>())
|
||||
.def_readwrite("dpdu", &TangentSpace::dpdu)
|
||||
.def_readwrite("dpdv", &TangentSpace::dpdv)
|
||||
.def("serialize", &TangentSpace::serialize)
|
||||
.def("__repr__", &TangentSpace::toString);
|
||||
|
||||
BP_STRUCT(PositionSamplingRecord, bp::init<>())
|
||||
.def(bp::init<Float>())
|
||||
.def(bp::init<Intersection, EMeasure>())
|
||||
|
@ -340,20 +386,27 @@ void export_render() {
|
|||
.def("hasBSDF", &Shape::hasBSDF)
|
||||
.def("getBSDF", shape_getBSDF, BP_RETURN_VALUE)
|
||||
.def("getPrimitiveCount", &Shape::getPrimitiveCount)
|
||||
.def("getEffectivePrimitiveCount", &Shape::getEffectivePrimitiveCount);
|
||||
.def("getEffectivePrimitiveCount", &Shape::getEffectivePrimitiveCount)
|
||||
.def("copyAttachments", &Shape::copyAttachments);
|
||||
|
||||
void (TriMesh::*triMesh_serialize1)(Stream *stream) const = &TriMesh::serialize;
|
||||
void (TriMesh::*triMesh_serialize2)(Stream *stream, InstanceManager *) const = &TriMesh::serialize;
|
||||
|
||||
BP_CLASS(TriMesh, Shape, (bp::init<std::string, size_t, size_t, bool, bool, bool, bool, bool>()))
|
||||
BP_CLASS(TriMesh, Shape, (bp::init<std::string, size_t, size_t, bp::optional<bool, bool, bool, bool, bool> >()))
|
||||
.def(bp::init<Stream *, InstanceManager *>())
|
||||
.def(bp::init<Stream *, int>())
|
||||
.def("getTriangleCount", &TriMesh::getTriangleCount)
|
||||
.def("getTriangles", trimesh_getTriangles)
|
||||
.def("getVertexCount", &TriMesh::getVertexCount)
|
||||
.def("getVertexPositions", trimesh_getVertexPositions, BP_RETURN_VALUE)
|
||||
.def("hasVertexNormals", &TriMesh::hasVertexNormals)
|
||||
.def("getVertexNormals", trimesh_getVertexNormals, BP_RETURN_VALUE)
|
||||
.def("hasVertexColors", &TriMesh::hasVertexColors)
|
||||
.def("getVertexColors", trimesh_getVertexColors, BP_RETURN_VALUE)
|
||||
.def("hasVertexTexcoords", &TriMesh::hasVertexTexcoords)
|
||||
.def("getVertexTexcoords", trimesh_getVertexTexcoords, BP_RETURN_VALUE)
|
||||
.def("hasUVTangents", &TriMesh::hasUVTangents)
|
||||
.def("getUVTangents", trimesh_getUVTangents, BP_RETURN_VALUE)
|
||||
.def("computeUVTangents", &TriMesh::computeUVTangents)
|
||||
.def("computeNormals", &TriMesh::computeNormals)
|
||||
.def("rebuildTopology", &TriMesh::rebuildTopology)
|
||||
|
|
Loading…
Reference in New Issue