diff --git a/include/mitsuba/render/shape.h b/include/mitsuba/render/shape.h index 3c7fe7ea..8ad7e0a3 100644 --- a/include/mitsuba/render/shape.h +++ b/include/mitsuba/render/shape.h @@ -166,6 +166,7 @@ public: /** \brief Abstract base class of all shapes * \ingroup librender + * \ingroup libpython */ class MTS_EXPORT_RENDER Shape : public ConfigurableObject { public: @@ -235,6 +236,10 @@ public: * intersection. The function \ref fillIntersectionRecord() * can later use this information to fill in a detailed * intersection record. + * + * \remark In Python, this function also calls \c fillIntersectionRecord + * and has the signature + * intersection = shape.rayIntersect(ray, mint, maxt) */ virtual bool rayIntersect(const Ray &ray, Float mint, Float maxt, Float &t, void *temp) const; @@ -248,12 +253,17 @@ public: * shapes, this will simply call forward the call to \ref * rayIntersect. When the shape actually contains a nested * kd-tree, some optimizations are possible. + * + * \remark This function is not exposed in Python */ virtual bool rayIntersect(const Ray &ray, Float mint, Float maxt) const; /** * \brief Given that an intersection has been found, create a * detailed intersection record + * + * \remark This function is not directly exposed in Python. + * It is implicitly called as part of \c rayIntersect. */ virtual void fillIntersectionRecord(const Ray &ray, const void *temp, Intersection &its) const; @@ -276,6 +286,9 @@ public: * \param shadingFrame * Specifies whether to compute the derivative of the * geometric normal \a or the shading normal of the surface + * + * \remark In Python, the signature of this function is + * dndu, dndv = shape.getNormalDerivative(its, shadingFrame) */ virtual void getNormalDerivative(const Intersection &its, Vector &dndu, Vector &dndv, bool shadingFrame = true) const; @@ -293,6 +306,9 @@ public: * \param shadingFrame * Specifies whether to compute the curvature based on the * geometric normal \a or the shading normal of the surface + * + * \remark In Python, the signature of this function is + * H, K = shape.getCurvature(its, shadingFrame) */ void getCurvature(const Intersection &its, Float &H, Float &K, bool shadingFrame = true) const; @@ -303,6 +319,8 @@ public: * This function is used by the kd-tree visualization in * the interactive walkthrough. The default implementation * simply returns NULL. + * + * \remark This function is not exposed in Python */ virtual const KDTreeBase *getKDTree() const; diff --git a/src/libpython/core.cpp b/src/libpython/core.cpp index ac625321..247afd60 100644 --- a/src/libpython/core.cpp +++ b/src/libpython/core.cpp @@ -20,6 +20,13 @@ #include #include +#if defined(__LINUX__) +# if !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +#endif + using namespace mitsuba; void initializeFramework() { @@ -28,12 +35,26 @@ void initializeFramework() { Object::staticInitialization(); PluginManager::staticInitialization(); Statistics::staticInitialization(); + FileStream::staticInitialization(); Thread::staticInitialization(); Logger::staticInitialization(); Spectrum::staticInitialization(); + Bitmap::staticInitialization(); Scheduler::staticInitialization(); SHVector::staticInitialization(); SceneHandler::staticInitialization(); + + fs::path sharedLibraryPath; + + /* Try to detect the python plugin path */ + #if defined(__LINUX__) + Dl_info info; + dladdr((void *) &initializeFramework, &info); + if (info.dli_fname) + sharedLibraryPath = fs::path(info.dli_fname); + #elif defined(__OSX__) + + #endif } void shutdownFramework() { @@ -41,9 +62,11 @@ void shutdownFramework() { SceneHandler::staticShutdown(); SHVector::staticShutdown(); Scheduler::staticShutdown(); + Bitmap::staticShutdown(); Spectrum::staticShutdown(); Logger::staticShutdown(); Thread::staticShutdown(); + FileStream::staticShutdown(); Statistics::staticShutdown(); PluginManager::staticShutdown(); Object::staticShutdown(); @@ -316,6 +339,7 @@ bp::object cast(ConfigurableObject *obj) { #define TryCast(ClassName) if (cls->derivesFrom(MTS_CLASS(ClassName))) \ return bp::object(ref(static_cast(obj))) TryCast(BSDF); + TryCast(TriMesh); TryCast(Shape); TryCast(PhaseFunction); TryCast(Integrator); @@ -1207,12 +1231,14 @@ void export_core() { /* Functions from qmc.h */ bp::def("radicalInverse2Single", radicalInverse2Single); bp::def("radicalInverse2Double", radicalInverse2Double); + bp::def("radicalInverse2", radicalInverse2Double); bp::def("sobol2Single", sobol2Single); bp::def("sobol2Double", sobol2Double); - bp::def("sampleTEA", sobol2Double); - bp::def("radicalInverse", sobol2Double); - bp::def("radicalInverseFast", sobol2Double); - bp::def("radicalInverseIncremental", sobol2Double); + bp::def("sobol2", sobol2Double); + bp::def("sampleTEA", sampleTEA); + bp::def("radicalInverse", radicalInverse); + bp::def("radicalInverseFast", radicalInverseFast); + bp::def("radicalInverseIncremental", radicalInverseIncremental); bp::detail::current_scope = oldScope; } diff --git a/src/libpython/render.cpp b/src/libpython/render.cpp index 9ce5c597..8079405b 100644 --- a/src/libpython/render.cpp +++ b/src/libpython/render.cpp @@ -30,6 +30,34 @@ bp::tuple bsdf_sample(const BSDF *bsdf, BSDFSamplingRecord &bRec, const Point2 & return bp::make_tuple(result, pdf); } +bp::object shape_rayIntersect(const Shape *shape, const Ray &ray, Float mint, Float maxt) { + uint8_t temp[MTS_KD_INTERSECTION_TEMP]; + Float t; + + if (!shape->rayIntersect(ray, mint, maxt, t, temp)) + return bp::object(); + + Intersection its; + its.shape = shape; + its.t = t; + shape->fillIntersectionRecord(ray, temp, its); + + return bp::object(its); +} + +bp::tuple shape_getCurvature(const Shape *shape, const Intersection &its, bool shadingFrame) { + Float H, K; + shape->getCurvature(its, H, K, shadingFrame); + return bp::make_tuple(H, K); +} + +bp::tuple shape_getNormalDerivative(const Shape *shape, const Intersection &its, bool shadingFrame) { + Vector dpdu, dpdv; + shape->getNormalDerivative(its, dpdu, dpdv, shadingFrame); + return bp::make_tuple(dpdu, dpdv); +} + + ref loadScene(const fs::path &filename, const StringMap ¶ms) { SceneHandler::ParameterMap pmap; for (StringMap::const_iterator it = params.begin(); it != params.end(); ++it) @@ -133,6 +161,7 @@ void export_render() { .def_readwrite("color", &Intersection::color) .def_readwrite("wi", &Intersection::wi) .def_readwrite("shape", &Intersection::shape) + .def_readwrite("instance", &Intersection::instance) .add_property("hasUVPartials", &intersection_get_hasUVPartials, &intersection_set_hasUVPartials) .add_property("primIndex", &intersection_get_primIndex, &intersection_set_primIndex) .def("toWorld", &Intersection::toWorld, BP_RETURN_VALUE) @@ -146,6 +175,42 @@ void export_render() { .def("LoSub", &Intersection::LoSub) .def("__repr__", &Intersection::toString); + Medium *(Shape::*shape_getInteriorMedium)(void) = &Shape::getInteriorMedium; + Medium *(Shape::*shape_getExteriorMedium)(void) = &Shape::getExteriorMedium; + Sensor *(Shape::*shape_getSensor)(void) = &Shape::getSensor; + Emitter *(Shape::*shape_getEmitter)(void) = &Shape::getEmitter; + Subsurface *(Shape::*shape_getSubsurface)(void) = &Shape::getSubsurface; + BSDF *(Shape::*shape_getBSDF)(void) = &Shape::getBSDF; + + BP_CLASS(Shape, ConfigurableObject, bp::no_init) + .def("getName", &Shape::getName, BP_RETURN_VALUE) + .def("isCompound", &Shape::isCompound) + .def("getElement", &Shape::getElement, BP_RETURN_VALUE) + .def("getSurfaceArea", &Shape::getSurfaceArea) + .def("getAABB", &Shape::getAABB, BP_RETURN_VALUE) + .def("getClippedAABB", &Shape::getClippedAABB, BP_RETURN_VALUE) + .def("createTriMesh", &Shape::createTriMesh, BP_RETURN_VALUE) + .def("rayIntersect", &shape_rayIntersect) + .def("getNormalDerivative", &shape_getNormalDerivative) + .def("getCurvature", &shape_getCurvature) + .def("samplePosition", &Shape::samplePosition) + .def("pdfPosition", &Shape::pdfPosition) + .def("sampleDirect", &Shape::sampleDirect) + .def("pdfDirect", &Shape::pdfDirect) + .def("getInteriorMedium", shape_getInteriorMedium, BP_RETURN_VALUE) + .def("getExteriorMedium", shape_getExteriorMedium, BP_RETURN_VALUE) + .def("isMediumTransition", &Shape::isMediumTransition) + .def("hasSubsurface", &Shape::hasSubsurface) + .def("getSubsurface", shape_getSubsurface, BP_RETURN_VALUE) + .def("isEmitter", &Shape::isEmitter) + .def("getEmitter", shape_getEmitter, BP_RETURN_VALUE) + .def("isSensor", &Shape::isSensor) + .def("getSensor", shape_getSensor, BP_RETURN_VALUE) + .def("hasBSDF", &Shape::hasBSDF) + .def("getBSDF", shape_getBSDF, BP_RETURN_VALUE) + .def("getPrimitiveCount", &Shape::getPrimitiveCount) + .def("getEffectivePrimitiveCount", &Shape::getEffectivePrimitiveCount); + BP_STRUCT(BSDFSamplingRecord, (bp::init())) .def(bp::init()) .def(bp::init()) @@ -217,8 +282,8 @@ void export_render() { bp::class_("Noise") .def("perlinNoise", &Noise::perlinNoise) - .def("fbm", &Noise::fbm) - .def("turbulence", &Noise::turbulence); + .def("turbulence", &Noise::turbulence) + .def("fbm", &Noise::fbm); bp::detail::current_scope = oldScope; }