merged with the time-aware branch
commit
2cc242e5e7
|
@ -31,24 +31,27 @@ struct Ray {
|
|||
Vector d; ///< Ray direction
|
||||
Float maxt; ///< Maximum range for intersection tests
|
||||
Vector dRcp; ///< Componentwise reciprocals of the ray direction
|
||||
Float time; ///< Time value associated with this ray
|
||||
|
||||
/// Construct a new ray
|
||||
inline Ray() : mint(Epsilon), maxt(std::numeric_limits<Float>::infinity()) {
|
||||
inline Ray() : mint(Epsilon),
|
||||
maxt(std::numeric_limits<Float>::infinity()), time(0.0f) {
|
||||
}
|
||||
|
||||
/// Copy constructor (1)
|
||||
inline Ray(const Ray &ray)
|
||||
: o(ray.o), mint(ray.mint), d(ray.d), maxt(ray.maxt), dRcp(ray.dRcp) {
|
||||
: o(ray.o), mint(ray.mint), d(ray.d), maxt(ray.maxt),
|
||||
dRcp(ray.dRcp), time(ray.time) {
|
||||
}
|
||||
|
||||
/// Copy constructor (2)
|
||||
inline Ray(const Ray &ray, Float mint, Float maxt)
|
||||
: o(ray.o), mint(mint), d(ray.d), maxt(maxt), dRcp(ray.dRcp) {
|
||||
: o(ray.o), mint(mint), d(ray.d), maxt(maxt), dRcp(ray.dRcp), time(ray.time) {
|
||||
}
|
||||
|
||||
|
||||
/// Construct a new ray
|
||||
inline Ray(Point o, Vector _d)
|
||||
: o(o), mint(Epsilon), d(_d), maxt(std::numeric_limits<Float>::infinity()) {
|
||||
inline Ray(Point o, Vector _d, Float time)
|
||||
: o(o), mint(Epsilon), d(_d), maxt(std::numeric_limits<Float>::infinity()), time(time) {
|
||||
#ifdef MTS_DEBUG_FP
|
||||
disable_fpexcept();
|
||||
#endif
|
||||
|
@ -61,8 +64,8 @@ struct Ray {
|
|||
}
|
||||
|
||||
/// Construct a new ray
|
||||
inline Ray(Point o, Vector _d, Float mint, Float maxt)
|
||||
: o(o), mint(mint), d(_d), maxt(maxt) {
|
||||
inline Ray(Point o, Vector _d, Float mint, Float maxt, Float time)
|
||||
: o(o), mint(mint), d(_d), maxt(maxt), time(time) {
|
||||
#ifdef MTS_DEBUG_FP
|
||||
disable_fpexcept();
|
||||
#endif
|
||||
|
@ -76,6 +79,9 @@ struct Ray {
|
|||
|
||||
/// Set the origin
|
||||
inline void setOrigin(const Point &oVal) { o = oVal; }
|
||||
|
||||
/// Set the origin
|
||||
inline void setTime(const Float &tval) { time = tval; }
|
||||
|
||||
/// Set the direction and update the reciprocal
|
||||
inline void setDirection(const Vector &dVal) {
|
||||
|
@ -97,7 +103,8 @@ struct Ray {
|
|||
/// Return a string representation of this ray
|
||||
inline std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Ray[orig=" << o.toString() << ", dest=" << d.toString() << "]";
|
||||
oss << "Ray[orig=" << o.toString() << ", dest="
|
||||
<< d.toString() << ", time=" << time << "]";
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
@ -112,8 +119,8 @@ struct RayDifferential : public Ray {
|
|||
: hasDifferentials(false) {
|
||||
}
|
||||
|
||||
inline RayDifferential(const Point &p, const Vector &d)
|
||||
: Ray(p, d), hasDifferentials(false) {
|
||||
inline RayDifferential(const Point &p, const Vector &d, Float time)
|
||||
: Ray(p, d, time), hasDifferentials(false) {
|
||||
}
|
||||
|
||||
inline explicit RayDifferential(const Ray &ray)
|
||||
|
|
|
@ -310,6 +310,7 @@ public:
|
|||
b.dRcp.x = 1.0f / b.d.x;
|
||||
b.dRcp.y = 1.0f / b.d.y;
|
||||
b.dRcp.z = 1.0f / b.d.z;
|
||||
b.time = a.time;
|
||||
#ifdef MTS_DEBUG_FP
|
||||
enable_fpexcept();
|
||||
#endif
|
||||
|
|
|
@ -31,11 +31,11 @@ class MTS_EXPORT_RENDER Camera : public ConfigurableObject {
|
|||
public:
|
||||
/// Create a ray from the given sample
|
||||
virtual void generateRay(const Point2 &sample, const Point2 &lensSample,
|
||||
Ray &ray) const = 0;
|
||||
Float timeSample, Ray &ray) const = 0;
|
||||
|
||||
/// Create ray differentials from the given sample
|
||||
void generateRayDifferential(const Point2 &sample,
|
||||
const Point2 &lensSample, RayDifferential &ray) const;
|
||||
const Point2 &lensSample, Float timeSample, RayDifferential &ray) const;
|
||||
|
||||
/**
|
||||
* Turn a world-space position into fractional pixel coordinates.
|
||||
|
@ -46,6 +46,9 @@ public:
|
|||
|
||||
/// Does generateRay() expect a proper lens sample?
|
||||
virtual bool needsLensSample() const = 0;
|
||||
|
||||
/// Does generateRay() expect a proper time sample?
|
||||
inline bool needsTimeSample() const { return m_shutterOpenTime > 0; }
|
||||
|
||||
/// Return the camera position (approximate in the case of finite sensor area)
|
||||
inline const Point &getPosition() const { return m_position; }
|
||||
|
@ -81,11 +84,20 @@ public:
|
|||
*/
|
||||
inline const Sampler *getSampler() const { return m_sampler.get(); }
|
||||
|
||||
/// Return the time value of the shutter opening event
|
||||
inline Float getShutterOpen() const { return m_shutterOpen; }
|
||||
|
||||
/// Return the length, for which the shutter remains open
|
||||
inline Float getShutterOpenTime() const { return m_shutterOpenTime; }
|
||||
|
||||
/// Return the time value of the shutter closing event
|
||||
inline Float getShutterClose() const { return m_shutterOpen; }
|
||||
|
||||
/// Return the image plane normal
|
||||
inline Normal getImagePlaneNormal() const {
|
||||
return Normal(normalize(m_cameraToWorld(Vector(0, 0, 1))));
|
||||
}
|
||||
|
||||
|
||||
/// Return the view transformation
|
||||
inline const Transform &getViewTransform() const { return m_worldToCamera; }
|
||||
|
||||
|
@ -143,6 +155,7 @@ protected:
|
|||
Transform m_worldToCamera, m_cameraToWorld;
|
||||
Point m_position;
|
||||
Properties m_properties;
|
||||
Float m_shutterOpen, m_shutterClose, m_shutterOpenTime;
|
||||
};
|
||||
|
||||
class MTS_EXPORT_RENDER ProjectiveCamera : public Camera {
|
||||
|
|
|
@ -3163,7 +3163,7 @@ template <typename AABBType, typename Derived>
|
|||
sample2(random->nextFloat(), random->nextFloat());
|
||||
Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius;
|
||||
Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius;
|
||||
Ray ray(p1, normalize(p2-p1));
|
||||
Ray ray(p1, normalize(p2-p1), 0.0f);
|
||||
Float mint, maxt, t;
|
||||
if (this->m_aabb.rayIntersect(ray, mint, maxt)) {
|
||||
if (ray.mint > mint) mint = ray.mint;
|
||||
|
|
|
@ -288,7 +288,7 @@ public:
|
|||
* cosine-weighted sampling and a configurable number of rays.
|
||||
*/
|
||||
virtual Spectrum E(const Scene *scene, const Point &p, const
|
||||
Normal &n, Sampler *sampler) const;
|
||||
Normal &n, Float time, Sampler *sampler) const;
|
||||
|
||||
/**
|
||||
* Perform the main rendering task. The work is automatically
|
||||
|
|
|
@ -353,6 +353,7 @@ protected:
|
|||
shape->fillIntersectionRecord(ray,
|
||||
reinterpret_cast<const uint8_t*>(temp) + 8, its);
|
||||
}
|
||||
its.time = ray.time;
|
||||
}
|
||||
|
||||
/// Plain shadow ray query (used by the 'instance' plugin)
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
* which occurred while tracing particles.
|
||||
*/
|
||||
virtual void handleMediumInteraction(int depth, bool caustic,
|
||||
const MediumSamplingRecord &mRec, const Vector &wi,
|
||||
const MediumSamplingRecord &mRec, Float time, const Vector &wi,
|
||||
const Spectrum &weight);
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
|
|
|
@ -64,7 +64,7 @@ inline bool RadianceQueryRecord::rayIntersect(const RayDifferential &ray) {
|
|||
/* Only search for an intersection if this was explicitly requested */
|
||||
if (type & EIntersection) {
|
||||
scene->rayIntersect(ray, its);
|
||||
attenuation = scene->getAttenuation(Ray(ray.o, ray.d, 0, its.t));
|
||||
attenuation = scene->getAttenuation(Ray(ray.o, ray.d, 0, its.t, ray.time));
|
||||
if (type & EOpacity)
|
||||
alpha = its.isValid() ? 1 : (1 - attenuation.average());
|
||||
if (type & EDistance)
|
||||
|
|
|
@ -131,8 +131,8 @@ public:
|
|||
}
|
||||
|
||||
/// Cast a shadow ray
|
||||
inline bool isOccluded(const Point &p1, const Point &p2) const {
|
||||
Ray ray(p1, p2-p1);
|
||||
inline bool isOccluded(const Point &p1, const Point &p2, Float time) const {
|
||||
Ray ray(p1, p2-p1, time);
|
||||
ray.mint = ShadowEpsilon;
|
||||
ray.maxt = 1-ShadowEpsilon;
|
||||
return m_kdtree->rayIntersect(ray);
|
||||
|
@ -155,6 +155,9 @@ public:
|
|||
* @param lRec
|
||||
* A luminaire sampling record, which will hold information such as the
|
||||
* probability density, associated measure etc.
|
||||
* @param time
|
||||
* Associated time value -- this is needed to check the visibility when
|
||||
* objects are potentially moving over time
|
||||
* @param testVisibility
|
||||
* If this is true, a shadow-ray will be cast to ensure that no surface
|
||||
* blocks the path lRec.sRec.p <-> p.
|
||||
|
@ -162,7 +165,8 @@ public:
|
|||
* true if sampling was successful
|
||||
*/
|
||||
bool sampleLuminaire(const Point &p,
|
||||
LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const;
|
||||
LuminaireSamplingRecord &lRec, Float time,
|
||||
const Point2 &sample, bool testVisibility = true) const;
|
||||
|
||||
/**
|
||||
* Sample a visible point on a luminaire (ideally uniform wrt. the solid angle of p). Takes
|
||||
|
@ -186,9 +190,10 @@ public:
|
|||
* lRec.Le by the integrated extinction coefficient on the path lRec.sRec.p <-> p.
|
||||
*/
|
||||
inline bool sampleLuminaireAttenuated(const Point &p,
|
||||
LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const {
|
||||
if (sampleLuminaire(p, lRec, sample, testVisibility)) {
|
||||
lRec.Le *= getAttenuation(Ray(p, lRec.sRec.p-p, 0, 1));
|
||||
LuminaireSamplingRecord &lRec, Float time,
|
||||
const Point2 &sample, bool testVisibility = true) const {
|
||||
if (sampleLuminaire(p, lRec, time, sample, testVisibility)) {
|
||||
lRec.Le *= getAttenuation(Ray(p, lRec.sRec.p-p, 0, 1, 0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -201,7 +206,7 @@ public:
|
|||
inline bool sampleLuminaireAttenuated(const Intersection &its,
|
||||
LuminaireSamplingRecord &lRec, const Point2 &sample, bool testVisibility = true) const {
|
||||
if (sampleLuminaire(its, lRec, sample, testVisibility)) {
|
||||
lRec.Le *= getAttenuation(Ray(its.p, lRec.sRec.p-its.p, 0, 1));
|
||||
lRec.Le *= getAttenuation(Ray(its.p, lRec.sRec.p-its.p, 0, 1, 0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -132,6 +132,9 @@ public:
|
|||
/// Texture coordinate mapping partials wrt. changes in screen-space
|
||||
Float dudx, dudy, dvdx, dvdy;
|
||||
|
||||
/// Time value associated with the intersection
|
||||
Float time;
|
||||
|
||||
/// Interpolated vertex color
|
||||
Spectrum color;
|
||||
|
||||
|
|
|
@ -104,13 +104,14 @@ public:
|
|||
}
|
||||
|
||||
void generateRay(const Point2 &dirSample, const Point2 &lensSample,
|
||||
Ray &ray) const {
|
||||
Float timeSample, Ray &ray) const {
|
||||
Point rasterCoords(dirSample.x, dirSample.y, 0);
|
||||
Point imageCoords;
|
||||
m_rasterToCamera(rasterCoords, imageCoords);
|
||||
|
||||
/* Construct ray in camera space */
|
||||
Ray localRay(imageCoords, Vector(0, 0, 1));
|
||||
Ray localRay(imageCoords, Vector(0, 0, 1),
|
||||
m_shutterOpen + m_shutterOpenTime * timeSample);
|
||||
localRay.mint = 0;
|
||||
localRay.maxt = m_farClip - m_nearClip;
|
||||
|
||||
|
@ -154,6 +155,8 @@ public:
|
|||
<< " aspect = " << m_aspect << "," << std::endl
|
||||
<< " nearClip = " << m_nearClip << "," << std::endl
|
||||
<< " farClip = " << m_farClip << "," << std::endl
|
||||
<< " shutterOpen = " << m_shutterOpen << "," << std::endl
|
||||
<< " shutterClose = " << m_shutterClose << "," << std::endl
|
||||
<< " areaDensity = " << m_areaDensity << "," << std::endl
|
||||
<< " cameraToWorld = " << indent(m_cameraToWorld.toString()) << "," << std::endl
|
||||
<< " cameraToScreen = " << indent(m_cameraToScreen.toString()) << "," << std::endl
|
||||
|
|
|
@ -109,15 +109,16 @@ public:
|
|||
return m_lensRadius > 0.0f;
|
||||
}
|
||||
|
||||
void generateRay(const Point2 &dirSample, const Point2 &lensSample,
|
||||
Ray &ray) const {
|
||||
void generateRay(const Point2 &dirSample, const Point2 &lensSample,
|
||||
Float timeSample, Ray &ray) const {
|
||||
/* Calculate intersection on the image plane */
|
||||
Point rasterCoords(dirSample.x, dirSample.y, 0);
|
||||
Point imageCoords;
|
||||
m_rasterToCamera(rasterCoords, imageCoords);
|
||||
|
||||
/* Construct ray in camera space */
|
||||
Ray localRay(Point(0, 0, 0), Vector(imageCoords));
|
||||
Ray localRay(Point(0, 0, 0), Vector(imageCoords),
|
||||
m_shutterOpen + m_shutterOpenTime * timeSample);
|
||||
|
||||
if (m_lensRadius > 0.0f) {
|
||||
/* Sample a point on the aperture */
|
||||
|
@ -184,6 +185,8 @@ public:
|
|||
<< " yfov = " << m_yfov << "," << std::endl
|
||||
<< " nearClip = " << m_nearClip << "," << std::endl
|
||||
<< " farClip = " << m_farClip << "," << std::endl
|
||||
<< " shutterOpen = " << m_shutterOpen << "," << std::endl
|
||||
<< " shutterClose = " << m_shutterClose << "," << std::endl
|
||||
<< " lensRadius = " << m_lensRadius << "," << std::endl
|
||||
<< " focalDistance = " << m_focalDistance << "," << std::endl
|
||||
<< " cameraToWorld = " << indent(m_cameraToWorld.toString()) << "," << std::endl
|
||||
|
|
|
@ -1177,7 +1177,7 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
|
|||
ctx.os << "\t\t<transform name=\"toWorld\">" << endl;
|
||||
ctx.os << "\t\t\t<matrix value=\"" << matrixValues.substr(0, matrixValues.length()-1) << "\"/>" << endl;
|
||||
ctx.os << "\t\t</transform>" << endl << endl;
|
||||
ctx.os << "\t\t<sampler type=\"ldsampler\">" << endl;
|
||||
ctx.os << "\t\t<sampler id=\"sampler\" type=\"ldsampler\">" << endl;
|
||||
ctx.os << "\t\t\t<integer name=\"sampleCount\" value=\"" << ctx.cvt->m_samplesPerPixel << "\"/>" << endl;
|
||||
ctx.os << "\t\t</sampler>" << endl << endl;
|
||||
ctx.os << "\t\t<film id=\"film\" type=\"" << ctx.cvt->m_filmType << "\">" << endl;
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void findRemovals(DOMNode *node, std::set<std::string> &removals) {
|
||||
void createNodeMap(DOMNode *node, std::map<std::string, DOMNode *> &nodes) {
|
||||
if (node) {
|
||||
char *nodeName = XMLString::transcode(node->getNodeName());
|
||||
if (strcmp(nodeName, "ref") == 0) {
|
||||
|
@ -68,63 +68,20 @@ void findRemovals(DOMNode *node, std::set<std::string> &removals) {
|
|||
XMLString::release(&nodeName);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) {
|
||||
DOMNamedNodeMap *attributes = node->getAttributes();
|
||||
for (size_t i=0; i<attributes->getLength(); ++i) {
|
||||
DOMAttr *attribute = (DOMAttr*) attributes->item(i);
|
||||
char *name = XMLString::transcode(attribute->getName());
|
||||
XMLCh *idString = XMLString::transcode("id");
|
||||
DOMAttr *attribute = (DOMAttr *) attributes->getNamedItem(idString);
|
||||
XMLString::release(&idString);
|
||||
if (attribute != NULL) {
|
||||
char *value = XMLString::transcode(attribute->getValue());
|
||||
|
||||
if (strcmp(name, "id") == 0)
|
||||
removals.insert(value);
|
||||
|
||||
XMLString::release(&name);
|
||||
nodes[value] = node;
|
||||
XMLString::release(&value);
|
||||
}
|
||||
}
|
||||
for (DOMNode *child = node->getFirstChild(); child != 0; child=child->getNextSibling())
|
||||
findRemovals(child, removals);
|
||||
createNodeMap(child, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
bool cleanupPass(DOMNode *node, const std::set<std::string> &removals) {
|
||||
if (node) {
|
||||
char *nodeName = XMLString::transcode(node->getNodeName());
|
||||
if (strcmp(nodeName, "ref") == 0) {
|
||||
XMLString::release(&nodeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE && node->hasAttributes()) {
|
||||
DOMNamedNodeMap *attributes = node->getAttributes();
|
||||
for (size_t i=0; i<attributes->getLength(); ++i) {
|
||||
DOMAttr *attribute = (DOMAttr*) attributes->item(i);
|
||||
char *name = XMLString::transcode(attribute->getName());
|
||||
char *value = XMLString::transcode(attribute->getValue());
|
||||
|
||||
if (strcmp(name, "id") == 0 && removals.find(value) != removals.end()) {
|
||||
XMLString::release(&name);
|
||||
XMLString::release(&value);
|
||||
return true; /* Remove this node */
|
||||
}
|
||||
|
||||
XMLString::release(&name);
|
||||
XMLString::release(&value);
|
||||
}
|
||||
XMLString::release(&nodeName);
|
||||
} else if (node->getNodeType() == DOMNode::TEXT_NODE) {
|
||||
return true;
|
||||
}
|
||||
DOMNode *child = node->getFirstChild();
|
||||
while (child) {
|
||||
DOMNode *next = child->getNextSibling();
|
||||
bool doRemove = cleanupPass(child, removals);
|
||||
if (doRemove)
|
||||
node->removeChild(child);
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GeometryConverter::convert(const fs::path &inputFile,
|
||||
const fs::path &outputDirectory,
|
||||
const fs::path &sceneName,
|
||||
|
@ -191,10 +148,8 @@ void GeometryConverter::convert(const fs::path &inputFile,
|
|||
if (adj == NULL)
|
||||
SLog(EError, "Could not parse adjustments file!");
|
||||
|
||||
std::set<std::string> removals, emptyList;
|
||||
cleanupPass(adj, emptyList);
|
||||
findRemovals(adj, removals);
|
||||
cleanupPass(doc, removals);
|
||||
std::map<std::string, DOMNode *> nodeMap;
|
||||
createNodeMap(doc, nodeMap);
|
||||
|
||||
DOMElement *docRoot = doc->getDocumentElement();
|
||||
DOMElement *adjRoot = adj->getDocumentElement();
|
||||
|
@ -222,9 +177,39 @@ void GeometryConverter::convert(const fs::path &inputFile,
|
|||
SAssertEx(insertBeforeNode != NULL, "Internal error while applying adjustments: cannot find shape/camera node");
|
||||
}
|
||||
|
||||
for (DOMNode *child = adjRoot->getFirstChild(); child != 0; child=child->getNextSibling())
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode);
|
||||
for (DOMNode *child = adjRoot->getFirstChild(); child != 0; child=child->getNextSibling()) {
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
char *nodeName = XMLString::transcode(child->getNodeName());
|
||||
std::string id;
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE && child->hasAttributes()) {
|
||||
DOMNamedNodeMap *attributes = child->getAttributes();
|
||||
XMLCh *idString = XMLString::transcode("id");
|
||||
DOMAttr *attribute = (DOMAttr *) attributes->getNamedItem(idString);
|
||||
XMLString::release(&idString);
|
||||
if (attribute) {
|
||||
char *value = XMLString::transcode(attribute->getValue());
|
||||
id = value;
|
||||
XMLString::release(&value);
|
||||
}
|
||||
}
|
||||
if (id != "" && nodeMap.find(id) != nodeMap.end()) {
|
||||
DOMNode *node = nodeMap[id], *parent = node->getParentNode();
|
||||
if (strcmp(nodeName, "append") == 0) {
|
||||
DOMNode *node = nodeMap[id];
|
||||
for (DOMNode *child2 = child->getFirstChild(); child2 != 0; child2=child2->getNextSibling())
|
||||
node->insertBefore(doc->importNode(child2, true), NULL);
|
||||
} else if (parent == insertBeforeNode->getParentNode()) {
|
||||
parent->removeChild(node);
|
||||
docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode);
|
||||
} else {
|
||||
parent->replaceChild(doc->importNode(child, true), node);
|
||||
}
|
||||
} else {
|
||||
docRoot->insertBefore(doc->importNode(child, true), insertBeforeNode);
|
||||
}
|
||||
XMLString::release(&nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
DOMLSSerializer *serializer = impl->createLSSerializer();
|
||||
DOMConfiguration *serConf(serializer->getDomConfig());
|
||||
|
|
|
@ -49,6 +49,7 @@ protected:
|
|||
Float m_gamma, m_exposure;
|
||||
std::string m_toneMappingMethod;
|
||||
Float m_reinhardKey, m_reinhardBurn;
|
||||
int m_compressionRate;
|
||||
public:
|
||||
PNGFilm(const Properties &props) : Film(props) {
|
||||
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
||||
|
@ -68,6 +69,8 @@ public:
|
|||
m_reinhardBurn = props.getFloat("reinhardBurn", 0.0f);
|
||||
/* Reinhard "key" parameter */
|
||||
m_reinhardKey = props.getFloat("reinhardKey", 0.18f);
|
||||
/* Compression rate (1=low, 9=high) */
|
||||
m_compressionRate = props.getInteger("compressionRate", 1);
|
||||
|
||||
if (m_toneMappingMethod != "gamma" && m_toneMappingMethod != "reinhard")
|
||||
Log(EError, "Unknown tone mapping method specified (must be 'gamma' or 'reinhard')");
|
||||
|
@ -95,6 +98,7 @@ public:
|
|||
m_reinhardKey = stream->readFloat();
|
||||
m_reinhardBurn = stream->readFloat();
|
||||
m_exposure = stream->readFloat();
|
||||
m_compressionRate = stream->readInt();
|
||||
m_gamma = 1.0f / m_gamma;
|
||||
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
||||
}
|
||||
|
@ -109,6 +113,7 @@ public:
|
|||
stream->writeFloat(m_reinhardKey);
|
||||
stream->writeFloat(m_reinhardBurn);
|
||||
stream->writeFloat(m_exposure);
|
||||
stream->writeInt(m_compressionRate);
|
||||
}
|
||||
|
||||
virtual ~PNGFilm() {
|
||||
|
@ -403,7 +408,7 @@ public:
|
|||
Log(EInfo, "Writing image to \"%s\" ..", filename.leaf().c_str());
|
||||
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
||||
bitmap->setGamma(m_gamma);
|
||||
bitmap->save(Bitmap::EPNG, stream, 1);
|
||||
bitmap->save(Bitmap::EPNG, stream, m_compressionRate);
|
||||
}
|
||||
|
||||
bool destinationExists(const fs::path &baseName) const {
|
||||
|
|
|
@ -168,7 +168,7 @@ public:
|
|||
bsdfVal /= bsdfPdf;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
Ray bsdfRay(its.p, its.toWorld(bRec.wo));
|
||||
Ray bsdfRay(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
bool hitLuminaire = false;
|
||||
if (scene->rayIntersect(bsdfRay, bsdfIts)) {
|
||||
bsdfRay.mint = 0; bsdfRay.maxt = bsdfIts.t;
|
||||
|
|
|
@ -103,8 +103,9 @@ public:
|
|||
|
||||
Vector2i filmSize = camera->getFilm()->getSize();
|
||||
bool needsLensSample = camera->needsLensSample();
|
||||
bool needsTimeSample = camera->needsTimeSample();
|
||||
const int nSamples = 10000;
|
||||
Float luminance = 0;
|
||||
Float luminance = 0, timeSample = 0;
|
||||
RadianceQueryRecord rRec(scene, sampler);
|
||||
for (int i=0; i<nSamples; ++i) {
|
||||
Point2 sample, lensSample;
|
||||
|
@ -113,10 +114,12 @@ public:
|
|||
rRec.newQuery(RadianceQueryRecord::ERadiance);
|
||||
if (needsLensSample)
|
||||
lensSample = rRec.nextSample2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = rRec.nextSample1D();
|
||||
sample = rRec.nextSample2D();
|
||||
sample.x *= filmSize.x;
|
||||
sample.y *= filmSize.y;
|
||||
camera->generateRayDifferential(sample, lensSample, eyeRay);
|
||||
camera->generateRayDifferential(sample, lensSample, timeSample, eyeRay);
|
||||
|
||||
luminance += m_subIntegrator->Li(eyeRay, rRec).getLuminance();
|
||||
}
|
||||
|
@ -130,13 +133,14 @@ public:
|
|||
void renderBlock(const Scene *scene, const Camera *camera, Sampler *sampler,
|
||||
ImageBlock *block, const bool &stop) const {
|
||||
bool needsLensSample = camera->needsLensSample();
|
||||
bool needsTimeSample = camera->needsTimeSample();
|
||||
const TabulatedFilter *filter = camera->getFilm()->getTabulatedFilter();
|
||||
|
||||
Float mean, meanSqr;
|
||||
Point2 sample, lensSample;
|
||||
RayDifferential eyeRay;
|
||||
int x, y;
|
||||
Float sampleLuminance;
|
||||
Float sampleLuminance, timeSample = 0;
|
||||
RadianceQueryRecord rRec(scene, sampler);
|
||||
int sampleIndex;
|
||||
|
||||
|
@ -157,10 +161,12 @@ public:
|
|||
rRec.newQuery(RadianceQueryRecord::ECameraRay);
|
||||
if (needsLensSample)
|
||||
lensSample = rRec.nextSample2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = rRec.nextSample1D();
|
||||
sample = rRec.nextSample2D();
|
||||
sample.x += x; sample.y += y;
|
||||
camera->generateRayDifferential(sample,
|
||||
lensSample, eyeRay);
|
||||
lensSample, timeSample, eyeRay);
|
||||
|
||||
Spectrum sampleValue = m_subIntegrator->Li(eyeRay, rRec);
|
||||
|
||||
|
@ -217,8 +223,8 @@ public:
|
|||
return m_subIntegrator->Li(ray, rRec);
|
||||
}
|
||||
|
||||
Spectrum E(const Scene *scene, const Point &p, const Normal &n, Sampler *sampler) const {
|
||||
return m_subIntegrator->E(scene, p, n, sampler);
|
||||
Spectrum E(const Scene *scene, const Point &p, const Normal &n, Float time, Sampler *sampler) const {
|
||||
return m_subIntegrator->E(scene, p, n, time, sampler);
|
||||
}
|
||||
|
||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||
|
|
|
@ -277,7 +277,7 @@ public:
|
|||
RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance);
|
||||
rRec2.extra = 1;
|
||||
rRec2.sampler = sampler;
|
||||
entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d), rRec2);
|
||||
entry.L = m_subIntegrator->Li(RayDifferential(rRec.its.p, entry.d, ray.time), rRec2);
|
||||
entry.dist = rRec2.dist;
|
||||
sampler->advance();
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ public:
|
|||
E = hs->getIrradiance();
|
||||
}
|
||||
|
||||
Spectrum E(const Scene *scene, const Point &p, const Normal &n, Sampler *sampler) const {
|
||||
Spectrum E(const Scene *scene, const Point &p, const Normal &n, Float time, Sampler *sampler) const {
|
||||
Spectrum EDir(0.0f), EIndir(0.0f);
|
||||
RadianceQueryRecord rRec(scene, sampler);
|
||||
LuminaireSamplingRecord lRec;
|
||||
|
@ -297,7 +297,7 @@ public:
|
|||
for (unsigned int i=0; i<m_irrSamples; i++) {
|
||||
rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission);
|
||||
|
||||
if (scene->sampleLuminaireAttenuated(p, lRec, rRec.nextSample2D())) {
|
||||
if (scene->sampleLuminaireAttenuated(p, lRec, time, rRec.nextSample2D())) {
|
||||
Float dp = dot(lRec.d, n);
|
||||
if (dp < 0)
|
||||
EDir -= lRec.Le * dp;
|
||||
|
|
|
@ -104,7 +104,7 @@ public:
|
|||
if (stop)
|
||||
break;
|
||||
Point2 sample(x + .5f, y + .5f);
|
||||
m_camera->generateRayDifferential(sample, lensSample, eyeRay);
|
||||
m_camera->generateRayDifferential(sample, lensSample, 0.0f, eyeRay);
|
||||
if (m_scene->rayIntersect(eyeRay, its)) {
|
||||
const BSDF *bsdf = its.shape->getBSDF();
|
||||
if (!bsdf->getType() == BSDF::EDiffuseReflection)
|
||||
|
@ -125,7 +125,7 @@ public:
|
|||
rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission | RadianceQueryRecord::EDistance);
|
||||
rRec.depth = 2;
|
||||
rRec.extra = 1; // mark as irradiance cache query
|
||||
entry.L = integrator->Li(RayDifferential(its.p, entry.d), rRec);
|
||||
entry.L = integrator->Li(RayDifferential(its.p, entry.d, 0.0f), rRec);
|
||||
entry.dist = rRec.dist;
|
||||
m_sampler->advance();
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ public:
|
|||
prevIts = its;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo));
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
bool hitLuminaire = false;
|
||||
if (scene->rayIntersect(ray, its)) {
|
||||
/* Intersected something - check if it was a luminaire */
|
||||
|
|
|
@ -77,7 +77,7 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool,
|
|||
|
||||
if (m_camera->positionToSample(its.p, screenSample)) {
|
||||
Point cameraPosition = m_camera->getPosition(screenSample);
|
||||
if (m_scene->isOccluded(cameraPosition, its.p))
|
||||
if (m_scene->isOccluded(cameraPosition, its.p, its.time))
|
||||
return;
|
||||
|
||||
const BSDF *bsdf = its.shape->getBSDF();
|
||||
|
@ -94,7 +94,7 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool,
|
|||
importance = 1/m_camera->areaDensity(screenSample);
|
||||
|
||||
/* Compute Le * importance and store it in an accumulation buffer */
|
||||
Ray ray(its.p, d, 0, dist);
|
||||
Ray ray(its.p, d, 0, dist, its.time);
|
||||
Spectrum sampleVal = weight * bsdf->fCos(bRec)
|
||||
* m_scene->getAttenuation(ray) * importance;
|
||||
|
||||
|
@ -103,13 +103,13 @@ void CaptureParticleWorker::handleSurfaceInteraction(int, bool,
|
|||
}
|
||||
|
||||
void CaptureParticleWorker::handleMediumInteraction(int, bool,
|
||||
const MediumSamplingRecord &mRec, const Vector &wi,
|
||||
const MediumSamplingRecord &mRec, Float time, const Vector &wi,
|
||||
const Spectrum &weight) {
|
||||
Point2 screenSample;
|
||||
|
||||
if (m_camera->positionToSample(mRec.p, screenSample)) {
|
||||
Point cameraPosition = m_camera->getPosition(screenSample);
|
||||
if (m_scene->isOccluded(cameraPosition, mRec.p))
|
||||
if (m_scene->isOccluded(cameraPosition, mRec.p, time))
|
||||
return;
|
||||
|
||||
Vector wo = cameraPosition - mRec.p;
|
||||
|
@ -122,7 +122,7 @@ void CaptureParticleWorker::handleMediumInteraction(int, bool,
|
|||
importance = 1/m_camera->areaDensity(screenSample);
|
||||
|
||||
/* Compute Le * importance and store in accumulation buffer */
|
||||
Ray ray(mRec.p, wo, 0, dist);
|
||||
Ray ray(mRec.p, wo, 0, dist, time);
|
||||
|
||||
Spectrum sampleVal = weight * mRec.medium->getPhaseFunction()->f(mRec, wi, wo)
|
||||
* m_scene->getAttenuation(ray) * importance;
|
||||
|
|
|
@ -103,7 +103,7 @@ public:
|
|||
* pixel of the accumulation buffer.
|
||||
*/
|
||||
void handleMediumInteraction(int depth, bool caustic,
|
||||
const MediumSamplingRecord &mRec, const Vector &wi,
|
||||
const MediumSamplingRecord &mRec, Float time, const Vector &wi,
|
||||
const Spectrum &weight);
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
|
||||
/* Estimate the single scattering component if this is requested */
|
||||
if (rRec.type & RadianceQueryRecord::EInscatteredDirectRadiance &&
|
||||
scene->sampleLuminaireAttenuated(mRec.p, lRec, rRec.nextSample2D())) {
|
||||
scene->sampleLuminaireAttenuated(mRec.p, lRec, ray.time, rRec.nextSample2D())) {
|
||||
/* Evaluate the phase function */
|
||||
Spectrum phaseVal = phase->f(mRec, -ray.d, -lRec.d);
|
||||
|
||||
|
@ -111,7 +111,7 @@ public:
|
|||
prevIts = its;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
ray = Ray(mRec.p, wo);
|
||||
ray = Ray(mRec.p, wo, ray.time);
|
||||
bool hitLuminaire = false;
|
||||
if (scene->rayIntersect(ray, its)) {
|
||||
/* Intersected something - check if it was a luminaire */
|
||||
|
@ -230,7 +230,7 @@ public:
|
|||
prevIts = its;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo));
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
bool hitLuminaire = false;
|
||||
if (scene->rayIntersect(ray, its)) {
|
||||
/* Intersected something - check if it was a luminaire */
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
|
||||
/* Estimate the single scattering component if this is requested */
|
||||
if (rRec.type & RadianceQueryRecord::EInscatteredDirectRadiance &&
|
||||
scene->sampleLuminaireAttenuated(mRec.p, lRec, rRec.nextSample2D())) {
|
||||
scene->sampleLuminaireAttenuated(mRec.p, lRec, ray.time, rRec.nextSample2D())) {
|
||||
Li += pathThroughput * lRec.Le * phase->f(mRec, -ray.d, -lRec.d);
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
prevIts = its;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
ray = Ray(mRec.p, wo);
|
||||
ray = Ray(mRec.p, wo, ray.time);
|
||||
computeIntersection = true;
|
||||
|
||||
/* ==================================================================== */
|
||||
|
@ -179,7 +179,7 @@ public:
|
|||
prevIts = its;
|
||||
|
||||
/* Trace a ray in this direction */
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo));
|
||||
ray = Ray(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
computeIntersection = true;
|
||||
|
||||
/* ==================================================================== */
|
||||
|
|
|
@ -353,7 +353,7 @@ public:
|
|||
continue;
|
||||
|
||||
rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadiance);
|
||||
recursiveRay = Ray(its.p, its.toWorld(bRec.wo));
|
||||
recursiveRay = Ray(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
Li += m_parentIntegrator->Li(recursiveRay, rRec2) * bsdfVal;
|
||||
}
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ public:
|
|||
Spectrum bsdfVal = bsdf->sampleCos(bRec);
|
||||
|
||||
rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadianceNoEmission);
|
||||
recursiveRay = Ray(its.p, its.toWorld(bRec.wo));
|
||||
recursiveRay = Ray(its.p, its.toWorld(bRec.wo), ray.time);
|
||||
Li += m_parentIntegrator->Li(recursiveRay, rRec2) * bsdfVal * weight;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -135,9 +135,11 @@ public:
|
|||
|
||||
m_totalEmitted = 0;
|
||||
bool needsLensSample = camera->needsLensSample();
|
||||
bool needsTimeSample = camera->needsTimeSample();
|
||||
Log(EInfo, "Creating approximately %i gather points", cropSize.x*cropSize.y*sampleCount);
|
||||
Point2 lensSample, sample;
|
||||
RayDifferential eyeRay;
|
||||
Float timeSample = 0;
|
||||
m_filter = camera->getFilm()->getTabulatedFilter();
|
||||
Vector2 filterSize = m_filter->getFilterSize();
|
||||
int borderSize = (int) std::ceil(std::max(filterSize.x, filterSize.y));
|
||||
|
@ -179,10 +181,12 @@ public:
|
|||
for (uint64_t j = 0; j<sampleCount; j++) {
|
||||
if (needsLensSample)
|
||||
lensSample = cameraSampler->next2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = cameraSampler->next1D();
|
||||
sample = cameraSampler->next2D();
|
||||
sample.x += x; sample.y += y;
|
||||
camera->generateRayDifferential(sample,
|
||||
lensSample, eyeRay);
|
||||
lensSample, timeSample, eyeRay);
|
||||
size_t offset = gatherPoints.size();
|
||||
int count = createGatherPoints(scene, eyeRay, sample, Spectrum(1.0f),
|
||||
gatherPoints, 1);
|
||||
|
@ -240,7 +244,7 @@ public:
|
|||
continue;
|
||||
bsdfVal = bsdf->fDelta(bRec);
|
||||
|
||||
RayDifferential recursiveRay(p.its.p, p.its.toWorld(bRec.wo));
|
||||
RayDifferential recursiveRay(p.its.p, p.its.toWorld(bRec.wo), ray.time);
|
||||
count += createGatherPoints(scene, recursiveRay, sample,
|
||||
weight * bsdfVal, gatherPoints, depth+1);
|
||||
}
|
||||
|
|
|
@ -169,6 +169,7 @@ public:
|
|||
void distributedRTPass(Scene *scene, std::vector<SerializableObject *> &samplers) {
|
||||
ref<Camera> camera = scene->getCamera();
|
||||
bool needsLensSample = camera->needsLensSample();
|
||||
bool needsTimeSample = camera->needsTimeSample();
|
||||
ref<Film> film = camera->getFilm();
|
||||
Vector2i cropSize = film->getCropSize();
|
||||
Point2i cropOffset = film->getCropOffset();
|
||||
|
@ -191,16 +192,19 @@ public:
|
|||
for (int xofsInt = 0; xofsInt < m_blockSize; ++xofsInt) {
|
||||
if (xofsInt + xofs - cropOffset.x >= cropSize.x)
|
||||
continue;
|
||||
Point2 lensSample, sample;
|
||||
Point2 lensSample, sample;
|
||||
Float timeSample = 0.0f;
|
||||
GatherPoint &gatherPoint = gatherPoints[index++];
|
||||
sampler->generate();
|
||||
if (needsLensSample)
|
||||
lensSample = sampler->next2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = sampler->next1D();
|
||||
gatherPoint.pos = Point2i(xofs + xofsInt, yofs + yofsInt);
|
||||
sample = sampler->next2D();
|
||||
sample += Vector2((Float) gatherPoint.pos.x, (Float) gatherPoint.pos.y);
|
||||
RayDifferential ray;
|
||||
camera->generateRayDifferential(sample, lensSample, ray);
|
||||
camera->generateRayDifferential(sample, lensSample, timeSample, ray);
|
||||
Spectrum weight(1.0f);
|
||||
int depth = 1;
|
||||
|
||||
|
@ -232,7 +236,7 @@ public:
|
|||
gatherPoint.depth = -1;
|
||||
break;
|
||||
}
|
||||
ray = RayDifferential(gatherPoint.its.p, gatherPoint.its.toWorld(bRec.wo));
|
||||
ray = RayDifferential(gatherPoint.its.p, gatherPoint.its.toWorld(bRec.wo), ray.time);
|
||||
++depth;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -844,7 +844,7 @@ Float SparseWaveletOctree::lineIntegral(Point start, Point end) const {
|
|||
start /= (Float) m_size;
|
||||
end /= (Float) m_size;
|
||||
|
||||
Ray ray(start, normalize(end-start));
|
||||
Ray ray(start, normalize(end-start), 0.0f);
|
||||
|
||||
uint8_t a = 0;
|
||||
if (ray.d.x < 0) {
|
||||
|
|
|
@ -24,8 +24,14 @@ MTS_NAMESPACE_BEGIN
|
|||
Camera::Camera(const Properties &props)
|
||||
: ConfigurableObject(props), m_properties(props) {
|
||||
m_cameraToWorld = props.getTransform("toWorld", Transform());
|
||||
m_shutterOpen = props.getFloat("shutterOpen", 0.0f);
|
||||
m_shutterClose = props.getFloat("shutterClose", 5.0f);
|
||||
if (m_shutterOpen > m_shutterClose)
|
||||
Log(EError, "Shutter opening time must be less than "
|
||||
"or equal to the shutter closing time!");
|
||||
m_worldToCamera = m_cameraToWorld.inverse();
|
||||
m_position = m_cameraToWorld(Point(0,0,0));
|
||||
m_shutterOpenTime = m_shutterClose - m_shutterOpen;
|
||||
}
|
||||
|
||||
Camera::Camera(Stream *stream, InstanceManager *manager)
|
||||
|
@ -34,7 +40,10 @@ Camera::Camera(Stream *stream, InstanceManager *manager)
|
|||
m_sampler = static_cast<Sampler *>(manager->getInstance(stream));
|
||||
m_worldToCamera = Transform(stream);
|
||||
m_cameraToWorld = Transform(stream);
|
||||
m_shutterOpen = stream->readFloat();
|
||||
m_shutterClose = stream->readFloat();
|
||||
m_position = m_cameraToWorld(Point(0,0,0));
|
||||
m_shutterOpenTime = m_shutterClose - m_shutterOpen;
|
||||
}
|
||||
|
||||
Camera::~Camera() {
|
||||
|
@ -60,16 +69,18 @@ void Camera::serialize(Stream *stream, InstanceManager *manager) const {
|
|||
manager->serialize(stream, m_sampler.get());
|
||||
m_worldToCamera.serialize(stream);
|
||||
m_cameraToWorld.serialize(stream);
|
||||
stream->writeFloat(m_shutterOpen);
|
||||
stream->writeFloat(m_shutterClose);
|
||||
}
|
||||
|
||||
void Camera::generateRayDifferential(const Point2 &sample,
|
||||
const Point2 &lensSample, RayDifferential &ray) const {
|
||||
const Point2 &lensSample, Float timeSample, RayDifferential &ray) const {
|
||||
|
||||
generateRay(sample, lensSample, ray);
|
||||
generateRay(sample, lensSample, timeSample, ray);
|
||||
Point2 temp = sample; temp.x += 1;
|
||||
generateRay(temp, lensSample, ray.rx);
|
||||
generateRay(temp, lensSample, timeSample, ray.rx);
|
||||
temp = sample; temp.y += 1;
|
||||
generateRay(temp, lensSample, ray.ry);
|
||||
generateRay(temp, lensSample, timeSample, ray.ry);
|
||||
ray.hasDifferentials = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ void SampleIntegrator::serialize(Stream *stream, InstanceManager *manager) const
|
|||
stream->writeBool(m_irrIndirect);
|
||||
}
|
||||
|
||||
Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n,
|
||||
Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n, Float time,
|
||||
Sampler *sampler) const {
|
||||
Spectrum E(0.0f);
|
||||
LuminaireSamplingRecord lRec;
|
||||
|
@ -80,7 +80,7 @@ Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n
|
|||
rRec.newQuery(RadianceQueryRecord::ERadianceNoEmission);
|
||||
|
||||
/* Direct */
|
||||
if (scene->sampleLuminaireAttenuated(p, lRec, rRec.nextSample2D())) {
|
||||
if (scene->sampleLuminaireAttenuated(p, lRec, time, rRec.nextSample2D())) {
|
||||
Float dp = dot(lRec.d, n);
|
||||
if (dp < 0)
|
||||
E -= lRec.Le * dp;
|
||||
|
@ -90,7 +90,7 @@ Spectrum SampleIntegrator::E(const Scene *scene, const Point &p, const Normal &n
|
|||
if (m_irrIndirect) {
|
||||
Vector d = frame.toWorld(squareToHemispherePSA(rRec.nextSample2D()));
|
||||
++rRec.depth;
|
||||
E += Li(RayDifferential(p, d), rRec) * M_PI;
|
||||
E += Li(RayDifferential(p, d, time), rRec) * M_PI;
|
||||
}
|
||||
sampler->advance();
|
||||
}
|
||||
|
@ -150,6 +150,7 @@ void SampleIntegrator::renderBlock(const Scene *scene,
|
|||
const Camera *camera, Sampler *sampler, ImageBlock *block, const bool &stop) const {
|
||||
Point2 sample, lensSample;
|
||||
RayDifferential eyeRay;
|
||||
Float timeSample = 0;
|
||||
Spectrum spec;
|
||||
int x, y;
|
||||
uint64_t j;
|
||||
|
@ -162,6 +163,7 @@ void SampleIntegrator::renderBlock(const Scene *scene,
|
|||
block->clear();
|
||||
RadianceQueryRecord rRec(scene, sampler);
|
||||
bool needsLensSample = camera->needsLensSample();
|
||||
bool needsTimeSample = camera->needsTimeSample();
|
||||
const TabulatedFilter *filter = camera->getFilm()->getTabulatedFilter();
|
||||
Float scaleFactor = 1.0f/std::sqrt((Float) sampler->getSampleCount());
|
||||
|
||||
|
@ -175,10 +177,12 @@ void SampleIntegrator::renderBlock(const Scene *scene,
|
|||
rRec.newQuery(RadianceQueryRecord::ECameraRay);
|
||||
if (needsLensSample)
|
||||
lensSample = rRec.nextSample2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = rRec.nextSample1D();
|
||||
sample = rRec.nextSample2D();
|
||||
sample.x += x; sample.y += y;
|
||||
camera->generateRayDifferential(sample,
|
||||
lensSample, eyeRay);
|
||||
lensSample, timeSample, eyeRay);
|
||||
eyeRay.scaleDifferential(scaleFactor);
|
||||
++cameraRays;
|
||||
spec = Li(eyeRay, rRec);
|
||||
|
@ -199,10 +203,12 @@ void SampleIntegrator::renderBlock(const Scene *scene,
|
|||
rRec.newQuery(RadianceQueryRecord::ECameraRay);
|
||||
if (needsLensSample)
|
||||
lensSample = rRec.nextSample2D();
|
||||
if (needsTimeSample)
|
||||
timeSample = rRec.nextSample1D();
|
||||
sample = rRec.nextSample2D();
|
||||
sample.x += x; sample.y += y;
|
||||
camera->generateRayDifferential(sample,
|
||||
lensSample, eyeRay);
|
||||
lensSample, timeSample, eyeRay);
|
||||
eyeRay.scaleDifferential(scaleFactor);
|
||||
++cameraRays;
|
||||
spec = Li(eyeRay, rRec);
|
||||
|
|
|
@ -86,6 +86,7 @@ std::string Intersection::toString() const {
|
|||
<< " uv = " << uv.toString() << "," << std::endl
|
||||
<< " dpdu = " << dpdu.toString() << "," << std::endl
|
||||
<< " dpdv = " << dpdv.toString() << "," << std::endl
|
||||
<< " time = " << time << "," << std::endl
|
||||
<< " shape = " << indent(((Object *)shape)->toString()) << std::endl
|
||||
<< "]";
|
||||
return oss.str();
|
||||
|
|
|
@ -262,7 +262,7 @@ inline int new_node(Float t1, int a, Float t2, int b, Float t3, int c) {
|
|||
Float SparseMipmap3D::lineIntegral(const Ray &r) const {
|
||||
Float length = r.d.length();
|
||||
|
||||
Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length);
|
||||
Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length, 0.0f);
|
||||
|
||||
uint8_t a = 0;
|
||||
if (ray.d.x < 0) {
|
||||
|
@ -304,7 +304,7 @@ bool SparseMipmap3D::invertLineIntegral(const Ray &r, Float desiredDensity,
|
|||
Float &accumDensity, Float &samplePos, Float &sampleDensity) const {
|
||||
Float length = r.d.length();
|
||||
|
||||
Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length);
|
||||
Ray ray(r(r.mint), r.d/length, 0, (r.maxt-r.mint)*length, 0.0f);
|
||||
|
||||
uint8_t a = 0;
|
||||
if (ray.d.x < 0) {
|
||||
|
|
|
@ -98,6 +98,9 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|||
Spectrum weight, bsdfVal;
|
||||
int depth;
|
||||
bool caustic;
|
||||
ref<Camera> camera = m_scene->getCamera();
|
||||
Float shutterOpen = camera->getShutterOpen(),
|
||||
shutterOpenTime = camera->getShutterOpenTime();
|
||||
|
||||
m_sampler->generate();
|
||||
for (size_t index = range->getRangeStart(); index <= range->getRangeEnd() && !stop; ++index) {
|
||||
|
@ -108,7 +111,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|||
/* Sample an emitted particle */
|
||||
m_scene->sampleEmission(eRec, areaSample, dirSample);
|
||||
|
||||
ray = Ray(eRec.sRec.p, eRec.d);
|
||||
ray = Ray(eRec.sRec.p, eRec.d, shutterOpen + shutterOpenTime * m_sampler->next1D());
|
||||
weight = eRec.P;
|
||||
depth = 1;
|
||||
caustic = true;
|
||||
|
@ -126,7 +129,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|||
*/
|
||||
|
||||
weight *= mRec.sigmaS * mRec.attenuation / mRec.pdf;
|
||||
handleMediumInteraction(depth, caustic, mRec, -ray.d, weight);
|
||||
handleMediumInteraction(depth, caustic, mRec, ray.time, -ray.d, weight);
|
||||
|
||||
if (!m_multipleScattering)
|
||||
break;
|
||||
|
@ -144,7 +147,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|||
weight /= mRec.albedo;
|
||||
}
|
||||
|
||||
ray = Ray(mRec.p, wo);
|
||||
ray = Ray(mRec.p, wo, ray.time);
|
||||
} else if (its.t == std::numeric_limits<Float>::infinity()) {
|
||||
/* There is no surface in this direction */
|
||||
break;
|
||||
|
@ -179,7 +182,7 @@ void ParticleTracer::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|||
|
||||
weight *= bsdfVal;
|
||||
Vector wi = -ray.d, wo = its.toWorld(bRec.wo);
|
||||
ray = Ray(its.p, wo);
|
||||
ray = Ray(its.p, wo, ray.time);
|
||||
|
||||
/* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */
|
||||
Float wiDotGeoN = dot(its.geoFrame.n, wi),
|
||||
|
@ -206,7 +209,7 @@ void ParticleTracer::handleSurfaceInteraction(int depth, bool caustic,
|
|||
}
|
||||
|
||||
void ParticleTracer::handleMediumInteraction(int depth, bool caustic,
|
||||
const MediumSamplingRecord &mRec, const Vector &wi,
|
||||
const MediumSamplingRecord &mRec, Float time, const Vector &wi,
|
||||
const Spectrum &weight) {
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work
|
|||
/* Generate a camera ray without normalization */
|
||||
primary = Ray(m_cameraO, m_cameraTL
|
||||
+ m_cameraDx * (Float) x
|
||||
+ m_cameraDy * (Float) y);
|
||||
+ m_cameraDy * (Float) y, 0.0f);
|
||||
|
||||
++numRays;
|
||||
if (!m_kdtree->rayIntersect(primary, its)) {
|
||||
|
@ -88,7 +88,7 @@ void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *work
|
|||
value = Spectrum(0.0f);
|
||||
|
||||
toVPL = m_vpl.its.p - its.p;
|
||||
secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon);
|
||||
secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon, 0.0f);
|
||||
++numRays;
|
||||
if (m_kdtree->rayIntersect(secondary)) {
|
||||
block->setPixel(pos++, value);
|
||||
|
@ -281,7 +281,8 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe
|
|||
secItv4.maxt.f[idx] = 0;
|
||||
emitted[idx] = m_scene->LeBackground(Ray(
|
||||
Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]),
|
||||
Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx])
|
||||
Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]),
|
||||
0.0f
|
||||
));
|
||||
memset(&direct[idx], 0, sizeof(Spectrum));
|
||||
continue;
|
||||
|
@ -346,7 +347,8 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe
|
|||
} else {
|
||||
Ray ray(
|
||||
Point(primRay4.o[0].f[idx], primRay4.o[1].f[idx], primRay4.o[2].f[idx]),
|
||||
Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx])
|
||||
Vector(primRay4.d[0].f[idx], primRay4.d[1].f[idx], primRay4.d[2].f[idx]),
|
||||
0.0f
|
||||
);
|
||||
its.t = its4.t.f[idx];
|
||||
shape->fillIntersectionRecord(ray, temp + idx * MTS_KD_INTERSECTION_TEMP + 8, its);
|
||||
|
|
|
@ -383,7 +383,7 @@ Float Scene::pdfLuminaire(const Intersection &its,
|
|||
}
|
||||
|
||||
bool Scene::sampleLuminaire(const Point &p,
|
||||
LuminaireSamplingRecord &lRec, const Point2 &s,
|
||||
LuminaireSamplingRecord &lRec, Float time, const Point2 &s,
|
||||
bool testVisibility) const {
|
||||
Point2 sample(s);
|
||||
Float lumPdf;
|
||||
|
@ -392,7 +392,7 @@ bool Scene::sampleLuminaire(const Point &p,
|
|||
luminaire->sample(p, lRec, sample);
|
||||
|
||||
if (lRec.pdf != 0) {
|
||||
if (testVisibility && isOccluded(p, lRec.sRec.p))
|
||||
if (testVisibility && isOccluded(p, lRec.sRec.p, time))
|
||||
return false;
|
||||
lRec.pdf *= lumPdf;
|
||||
lRec.Le /= lRec.pdf;
|
||||
|
@ -413,7 +413,7 @@ bool Scene::sampleLuminaire(const Intersection &its,
|
|||
luminaire->sample(its, lRec, sample);
|
||||
|
||||
if (lRec.pdf != 0) {
|
||||
if (testVisibility && isOccluded(its.p, lRec.sRec.p))
|
||||
if (testVisibility && isOccluded(its.p, lRec.sRec.p, its.time))
|
||||
return false;
|
||||
lRec.pdf *= lumPdf;
|
||||
lRec.Le /= lRec.pdf;
|
||||
|
|
|
@ -93,8 +93,6 @@ void AnimatedTransform::eval(Float t, Transform &trafo) const {
|
|||
"animation track type: %i!", track->getType());
|
||||
}
|
||||
}
|
||||
//cout << "T:" << translation.toString() << " R:" << rotation.toString() << " S:" << scale.toString() << endl;
|
||||
|
||||
trafo = Transform::translate(translation) *
|
||||
rotation.toTransform() *
|
||||
Transform::scale(scale);
|
||||
|
|
|
@ -55,7 +55,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept
|
|||
weight *= scene->sampleEmissionDirection(eRec, dirSample);
|
||||
Float cosTheta = (eRec.luminaire->getType() & Luminaire::EOnSurface) ? absDot(eRec.sRec.n, eRec.d) : 1;
|
||||
weight *= cosTheta / eRec.pdfDir;
|
||||
ray = Ray(eRec.sRec.p, eRec.d);
|
||||
ray = Ray(eRec.sRec.p, eRec.d, 0.0f);
|
||||
|
||||
depth = 2;
|
||||
while (!weight.isBlack() && depth < maxDepth) {
|
||||
|
@ -85,7 +85,7 @@ size_t generateVPLs(const Scene *scene, size_t offset, size_t count, int maxDept
|
|||
weight *= bsdfVal;
|
||||
|
||||
Vector wi = -ray.d, wo = its.toWorld(bRec.wo);
|
||||
ray = Ray(its.p, wo);
|
||||
ray = Ray(its.p, wo, 0.0f);
|
||||
|
||||
/* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */
|
||||
Float wiDotGeoN = dot(its.geoFrame.n, wi),
|
||||
|
|
|
@ -377,7 +377,7 @@ public:
|
|||
}
|
||||
|
||||
bool isInside(const Ray &r) const {
|
||||
Ray ray(r(r.mint + Epsilon), r.d);
|
||||
Ray ray(r(r.mint + Epsilon), r.d, 0.0f);
|
||||
Intersection its;
|
||||
if (!m_kdTree->rayIntersect(ray, its))
|
||||
return false;
|
||||
|
@ -386,7 +386,7 @@ public:
|
|||
|
||||
Spectrum tau(const Ray &r) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength);
|
||||
Ray ray(r(r.mint), r.d / dLength, 0.0f);
|
||||
Float coveredLength = 0, remaining = (r.maxt - r.mint) * dLength;
|
||||
bool inside = isInside(r);
|
||||
Intersection its;
|
||||
|
@ -416,7 +416,7 @@ public:
|
|||
bool sampleDistance(const Ray &theRay, Float distSurf,
|
||||
MediumSamplingRecord &mRec, Sampler *sampler) const {
|
||||
Intersection its;
|
||||
Ray ray(theRay.o, theRay.d);
|
||||
Ray ray(theRay.o, theRay.d, 0.0f);
|
||||
int iterations = 0;
|
||||
|
||||
/* Check if the start of the ray is already inside the medium */
|
||||
|
|
|
@ -364,7 +364,7 @@ public:
|
|||
|
||||
Spectrum tau(const Ray &r) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength);
|
||||
Ray ray(r(r.mint), r.d / dLength, 0.0f);
|
||||
Float remaining = (r.maxt - r.mint) * dLength;
|
||||
Float integral = 0.0f;
|
||||
int iterations = 0;
|
||||
|
@ -462,7 +462,7 @@ public:
|
|||
bool sampleDistance(const Ray &r, Float maxDist,
|
||||
MediumSamplingRecord &mRec, Sampler *sampler) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength);
|
||||
Ray ray(r(r.mint), r.d / dLength, 0.0f);
|
||||
Float remaining = (maxDist - r.mint) * dLength,
|
||||
desiredTau = -std::log(1-sampler->next1D())/m_sizeMultiplier,
|
||||
accumulatedTau = 0.0f,
|
||||
|
|
|
@ -168,7 +168,7 @@ public:
|
|||
|
||||
Spectrum tau(const Ray &r) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength);
|
||||
Ray ray(r(r.mint), r.d / dLength, 0.0f);
|
||||
Float remaining = (r.maxt - r.mint) * dLength;
|
||||
Float integral = 0.0f;
|
||||
int iterations = 0;
|
||||
|
@ -266,7 +266,7 @@ public:
|
|||
bool sampleDistance(const Ray &r, Float maxDist,
|
||||
MediumSamplingRecord &mRec, Sampler *sampler) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength);
|
||||
Ray ray(r(r.mint), r.d / dLength, 0.0f);
|
||||
Float remaining = (maxDist - r.mint) * dLength,
|
||||
desiredTau = -std::log(1-sampler->next1D())/m_sizeMultiplier,
|
||||
accumulatedTau = 0.0f,
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
}
|
||||
|
||||
bool isInside(const Ray &r) const {
|
||||
Ray ray(r(r.mint + Epsilon), r.d);
|
||||
Ray ray(r(r.mint + Epsilon), r.d, 0.0f);
|
||||
Intersection its;
|
||||
if (!m_kdTree->rayIntersect(ray, its))
|
||||
return false;
|
||||
|
@ -121,7 +121,7 @@ public:
|
|||
|
||||
Spectrum tau(const Ray &r) const {
|
||||
Float dLength = r.d.length();
|
||||
Ray ray(r(r.mint), r.d / dLength, Epsilon, std::numeric_limits<Float>::infinity());
|
||||
Ray ray(r(r.mint), r.d / dLength, Epsilon, std::numeric_limits<Float>::infinity(), 0.0f);
|
||||
Float coveredLength = 0, remaining = (r.maxt - r.mint) * dLength;
|
||||
bool inside = isInside(r);
|
||||
Intersection its;
|
||||
|
@ -147,7 +147,7 @@ public:
|
|||
bool sampleDistance(const Ray &theRay, Float distSurf,
|
||||
MediumSamplingRecord &mRec, Sampler *sampler) const {
|
||||
Intersection its;
|
||||
Ray ray(theRay.o, theRay.d);
|
||||
Ray ray(theRay.o, theRay.d, 0.0f);
|
||||
int iterations = 0;
|
||||
|
||||
/* Check if the start of the ray is already inside the medium */
|
||||
|
|
|
@ -92,11 +92,12 @@ void PreviewProcess::configure(const VPL &vpl, Float minDist, const Point2 &jitt
|
|||
const Point2 right(topLeft.x + m_film->getSize().x, topLeft.y);
|
||||
const Point2 bottom(topLeft.x, topLeft.y + m_film->getSize().y);
|
||||
const Point2 lens(0, 0);
|
||||
Float time = 0.0f;
|
||||
|
||||
const Camera *camera = m_scene->getCamera();
|
||||
camera->generateRay(topLeft, lens, topLeftRay);
|
||||
camera->generateRay(right, lens, rightRay);
|
||||
camera->generateRay(bottom, lens, bottomRay);
|
||||
camera->generateRay(topLeft, lens, time, topLeftRay);
|
||||
camera->generateRay(right, lens, time, rightRay);
|
||||
camera->generateRay(bottom, lens, time, bottomRay);
|
||||
m_cameraTL = Vector(topLeftRay.d);
|
||||
m_cameraO = camera->getPosition();
|
||||
m_cameraDx = (rightRay.d - topLeftRay.d)
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
#define TIME 0
|
||||
|
||||
class AnimatedInstance : public Shape {
|
||||
public:
|
||||
AnimatedInstance(const Properties &props) : Shape(props) {
|
||||
|
@ -96,7 +94,7 @@ public:
|
|||
const KDTree *kdtree = m_shapeGroup->getKDTree();
|
||||
Ray ray;
|
||||
Transform objectToWorld, worldToObject;
|
||||
m_transform->eval(TIME, objectToWorld);
|
||||
m_transform->eval(_ray.time, objectToWorld);
|
||||
worldToObject = objectToWorld.inverse();
|
||||
worldToObject(_ray, ray);
|
||||
return kdtree->rayIntersect(ray, mint, maxt, t, temp);
|
||||
|
@ -106,7 +104,7 @@ public:
|
|||
const KDTree *kdtree = m_shapeGroup->getKDTree();
|
||||
Ray ray;
|
||||
Transform objectToWorld, worldToObject;
|
||||
m_transform->eval(TIME, objectToWorld);
|
||||
m_transform->eval(_ray.time, objectToWorld);
|
||||
worldToObject = objectToWorld.inverse();
|
||||
worldToObject(_ray, ray);
|
||||
return kdtree->rayIntersect(ray, mint, maxt);
|
||||
|
@ -116,7 +114,7 @@ public:
|
|||
const void *temp, Intersection &its) const {
|
||||
const KDTree *kdtree = m_shapeGroup->getKDTree();
|
||||
Transform objectToWorld;
|
||||
m_transform->eval(TIME, objectToWorld);
|
||||
m_transform->eval(ray.time, objectToWorld);
|
||||
kdtree->fillIntersectionRecord<false>(ray, temp, its);
|
||||
its.shFrame.n = normalize(objectToWorld(its.shFrame.n));
|
||||
its.shFrame.s = normalize(objectToWorld(its.shFrame.s));
|
||||
|
|
|
@ -209,7 +209,7 @@ public:
|
|||
Vector d = Frame(w*invDistW).toWorld(
|
||||
squareToCone(cosThetaMax, sample));
|
||||
|
||||
Ray ray(p, d);
|
||||
Ray ray(p, d, 0.0f);
|
||||
Float t;
|
||||
if (!rayIntersect(ray, 0, std::numeric_limits<Float>::infinity(), t, NULL)) {
|
||||
// This can happen sometimes due to roundoff errors - just fail to
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
const RangeWorkUnit *range = static_cast<const RangeWorkUnit *>(workUnit);
|
||||
IrradianceRecordVector *result = static_cast<IrradianceRecordVector *>(workResult);
|
||||
const SampleIntegrator *integrator = m_integrator.get();
|
||||
ref<Camera> camera = m_scene->getCamera();
|
||||
|
||||
result->clear();
|
||||
for (size_t i=range->getRangeStart(); i<range->getRangeEnd(); ++i) {
|
||||
|
@ -83,10 +84,11 @@ public:
|
|||
expSamples *= m_sampleCount;
|
||||
ShapeSamplingRecord sRec;
|
||||
Float pdf = m_shapes[index]->sampleArea(sRec, sample) * expSamples;
|
||||
Float time = camera->getShutterOpen() + m_sampler->next1D() * camera->getShutterOpenTime();
|
||||
|
||||
result->put(IrradianceSample(
|
||||
sRec.p,
|
||||
integrator->E(m_scene.get(), sRec.p, sRec.n, m_independentSampler),
|
||||
integrator->E(m_scene.get(), sRec.p, sRec.n, time, m_independentSampler),
|
||||
1/pdf
|
||||
));
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public:
|
|||
sample2(random->nextFloat(), random->nextFloat());
|
||||
Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius;
|
||||
Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius;
|
||||
Ray r(p1, normalize(p2-p1));
|
||||
Ray r(p1, normalize(p2-p1), 0.0f);
|
||||
Intersection its;
|
||||
|
||||
if (tree->rayIntersect(r))
|
||||
|
|
|
@ -225,7 +225,7 @@ public:
|
|||
sample2(random->nextFloat(), random->nextFloat());
|
||||
Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius;
|
||||
Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius;
|
||||
Ray r(p1, normalize(p2-p1));
|
||||
Ray r(p1, normalize(p2-p1), 0.0f);
|
||||
|
||||
Intersection its;
|
||||
if (kdtree->rayIntersect(r, its))
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import os
|
||||
|
||||
bl_addon_info = {
|
||||
"name": "Mitsuba",
|
||||
"author": "Wenzel Jakob",
|
||||
|
@ -30,6 +32,8 @@ bl_addon_info = {
|
|||
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba",
|
||||
"category": "Render"}
|
||||
|
||||
def plugin_path():
|
||||
return os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
from .core import RENDERENGINE_mitsuba
|
||||
|
||||
|
|
|
@ -27,7 +27,10 @@ from extensions_framework.engine import engine_base
|
|||
from extensions_framework import util as efutil
|
||||
|
||||
# Mitsuba-related classes
|
||||
from mitsuba import plugin_path
|
||||
from mitsuba.properties.engine import mitsuba_engine
|
||||
from mitsuba.properties.sampler import mitsuba_sampler
|
||||
from mitsuba.properties.integrator import mitsuba_integrator
|
||||
from mitsuba.properties.lamp import mitsuba_lamp
|
||||
from mitsuba.properties.texture import mitsuba_texture, \
|
||||
mitsuba_tex_ldrtexture, mitsuba_tex_checkerboard, \
|
||||
|
@ -40,9 +43,11 @@ from mitsuba.properties.material import mitsuba_material, \
|
|||
mitsuba_mat_composite, mitsuba_emission
|
||||
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba
|
||||
from mitsuba.outputs import MtsLog, MtsFilmDisplay
|
||||
from mitsuba.export.adjustments import MtsAdjustments
|
||||
from mitsuba.export import translate_id
|
||||
from mitsuba.export.film import resolution
|
||||
from mitsuba.ui import render_panels
|
||||
from mitsuba.ui import lamps
|
||||
from mitsuba.export import get_instance_materials
|
||||
from mitsuba.ui import render_panels, lamps
|
||||
from mitsuba.ui.textures import TEXTURE_PT_context_texture_mts
|
||||
from mitsuba.ui.textures import main, ldrtexture, checkerboard, \
|
||||
gridtexture, mapping
|
||||
|
@ -76,9 +81,12 @@ compatible("properties_data_camera")
|
|||
class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
||||
bl_idname = 'mitsuba'
|
||||
bl_label = 'Mitsuba'
|
||||
bl_use_preview = True
|
||||
|
||||
property_groups = [
|
||||
('Scene', mitsuba_engine),
|
||||
('Scene', mitsuba_integrator),
|
||||
('Scene', mitsuba_sampler),
|
||||
('Lamp', mitsuba_lamp),
|
||||
('Texture', mitsuba_texture),
|
||||
('mitsuba_texture', mitsuba_tex_ldrtexture),
|
||||
|
@ -104,31 +112,124 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
|||
def process_wait_timer(self):
|
||||
# Nothing to do here
|
||||
pass
|
||||
|
||||
def render_preview(self, scene):
|
||||
# Iterate through the preview scene, finding objects with materials attached
|
||||
objects_materials = {}
|
||||
|
||||
if resolution(scene) == (96, 96):
|
||||
return
|
||||
|
||||
for object in [ob for ob in scene.objects if ob.is_visible(scene) and not ob.hide_render]:
|
||||
for mat in get_instance_materials(object):
|
||||
if mat is not None:
|
||||
if not object.name in objects_materials.keys(): objects_materials[object] = []
|
||||
objects_materials[object].append(mat)
|
||||
|
||||
# find objects that are likely to be the preview objects
|
||||
preview_objects = [o for o in objects_materials.keys() if o.name.startswith('preview')]
|
||||
if len(preview_objects) < 1:
|
||||
return
|
||||
|
||||
# find the materials attached to the likely preview object
|
||||
likely_materials = objects_materials[preview_objects[0]]
|
||||
if len(likely_materials) < 1:
|
||||
return
|
||||
|
||||
tempdir = efutil.temp_directory()
|
||||
matfile = os.path.join(tempdir, "matpreview_materials.xml")
|
||||
output_file = os.path.join(tempdir, "matpreview.png")
|
||||
scene_file = os.path.join(os.path.join(plugin_path(),
|
||||
"matpreview"), "matpreview.xml")
|
||||
pm = likely_materials[0]
|
||||
adj = MtsAdjustments(matfile, tempdir,
|
||||
bpy.data.materials, bpy.data.textures)
|
||||
adj.writeHeader()
|
||||
adj.exportMaterial(pm)
|
||||
adj.exportPreviewMesh(pm)
|
||||
adj.writeFooter()
|
||||
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path))
|
||||
mitsuba_binary = os.path.join(mts_path, "mitsuba")
|
||||
env = copy.copy(os.environ)
|
||||
mts_render_libpath = os.path.join(mts_path, "src/librender")
|
||||
mts_core_libpath = os.path.join(mts_path, "src/libcore")
|
||||
mts_hw_libpath = os.path.join(mts_path, "src/libhw")
|
||||
env['LD_LIBRARY_PATH'] = mts_core_libpath + ":" + mts_render_libpath + ":" + mts_hw_libpath
|
||||
(width, height) = resolution(scene)
|
||||
refresh_interval = 1
|
||||
preview_spp = int(efutil.find_config_value('mitsuba', 'defaults', 'preview_spp', '16'))
|
||||
preview_depth = int(efutil.find_config_value('mitsuba', 'defaults', 'preview_depth', '2'))
|
||||
mitsuba_process = subprocess.Popen(
|
||||
[mitsuba_binary, '-q',
|
||||
'-r%i' % refresh_interval,
|
||||
'-o', output_file, '-Dmatfile=%s' % matfile,
|
||||
'-Dwidth=%i' % width,
|
||||
'-Dheight=%i' % height,
|
||||
'-Dspp=%i' % preview_spp,
|
||||
'-Ddepth=%i' % preview_depth,
|
||||
'-o', output_file, scene_file],
|
||||
env = env,
|
||||
cwd = tempdir
|
||||
)
|
||||
framebuffer_thread = MtsFilmDisplay({
|
||||
'resolution': resolution(scene),
|
||||
'RE': self,
|
||||
'output_file': output_file
|
||||
})
|
||||
framebuffer_thread.set_kick_period(refresh_interval)
|
||||
framebuffer_thread.start()
|
||||
render_update_timer = None
|
||||
while mitsuba_process.poll() == None and not self.test_break():
|
||||
render_update_timer = threading.Timer(1, self.process_wait_timer)
|
||||
render_update_timer.start()
|
||||
if render_update_timer.isAlive(): render_update_timer.join()
|
||||
|
||||
# If we exit the wait loop (user cancelled) and mitsuba is still running, then send SIGINT
|
||||
if mitsuba_process.poll() == None:
|
||||
# Use SIGTERM because that's the only one supported on Windows
|
||||
mitsuba_process.send_signal(subprocess.signal.SIGTERM)
|
||||
|
||||
# Stop updating the render result and load the final image
|
||||
framebuffer_thread.stop()
|
||||
framebuffer_thread.join()
|
||||
|
||||
if mitsuba_process.poll() != None and mitsuba_process.returncode != 0:
|
||||
MtsLog("MtsBlend: Rendering failed -- check the console")
|
||||
else:
|
||||
framebuffer_thread.kick(render_end=True)
|
||||
|
||||
|
||||
def render(self, scene):
|
||||
if scene is None:
|
||||
bpy.ops.ef.msg(msg_type='ERROR', msg_text='Scene to render is not valid')
|
||||
return
|
||||
if scene.mitsuba_engine.binary_path == '':
|
||||
bpy.ops.ef.msg(msg_type='ERROR', msg_text='The Mitsuba binary path is unspecified!')
|
||||
return
|
||||
|
||||
with self.render_lock: # just render one thing at a time
|
||||
if scene.name == 'preview':
|
||||
self.render_preview(scene)
|
||||
return
|
||||
|
||||
scene_path = efutil.filesystem_path(scene.render.filepath)
|
||||
if os.path.isdir(scene_path):
|
||||
self.output_dir = scene_path
|
||||
output_dir = scene_path
|
||||
else:
|
||||
self.output_dir = os.path.dirname(scene_path)
|
||||
if self.output_dir[-1] != '/':
|
||||
self.output_dir += '/'
|
||||
efutil.export_path = self.output_dir
|
||||
os.chdir(self.output_dir)
|
||||
output_dir = os.path.dirname(scene_path)
|
||||
if output_dir[-1] != '/':
|
||||
output_dir += '/'
|
||||
efutil.export_path = output_dir
|
||||
os.chdir(output_dir)
|
||||
|
||||
if scene.render.use_color_management == False:
|
||||
MtsLog('WARNING: Colour Management is switched off, render results may look too dark.')
|
||||
|
||||
MtsLog('MtsBlend: Current directory = "%s"' % self.output_dir)
|
||||
MtsLog('MtsBlend: Current directory = "%s"' % output_dir)
|
||||
output_basename = efutil.scene_filename() + '.%s.%05i' % (scene.name, scene.frame_current)
|
||||
|
||||
export_result = bpy.ops.export.mitsuba(
|
||||
directory = self.output_dir,
|
||||
directory = output_dir,
|
||||
filename = output_basename,
|
||||
scene = scene.name
|
||||
)
|
||||
|
@ -151,27 +252,29 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
|||
subprocess.Popen(
|
||||
[mtsgui_binary, efutil.export_path],
|
||||
env = env,
|
||||
cwd = self.output_dir
|
||||
cwd = output_dir
|
||||
)
|
||||
elif scene.mitsuba_engine.render_mode == 'cli':
|
||||
self.output_file = efutil.export_path[:-4] + ".png"
|
||||
output_file = efutil.export_path[:-4] + ".png"
|
||||
|
||||
mitsuba_process = subprocess.Popen(
|
||||
[mitsuba_binary, '-r', '%d' % scene.mitsuba_engine.refresh_interval,
|
||||
'-o', self.output_file, efutil.export_path],
|
||||
'-o', output_file, efutil.export_path],
|
||||
env = env,
|
||||
cwd = self.output_dir
|
||||
cwd = output_dir
|
||||
)
|
||||
framebuffer_thread = MtsFilmDisplay({
|
||||
'resolution': resolution(scene),
|
||||
'RE': self,
|
||||
'output_file': output_file
|
||||
})
|
||||
framebuffer_thread.set_kick_period(scene.mitsuba_engine.refresh_interval)
|
||||
framebuffer_thread.start()
|
||||
render_update_timer = None
|
||||
while mitsuba_process.poll() == None and not self.test_break():
|
||||
self.render_update_timer = threading.Timer(1, self.process_wait_timer)
|
||||
self.render_update_timer.start()
|
||||
if self.render_update_timer.isAlive(): self.render_update_timer.join()
|
||||
render_update_timer = threading.Timer(1, self.process_wait_timer)
|
||||
render_update_timer.start()
|
||||
if render_update_timer.isAlive(): render_update_timer.join()
|
||||
|
||||
# If we exit the wait loop (user cancelled) and mitsuba is still running, then send SIGINT
|
||||
if mitsuba_process.poll() == None:
|
||||
|
|
|
@ -189,3 +189,15 @@ class ParamSet(list):
|
|||
|
||||
def to_string_ref(self):
|
||||
return ''.join(item.to_string_ref() for item in self)
|
||||
|
||||
def get_instance_materials(ob):
|
||||
obmats = []
|
||||
# Grab materials attached to object instances ...
|
||||
if hasattr(ob, 'material_slots'):
|
||||
for ms in ob.material_slots:
|
||||
obmats.append(ms.material)
|
||||
# ... and to the object's mesh data
|
||||
if hasattr(ob.data, 'materials'):
|
||||
for m in ob.data.materials:
|
||||
obmats.append(m)
|
||||
return obmats
|
||||
|
|
|
@ -30,48 +30,57 @@ class MtsAdjustments:
|
|||
in translation when using the COLLADA exporter.
|
||||
'''
|
||||
|
||||
def __init__(self, target_file, target_dir):
|
||||
def __init__(self, target_file, target_dir, materials = None, textures = None):
|
||||
self.target_file = target_file
|
||||
self.target_dir = target_dir
|
||||
self.exported_materials = []
|
||||
self.exported_textures = []
|
||||
self.materials = materials if materials != None else bpy.data.textures
|
||||
self.textures = textures if textures != None else bpy.data.textures
|
||||
|
||||
def export_worldtrafo(self, adjfile, trafo):
|
||||
adjfile.write('\t\t<transform name="toWorld">\n')
|
||||
adjfile.write('\t\t\t<matrix value="')
|
||||
def exportWorldtrafo(self, trafo):
|
||||
self.out.write('\t\t<transform name="toWorld">\n')
|
||||
self.out.write('\t\t\t<matrix value="')
|
||||
for j in range(0,4):
|
||||
for i in range(0,4):
|
||||
adjfile.write("%f " % trafo[i][j])
|
||||
adjfile.write('"/>\n\t\t</transform>\n')
|
||||
self.out.write("%f " % trafo[i][j])
|
||||
self.out.write('"/>\n\t\t</transform>\n')
|
||||
|
||||
def export_lamp(self, adjfile, lamp, idx):
|
||||
def exportLamp(self, lamp, idx):
|
||||
ltype = lamp.data.mitsuba_lamp.type
|
||||
name = translate_id(lamp.data.name)
|
||||
if ltype == 'POINT':
|
||||
adjfile.write('\t<luminaire id="%s-light" type="point">\n' % lamp.data.name)
|
||||
self.out.write('\t<luminaire id="%s-light" type="point">\n' % name)
|
||||
mult = lamp.data.mitsuba_lamp.intensity
|
||||
self.export_worldtrafo(adjfile, lamp.matrix_world)
|
||||
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.exportWorldtrafo(lamp.matrix_world)
|
||||
self.out.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
|
||||
adjfile.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
adjfile.write('\t</luminaire>\n')
|
||||
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
self.out.write('\t</luminaire>\n')
|
||||
elif ltype == 'AREA':
|
||||
adjfile.write('\t<shape type="obj">\n')
|
||||
self.out.write('\t<shape type="obj">\n')
|
||||
size_x = lamp.data.size
|
||||
size_y = lamp.data.size
|
||||
if lamp.data.shape == 'RECTANGLE':
|
||||
size_y = lamp.data.size_y
|
||||
path = os.path.join(os.path.join(self.target_dir, 'meshes'), "_area_luminaire_%d.obj" % idx)
|
||||
mts_meshes_dir = os.path.join(self.target_dir, 'meshes')
|
||||
filename = "area_luminaire_%d.obj" % idx
|
||||
|
||||
adjfile.write('\t\t<string name="filename" value="%s"/>\n' % path)
|
||||
self.export_worldtrafo(adjfile, lamp.matrix_world)
|
||||
|
||||
adjfile.write('\n\t\t<luminaire id="%s-light" type="area">\n' % lamp.data.name)
|
||||
self.out.write('\t\t<string name="filename" value="meshes/%s"/>\n' % filename)
|
||||
self.exportWorldtrafo(lamp.matrix_world)
|
||||
self.out.write('\n\t\t<luminaire id="%s-light" type="area">\n' % name)
|
||||
mult = lamp.data.mitsuba_lamp.intensity / (2 * size_x * size_y)
|
||||
adjfile.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.out.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
|
||||
adjfile.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
adjfile.write('\t\t</luminaire>\n')
|
||||
adjfile.write('\t</shape>\n')
|
||||
self.out.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
self.out.write('\t\t</luminaire>\n')
|
||||
self.out.write('\t</shape>\n')
|
||||
|
||||
try:
|
||||
os.mkdir(mts_meshes_dir)
|
||||
except OSError:
|
||||
pass
|
||||
path = os.path.join(mts_meshes_dir, filename)
|
||||
objFile = open(path, 'w')
|
||||
objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2))
|
||||
objFile.write('v %f %f 0\n' % ( size_x/2, -size_y/2))
|
||||
|
@ -80,52 +89,62 @@ class MtsAdjustments:
|
|||
objFile.write('f 4 3 2 1\n')
|
||||
objFile.close()
|
||||
elif ltype == 'SUN':
|
||||
adjfile.write('\t<luminaire id="%s-light" type="directional">\n' % lamp.data.name)
|
||||
self.out.write('\t<luminaire id="%s-light" type="directional">\n' % name)
|
||||
mult = lamp.data.mitsuba_lamp.intensity
|
||||
scale = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))
|
||||
self.export_worldtrafo(adjfile, lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
|
||||
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.exportWorldtrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
|
||||
self.out.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
|
||||
adjfile.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
adjfile.write('\t</luminaire>\n')
|
||||
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
self.out.write('\t</luminaire>\n')
|
||||
elif ltype == 'SPOT':
|
||||
adjfile.write('\t<luminaire id="%s-light" type="spot">\n' % lamp.data.name)
|
||||
self.out.write('\t<luminaire id="%s-light" type="spot">\n' % name)
|
||||
mult = lamp.data.mitsuba_lamp.intensity
|
||||
self.export_worldtrafo(adjfile, lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
|
||||
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.exportWorldtrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
|
||||
self.out.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
|
||||
adjfile.write('\t\t<float name="cutoffAngle" value="%f"/>\n' % (lamp.data.spot_size * 180 / (math.pi * 2)))
|
||||
adjfile.write('\t\t<float name="beamWidth" value="%f"/>\n' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2)))
|
||||
adjfile.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
adjfile.write('\t</luminaire>\n')
|
||||
self.out.write('\t\t<float name="cutoffAngle" value="%f"/>\n' % (lamp.data.spot_size * 180 / (math.pi * 2)))
|
||||
self.out.write('\t\t<float name="beamWidth" value="%f"/>\n' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2)))
|
||||
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
self.out.write('\t</luminaire>\n')
|
||||
elif ltype == 'ENV':
|
||||
if lamp.data.mitsuba_lamp.envmap_type == 'constant':
|
||||
adjfile.write('\t<luminaire id="%s-light" type="constant">\n' % lamp.data.name)
|
||||
self.out.write('\t<luminaire id="%s-light" type="constant">\n' % name)
|
||||
mult = lamp.data.mitsuba_lamp.intensity
|
||||
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.out.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
|
||||
adjfile.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
adjfile.write('\t</luminaire>\n')
|
||||
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
|
||||
self.out.write('\t</luminaire>\n')
|
||||
elif lamp.data.mitsuba_lamp.envmap_type == 'envmap':
|
||||
adjfile.write('\t<luminaire id="%s-light" type="envmap">\n' % lamp.data.name)
|
||||
adjfile.write('\t\t<string name="filename" value="%s"/>\n' % efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file))
|
||||
self.export_worldtrafo(adjfile, lamp.matrix_world)
|
||||
adjfile.write('\t\t<float name="intensityScale" value="%f"/>\n' % lamp.data.mitsuba_lamp.intensity)
|
||||
adjfile.write('\t</luminaire>\n')
|
||||
self.out.write('\t<luminaire id="%s-light" type="envmap">\n' % name)
|
||||
self.out.write('\t\t<string name="filename" value="%s"/>\n' % efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file))
|
||||
self.exportWorldtrafo(lamp.matrix_world)
|
||||
self.out.write('\t\t<float name="intensityScale" value="%f"/>\n' % lamp.data.mitsuba_lamp.intensity)
|
||||
self.out.write('\t</luminaire>\n')
|
||||
|
||||
def find_texture(self, name):
|
||||
if name in bpy.data.textures:
|
||||
return bpy.data.textures[name]
|
||||
def exportIntegrator(self, integrator):
|
||||
self.out.write('\t<integrator id="integrator" type="%s">\n' % integrator.type)
|
||||
self.out.write('\t</integrator>\n')
|
||||
|
||||
def exportSampler(self, sampler):
|
||||
self.out.write('\t<sampler id="sampler" type="%s">\n' % sampler.type)
|
||||
self.out.write('\t\t<integer name="sampleCount" value="%i"/>\n' % sampler.sampleCount)
|
||||
self.out.write('\t</sampler>\n')
|
||||
|
||||
def findTexture(self, name):
|
||||
if name in self.textures:
|
||||
return self.textures[name]
|
||||
else:
|
||||
raise Exception('Failed to find texture "%s"' % name)
|
||||
|
||||
def find_material(self, name):
|
||||
if name in bpy.data.materials:
|
||||
return bpy.data.materials[name]
|
||||
|
||||
def findMaterial(self, name):
|
||||
if name in self.materials:
|
||||
return self.materials[name]
|
||||
else:
|
||||
raise Exception('Failed to find material "%s"' % name)
|
||||
|
||||
def export_texture(self, adjfile, mat):
|
||||
def exportTexture(self, mat):
|
||||
if mat.name in self.exported_textures:
|
||||
return
|
||||
self.exported_textures += [mat.name]
|
||||
|
@ -133,14 +152,14 @@ class MtsAdjustments:
|
|||
|
||||
for p in params:
|
||||
if p.type == 'reference_texture':
|
||||
self.export_texture(adjfile, self.find_texture(p.value))
|
||||
self.exportTexture(self.findTexture(p.value))
|
||||
|
||||
adjfile.write('\t<texture id="%s" type="%s">\n' % (translate_id(mat.name), mat.mitsuba_texture.type))
|
||||
adjfile.write(params.to_string())
|
||||
adjfile.write(params.to_string_ref())
|
||||
adjfile.write('\t</texture>\n')
|
||||
self.out.write('\t<texture id="%s" type="%s">\n' % (translate_id(mat.name), mat.mitsuba_texture.type))
|
||||
self.out.write(params.to_string())
|
||||
self.out.write(params.to_string_ref())
|
||||
self.out.write('\t</texture>\n')
|
||||
|
||||
def export_material(self, adjfile, mat):
|
||||
def exportMaterial(self, mat):
|
||||
if mat.name in self.exported_materials:
|
||||
return
|
||||
self.exported_materials += [mat.name]
|
||||
|
@ -148,44 +167,68 @@ class MtsAdjustments:
|
|||
|
||||
for p in params:
|
||||
if p.type == 'reference_material':
|
||||
self.export_material(adjfile, self.find_material(p.value))
|
||||
self.exportMaterial(self.findMaterial(p.value))
|
||||
elif p.type == 'reference_texture':
|
||||
self.export_texture(adjfile, self.find_texture(p.value))
|
||||
self.exportTexture(self.findTexture(p.value))
|
||||
|
||||
adjfile.write('\t<bsdf id="%s" type="%s">\n' % (translate_id(mat.name), mat.mitsuba_material.type))
|
||||
adjfile.write(params.to_string())
|
||||
adjfile.write(params.to_string_ref())
|
||||
adjfile.write('\t</bsdf>\n')
|
||||
self.out.write('\t<bsdf id="%s" type="%s">\n' % (translate_id(mat.name), mat.mitsuba_material.type))
|
||||
self.out.write(params.to_string())
|
||||
self.out.write(params.to_string_ref())
|
||||
self.out.write('\t</bsdf>\n')
|
||||
|
||||
def export_emission(self, adjfile, obj):
|
||||
def exportEmission(self, obj):
|
||||
lamp = obj.data.materials[0].mitsuba_emission
|
||||
name = translate_id(obj.data.name)
|
||||
adjfile.write('\t<shape id="%s-mesh_0" type="serialized">\n' % name)
|
||||
adjfile.write('\t\t<string name="filename" value="meshes/%s-mesh_0.serialized"/>\n' % name)
|
||||
self.export_worldtrafo(adjfile, obj.matrix_world)
|
||||
adjfile.write('\t\t<luminaire type="area">\n')
|
||||
self.out.write('\t<append id="%s-mesh_0">\n' % name)
|
||||
self.out.write('\t\t<luminaire type="area">\n')
|
||||
mult = lamp.intensity
|
||||
adjfile.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
self.out.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult))
|
||||
adjfile.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.samplingWeight)
|
||||
adjfile.write('\t\t</luminaire>\n')
|
||||
adjfile.write('\t</shape>\n')
|
||||
self.out.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.samplingWeight)
|
||||
self.out.write('\t\t</luminaire>\n')
|
||||
self.out.write('\t</append>\n')
|
||||
|
||||
def writeHeader(self):
|
||||
self.out = open(self.target_file, 'w')
|
||||
self.out.write('<scene>\n');
|
||||
|
||||
def writeFooter(self):
|
||||
self.out.write('</scene>\n');
|
||||
self.out.close()
|
||||
|
||||
def exportPreviewMesh(self, material):
|
||||
self.out.write('\t\t<shape id="Exterior-mesh_0" type="serialized">\n')
|
||||
self.out.write('\t\t\t<string name="filename" value="matpreview.serialized"/>\n')
|
||||
self.out.write('\t\t\t<integer name="shapeIndex" value="1"/>\n')
|
||||
self.out.write('\t\t\t<transform name="toWorld">\n')
|
||||
self.out.write('\t\t\t\t<matrix value="0.614046 0.614047 0 -1.78814e-07 -0.614047 0.614046 0 2.08616e-07 0 0 0.868393 1.02569 0 0 0 1"/>\n')
|
||||
self.out.write('\t\t\t</transform>\n')
|
||||
self.out.write('\t\t\t<ref id="%s" name="bsdf"/>\n' % translate_id(material.name))
|
||||
lamp = material.mitsuba_emission
|
||||
if lamp and lamp.use_emission:
|
||||
mult = lamp.intensity
|
||||
self.out.write('\t\t\t<luminaire type="area">\n')
|
||||
self.out.write('\t\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
|
||||
% (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult))
|
||||
self.out.write('\t\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.samplingWeight)
|
||||
self.out.write('\t\t\t</luminaire>\n')
|
||||
self.out.write('\t\t</shape>\n')
|
||||
self.out.write('\n')
|
||||
|
||||
def export(self, scene):
|
||||
adjfile = open(self.target_file, 'w')
|
||||
adjfile.write('<adjustments>\n');
|
||||
idx = 0
|
||||
self.writeHeader()
|
||||
self.exportIntegrator(scene.mitsuba_integrator)
|
||||
self.exportSampler(scene.mitsuba_sampler)
|
||||
for obj in scene.objects:
|
||||
if obj.type == 'LAMP':
|
||||
self.export_lamp(adjfile, obj, idx)
|
||||
self.exportLamp(obj, idx)
|
||||
elif obj.type == 'MESH':
|
||||
for mat in obj.data.materials:
|
||||
self.export_material(adjfile, mat)
|
||||
self.exportMaterial(mat)
|
||||
if len(obj.data.materials) > 0 and obj.data.materials[0].mitsuba_emission.use_emission:
|
||||
self.export_emission(adjfile, obj)
|
||||
self.exportEmission(obj)
|
||||
idx = idx+1
|
||||
adjfile.write('</adjustments>\n');
|
||||
adjfile.close()
|
||||
|
||||
self.writeFooter()
|
||||
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
|
||||
<!--
|
||||
|
||||
Automatically converted from COLLADA
|
||||
|
||||
-->
|
||||
<scene>
|
||||
<integrator id="integrator" type="path">
|
||||
<integer name="maxDepth" value="$depth"/>
|
||||
</integrator>
|
||||
|
||||
<include filename="$matfile"/>
|
||||
|
||||
<camera id="Camera-camera" type="perspective">
|
||||
<float name="fov" value="28.8415"/>
|
||||
<boolean name="mapSmallerSide" value="true"/>
|
||||
|
||||
<transform name="toWorld">
|
||||
<matrix value="0.68588 -0.31737 -0.654862 3.69558 0.727634 0.312469 0.610666 -3.46243 -0.0108168 0.895343 -0.445245 3.25463 0 0 0 1"/>
|
||||
</transform>
|
||||
|
||||
<sampler type="ldsampler">
|
||||
<integer name="sampleCount" value="$spp"/>
|
||||
</sampler>
|
||||
|
||||
<film id="film" type="pngfilm">
|
||||
<integer name="width" value="$width"/>
|
||||
<integer name="height" value="$height"/>
|
||||
<boolean name="alpha" value="false"/>
|
||||
<boolean name="banner" value="false"/>
|
||||
<rfilter type="gaussian"/>
|
||||
</film>
|
||||
</camera>
|
||||
|
||||
<luminaire id="Area_002-light" type="envmap">
|
||||
<string name="filename" value="envmap.exr"/>
|
||||
<transform name="toWorld">
|
||||
<matrix value="-0.224951 -0.000001 -0.974370 0.000000 -0.974370 0.000000 0.224951 0.000000 0.000000 1.000000 -0.000001 8.870000 0.000000 0.000000 0.000000 1.000000 "/>
|
||||
</transform>
|
||||
<float name="intensityScale" value="1.540006"/>
|
||||
</luminaire>
|
||||
|
||||
<bsdf id="__diffmat" type="lambertian">
|
||||
<rgb name="reflectance" value="0.5 0.5 0.5"/>
|
||||
</bsdf>
|
||||
|
||||
<texture id="__planetex" type="checkerboard">
|
||||
<rgb name="darkColor" value="0.20000000298 0.20000000298 0.20000000298"/>
|
||||
<rgb name="brightColor" value="0.40000000596 0.40000000596 0.40000000596"/>
|
||||
<float name="uscale" value="30.0"/>
|
||||
<float name="vscale" value="30.0"/>
|
||||
<float name="uoffset" value="0.0"/>
|
||||
<float name="voffset" value="0.0"/>
|
||||
</texture>
|
||||
|
||||
<bsdf id="__planemat" type="lambertian">
|
||||
<ref id="__planetex" name="reflectance"/>
|
||||
</bsdf>
|
||||
|
||||
<shape id="Interior-mesh_0" type="serialized">
|
||||
<string name="filename" value="matpreview.serialized"/>
|
||||
<integer name="shapeIndex" value="0"/>
|
||||
<transform name="toWorld">
|
||||
<matrix value="1 0 0 0 0 1 0 0 0 0 1 0.0252155 0 0 0 1"/>
|
||||
</transform>
|
||||
<ref id="__diffmat" name="bsdf"/>
|
||||
</shape>
|
||||
|
||||
<shape id="Plane-mesh_0" type="serialized">
|
||||
<string name="filename" value="matpreview.serialized"/>
|
||||
<integer name="shapeIndex" value="2"/>
|
||||
<transform name="toWorld">
|
||||
<matrix value="20 0 0 -10 0 20 0 10 0 0 20 0 0 0 0 1"/>
|
||||
</transform>
|
||||
<ref id="__planemat" name="bsdf"/>
|
||||
</shape>
|
||||
</scene>
|
|
@ -147,8 +147,6 @@ class EXPORT_OT_mitsuba(bpy.types.Operator):
|
|||
# Force scene update; NB, scene.update() doesn't work
|
||||
scene.frame_set(scene.frame_current)
|
||||
|
||||
(self.properties.filename, _) = os.path.splitext(self.properties.filename)
|
||||
|
||||
mts_basename = os.path.join(
|
||||
self.properties.directory,
|
||||
self.properties.filename)
|
||||
|
@ -169,13 +167,10 @@ class EXPORT_OT_mitsuba(bpy.types.Operator):
|
|||
adj = MtsAdjustments(mts_adj_file, self.properties.directory)
|
||||
adj.export(scene)
|
||||
|
||||
if scene.mitsuba_engine.binary_path == "":
|
||||
if scene.mitsuba_engine.binary_path == '':
|
||||
self.report({'ERROR'}, 'Mitsuba binary path must be specified!')
|
||||
return {'CANCELLED'}
|
||||
|
||||
scene.mitsuba_engine.binary_path = efutil.filesystem_path(scene.mitsuba_engine.binary_path)
|
||||
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', scene.mitsuba_engine.binary_path)
|
||||
|
||||
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path))
|
||||
mtsimport_binary = os.path.join(mts_path, "mtsimport")
|
||||
env = copy.copy(os.environ)
|
||||
|
@ -251,7 +246,10 @@ class MITSUBA_OT_material_add(bpy.types.Operator):
|
|||
def execute(self, context):
|
||||
obj = bpy.context.active_object
|
||||
index = obj.active_material_index
|
||||
curName = obj.material_slots[index].name
|
||||
if len(obj.material_slots) == 0:
|
||||
curName = 'Material'
|
||||
else:
|
||||
curName = obj.material_slots[index].name
|
||||
mat = bpy.data.materials.new(name=curName)
|
||||
obj.data.materials.append(mat)
|
||||
obj.active_material_index = len(obj.data.materials)-1
|
||||
|
|
|
@ -27,12 +27,12 @@ class MtsFilmDisplay(TimerThread):
|
|||
MtsLog('Updating render result %ix%i' % (xres,yres))
|
||||
|
||||
result = self.LocalStorage['RE'].begin_result(0, 0, int(xres), int(yres))
|
||||
if os.path.exists(self.LocalStorage['RE'].output_file):
|
||||
if os.path.exists(self.LocalStorage['output_file']):
|
||||
bpy.ops.ef.msg(msg_text='Updating RenderResult')
|
||||
lay = result.layers[0]
|
||||
lay.load_from_file(self.LocalStorage['RE'].output_file)
|
||||
lay.load_from_file(self.LocalStorage['output_file'])
|
||||
else:
|
||||
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['RE'].output_file
|
||||
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['output_file']
|
||||
MtsLog(err_msg)
|
||||
bpy.ops.ef.msg(msg_type='ERROR', msg_text=err_msg)
|
||||
self.LocalStorage['RE'].end_result(result)
|
||||
|
|
|
@ -81,5 +81,25 @@ class mitsuba_engine(declarative_property_group):
|
|||
'soft_min': 1,
|
||||
'save_in_preset': True
|
||||
},
|
||||
{
|
||||
'type': 'int',
|
||||
'attr': 'preview_depth',
|
||||
'name': 'Depth',
|
||||
'description': 'Max. path depth used when generating the preview (2: direct illumination, 3: one-bounce indirect, etc.)',
|
||||
'default': int(efutil.find_config_value('mitsuba', 'defaults', 'preview_depth', '2')),
|
||||
'min': 2,
|
||||
'max': 10,
|
||||
'save_in_preset': True
|
||||
},
|
||||
{
|
||||
'type': 'int',
|
||||
'attr': 'preview_spp',
|
||||
'name': 'SPP',
|
||||
'description': 'Samples per pixel used to generate the preview',
|
||||
'default': int(efutil.find_config_value('mitsuba', 'defaults', 'preview_spp', '16')),
|
||||
'min': 1,
|
||||
'max': 128,
|
||||
'save_in_preset': True
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
class mitsuba_integrator(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Integrator settings.
|
||||
This class will be instantiated within a Blender scene
|
||||
object.
|
||||
'''
|
||||
|
||||
controls = [
|
||||
'type',
|
||||
'sampleCount'
|
||||
]
|
||||
|
||||
properties = [
|
||||
{
|
||||
'type': 'enum',
|
||||
'attr': 'type',
|
||||
'name': 'Type',
|
||||
'description': 'Specifies the type of integrator to use',
|
||||
'default': 'ldintegrator',
|
||||
'items': [
|
||||
('direct', 'Direct Illumination', 'direct'),
|
||||
('path', 'Path tracer', 'path'),
|
||||
],
|
||||
'save_in_preset': True
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
class mitsuba_sampler(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Sampler settings.
|
||||
This class will be instantiated within a Blender scene
|
||||
object.
|
||||
'''
|
||||
|
||||
controls = [
|
||||
'type',
|
||||
'sampleCount'
|
||||
]
|
||||
|
||||
properties = [
|
||||
{
|
||||
'type': 'enum',
|
||||
'attr': 'type',
|
||||
'name': 'Type',
|
||||
'description': 'Specifies the type of sampler to use',
|
||||
'default': 'ldsampler',
|
||||
'items': [
|
||||
('independent', 'Independent', 'independent'),
|
||||
('stratified', 'Stratified', 'stratified'),
|
||||
('ldsampler', 'Low discrepancy', 'ldsampler')
|
||||
],
|
||||
'save_in_preset': True
|
||||
},
|
||||
{
|
||||
'type': 'int',
|
||||
'attr': 'sampleCount',
|
||||
'name': 'Pixel samples',
|
||||
'description': 'Number of samples to use for estimating the illumination at each pixel',
|
||||
'default': 8,
|
||||
'min': 1,
|
||||
'max': 10240,
|
||||
'save_in_preset': True
|
||||
}
|
||||
]
|
||||
|
|
@ -16,26 +16,120 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
import bpy, copy
|
||||
from properties_material import MaterialButtonsPanel
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
from mitsuba.outputs import MtsLog
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
material_cache = {}
|
||||
cached_spp = None
|
||||
cached_depth = None
|
||||
|
||||
class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
MTS_PROPS = ['type']
|
||||
|
||||
def draw(self, context):
|
||||
if not hasattr(context, 'material'):
|
||||
return
|
||||
global material_cache
|
||||
mat = context.material
|
||||
if mat.name in material_cache:
|
||||
mat_cached = material_cache[mat.name]
|
||||
else:
|
||||
mat_cached = {}
|
||||
material_cache[mat.name] = mat_cached
|
||||
|
||||
mat = self.get_contents(mat)
|
||||
repaint = False
|
||||
for prop in self.MTS_PROPS:
|
||||
prop_value = getattr(mat, prop)
|
||||
prop_cache_value = mat_cached[prop] if prop in mat_cached else None
|
||||
if prop_cache_value != prop_value:
|
||||
mat_cached[prop] = copy.copy(prop_value)
|
||||
repaint = True
|
||||
if repaint:
|
||||
# Cause a repaint
|
||||
MtsLog("Forcing a repaint")
|
||||
context.material.preview_render_type = context.material.preview_render_type
|
||||
return super().draw(context)
|
||||
|
||||
def get_contents(self, mat):
|
||||
return mat.mitsuba_material
|
||||
|
||||
class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
MTS_COMPAT = set()
|
||||
MTS_PROPS = []
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
'''
|
||||
Only show Mitsuba panel if mitsuba_material.material in MTS_COMPAT
|
||||
'''
|
||||
|
||||
if not hasattr(context, 'material'):
|
||||
return False
|
||||
|
||||
return super().poll(context) and context.material.mitsuba_material.type in cls.MTS_COMPAT
|
||||
|
||||
def draw(self, context):
|
||||
if not hasattr(context, 'material'):
|
||||
return
|
||||
mat = context.material
|
||||
sub_type = getattr(bpy.types, 'mitsuba_mat_%s' % mat.mitsuba_material.type)
|
||||
global material_cache
|
||||
if mat.name in material_cache:
|
||||
mat_cached = material_cache[mat.name]
|
||||
else:
|
||||
mat_cached = {}
|
||||
material_cache[mat.name] = mat_cached
|
||||
|
||||
mat = getattr(mat.mitsuba_material, 'mitsuba_mat_%s' %
|
||||
mat.mitsuba_material.type)
|
||||
props = sub_type.get_exportable_properties()
|
||||
|
||||
repaint = False
|
||||
for prop_entry in props:
|
||||
prop = prop_entry['attr']
|
||||
prop_value = getattr(mat, prop) if hasattr(mat, prop) else None
|
||||
prop_cache_value = mat_cached[prop] if prop in mat_cached else None
|
||||
if prop_cache_value != prop_value:
|
||||
mat_cached[prop] = copy.copy(prop_value)
|
||||
repaint = True
|
||||
if repaint:
|
||||
# Cause a repaint
|
||||
MtsLog("Forcing a repaint")
|
||||
context.material.preview_render_type = context.material.preview_render_type
|
||||
return super().draw(context)
|
||||
|
||||
class MATERIAL_PT_preview_mts(MaterialButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Preview"
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
|
||||
def draw(self, context):
|
||||
if not hasattr(context, 'material'):
|
||||
return
|
||||
self.layout.template_preview(context.material)
|
||||
engine = context.scene.mitsuba_engine
|
||||
row = self.layout.row(True)
|
||||
row.prop(engine, "preview_depth")
|
||||
row.prop(engine, "preview_spp")
|
||||
|
||||
global cached_depth
|
||||
global cached_spp
|
||||
if engine.preview_depth != cached_depth or engine.preview_spp != cached_spp:
|
||||
actualChange = cached_depth != None
|
||||
cached_depth = engine.preview_depth
|
||||
cached_spp = engine.preview_spp
|
||||
if actualChange:
|
||||
MtsLog("Forcing a repaint")
|
||||
context.material.preview_render_type = context.material.preview_render_type
|
||||
efutil.write_config_value('mitsuba', 'defaults', 'preview_spp', str(cached_spp))
|
||||
efutil.write_config_value('mitsuba', 'defaults', 'preview_depth', str(cached_depth))
|
||||
|
||||
|
||||
class MATERIAL_PT_context_material_mts(MaterialButtonsPanel, bpy.types.Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
|
|
@ -25,7 +25,7 @@ class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
|
|||
bl_label = 'Mitsuba Composite Material'
|
||||
|
||||
MTS_COMPAT = {'composite'}
|
||||
|
||||
|
||||
display_property_groups = [
|
||||
( ('material', 'mitsuba_material'), 'mitsuba_mat_composite' )
|
||||
]
|
||||
|
|
|
@ -28,13 +28,16 @@ class emission(mitsuba_material_base, bpy.types.Panel):
|
|||
|
||||
bl_label = 'Mitsuba Material Emission'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
MTS_PROPS = ['color', 'intensity', 'samplingWeight', 'use_emission']
|
||||
|
||||
display_property_groups = [
|
||||
( ('material',), 'mitsuba_emission' )
|
||||
]
|
||||
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = active_node_mat(context.material)
|
||||
def get_contents(self, mat):
|
||||
return mat.mitsuba_emission
|
||||
|
||||
self.layout.prop(mat.mitsuba_emission, "use_emission", text="")
|
||||
def draw_header(self, context):
|
||||
if hasattr(context, "material"):
|
||||
mat = active_node_mat(context.material)
|
||||
self.layout.prop(mat.mitsuba_emission, "use_emission", text="")
|
||||
|
|
|
@ -24,7 +24,7 @@ class ui_material_phong(mitsuba_material_sub, bpy.types.Panel):
|
|||
bl_label = 'Mitsuba Phong Material'
|
||||
|
||||
MTS_COMPAT = {'phong'}
|
||||
|
||||
|
||||
display_property_groups = [
|
||||
( ('material', 'mitsuba_material'), 'mitsuba_mat_phong' )
|
||||
]
|
||||
|
|
|
@ -20,6 +20,9 @@ import bpy
|
|||
from properties_render import RenderButtonsPanel
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
cached_binary_path = None
|
||||
|
||||
class render_described_context(RenderButtonsPanel, property_group_renderer):
|
||||
'''
|
||||
|
@ -28,7 +31,6 @@ class render_described_context(RenderButtonsPanel, property_group_renderer):
|
|||
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
|
||||
|
||||
class setup_preset(render_described_context, bpy.types.Panel):
|
||||
'''
|
||||
Engine settings presets UI Panel
|
||||
|
@ -41,7 +43,7 @@ class setup_preset(render_described_context, bpy.types.Panel):
|
|||
row.menu("MITSUBA_MT_presets_engine", text=bpy.types.MITSUBA_MT_presets_engine.bl_label)
|
||||
row.operator("mitsuba.preset_engine_add", text="", icon="ZOOMIN")
|
||||
row.operator("mitsuba.preset_engine_add", text="", icon="ZOOMOUT").remove_active = True
|
||||
|
||||
|
||||
super().draw(context)
|
||||
|
||||
class engine(render_described_context, bpy.types.Panel):
|
||||
|
@ -49,9 +51,42 @@ class engine(render_described_context, bpy.types.Panel):
|
|||
Engine settings UI Panel
|
||||
'''
|
||||
|
||||
bl_label = 'Mitsuba Engine Configuration'
|
||||
bl_label = 'Mitsuba Engine Settings'
|
||||
|
||||
display_property_groups = [
|
||||
( ('scene',), 'mitsuba_engine' )
|
||||
]
|
||||
|
||||
def draw(self, context):
|
||||
global cached_binary_path
|
||||
binary_path = context.scene.mitsuba_engine.binary_path
|
||||
if binary_path != "" and cached_binary_path != binary_path:
|
||||
binary_path = efutil.filesystem_path(binary_path)
|
||||
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', binary_path)
|
||||
context.scene.mitsuba_engine.binary_path = binary_path
|
||||
cached_binary_path = binary_path
|
||||
super().draw(context)
|
||||
|
||||
class integrator(render_described_context, bpy.types.Panel):
|
||||
'''
|
||||
Integrator settings UI Panel
|
||||
'''
|
||||
|
||||
bl_label = 'Mitsuba Integrator Settings'
|
||||
|
||||
display_property_groups = [
|
||||
( ('scene',), 'mitsuba_integrator' )
|
||||
]
|
||||
|
||||
|
||||
class sampler(render_described_context, bpy.types.Panel):
|
||||
'''
|
||||
Sampler settings UI Panel
|
||||
'''
|
||||
|
||||
bl_label = 'Mitsuba Sampler Settings'
|
||||
|
||||
display_property_groups = [
|
||||
( ('scene',), 'mitsuba_sampler' )
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in New Issue