465 lines
16 KiB
C++
465 lines
16 KiB
C++
/*
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License Version 3
|
|
as published by the Free Software Foundation.
|
|
|
|
Mitsuba is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <mitsuba/render/preview.h>
|
|
#include <mitsuba/render/triaccel.h>
|
|
#include <mitsuba/render/rectwu.h>
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
void PreviewWorker::serialize(Stream *stream, InstanceManager *manager) const {
|
|
Log(EError, "Serialization is not supported!");
|
|
}
|
|
|
|
ref<WorkUnit> PreviewWorker::createWorkUnit() const {
|
|
return new RectangularWorkUnit();
|
|
}
|
|
|
|
ref<WorkResult> PreviewWorker::createWorkResult() const {
|
|
/* Only pixel data, nothing else */
|
|
return new ImageBlock(Vector2i(m_blockSize, m_blockSize),
|
|
0, false, false, false, false);
|
|
}
|
|
|
|
void PreviewWorker::prepare() {
|
|
m_scene = static_cast<Scene *>(getResource("scene"));
|
|
m_kdtree = m_scene->getKDTree();
|
|
m_shapes = &m_kdtree->getShapes();
|
|
}
|
|
|
|
void PreviewWorker::process(const WorkUnit *workUnit, WorkResult *workResult,
|
|
const bool &stop) {
|
|
if (m_coherent)
|
|
processCoherent(workUnit, workResult, stop);
|
|
else
|
|
processIncoherent(workUnit, workResult, stop);
|
|
}
|
|
|
|
void PreviewWorker::processIncoherent(const WorkUnit *workUnit, WorkResult *workResult,
|
|
const bool &stop) {
|
|
const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit);
|
|
ImageBlock *block = static_cast<ImageBlock *>(workResult);
|
|
|
|
block->setOffset(rect->getOffset());
|
|
block->setSize(rect->getSize());
|
|
|
|
const int sx = rect->getOffset().x, sy = block->getOffset().y;
|
|
const int ex = sx + rect->getSize().x, ey = sy + rect->getSize().y;
|
|
|
|
/* Some local variables */
|
|
int pos = 0;
|
|
Intersection its;
|
|
Spectrum value, bsdfVal;
|
|
Vector toVPL;
|
|
Ray primary, secondary;
|
|
int numRays = 0;
|
|
float shutterOpen = m_scene->getCamera()->getShutterOpen();
|
|
|
|
for (int y=sy; y<ey; ++y) {
|
|
for (int x=sx; x<ex; ++x) {
|
|
/* Generate a camera ray without normalization */
|
|
primary = Ray(m_cameraO, m_cameraTL
|
|
+ m_cameraDx * (Float) x
|
|
+ m_cameraDy * (Float) y, shutterOpen);
|
|
|
|
++numRays;
|
|
if (!m_kdtree->rayIntersect(primary, its)) {
|
|
block->setPixel(pos++, m_scene->LeBackground(primary));
|
|
continue;
|
|
}
|
|
|
|
if (its.shape->isLuminaire())
|
|
value = its.Le(-primary.d);
|
|
else
|
|
value = Spectrum(0.0f);
|
|
|
|
toVPL = m_vpl.its.p - its.p;
|
|
secondary = Ray(its.p, toVPL, ShadowEpsilon, 1-ShadowEpsilon, shutterOpen);
|
|
++numRays;
|
|
if (m_kdtree->rayIntersect(secondary)) {
|
|
block->setPixel(pos++, value);
|
|
continue;
|
|
}
|
|
Float length = toVPL.length();
|
|
toVPL/=length;
|
|
|
|
BSDFQueryRecord rr(its, its.toLocal(toVPL));
|
|
rr.wi = normalize(rr.wi);
|
|
bsdfVal = its.shape->getBSDF()->fCos(rr);
|
|
length = std::max(length, m_minDist);
|
|
|
|
if (m_vpl.type == ESurfaceVPL) {
|
|
BSDFQueryRecord bRec(m_vpl.its, -m_vpl.its.toLocal(toVPL));
|
|
bRec.quantity = EImportance;
|
|
value += m_vpl.P * bsdfVal * m_vpl.its.shape->getBSDF()->fCos(bRec) / (length*length);
|
|
} else {
|
|
EmissionRecord eRec(m_vpl.luminaire,
|
|
ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), -toVPL);
|
|
eRec.type = EmissionRecord::EPreview;
|
|
value += m_vpl.P * bsdfVal * m_vpl.luminaire->fDirection(eRec)
|
|
* ((m_vpl.luminaire->getType() & Luminaire::EOnSurface ?
|
|
dot(m_vpl.its.shFrame.n, -toVPL) : (Float) 1)
|
|
/ (length*length));
|
|
}
|
|
block->setPixel(pos++, value);
|
|
}
|
|
}
|
|
block->setExtra(numRays);
|
|
}
|
|
|
|
void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workResult,
|
|
const bool &stop) {
|
|
#if defined(MTS_HAS_COHERENT_RT)
|
|
const RectangularWorkUnit *rect = static_cast<const RectangularWorkUnit *>(workUnit);
|
|
ImageBlock *block = static_cast<ImageBlock *>(workResult);
|
|
|
|
block->setOffset(rect->getOffset());
|
|
block->setSize(rect->getSize());
|
|
|
|
/* Some constants */
|
|
const int sx = rect->getOffset().x, sy = block->getOffset().y;
|
|
const int ex = sx + rect->getSize().x, ey = sy + rect->getSize().y;
|
|
const int width = rect->getSize().x;
|
|
const SSEVector MM_ALIGN16 xOffset(0.0f, 1.0f, 0.0f, 1.0f);
|
|
const SSEVector MM_ALIGN16 yOffset(0.0f, 0.0f, 1.0f, 1.0f);
|
|
const int pixelOffset[] = {0, 1, width, width+1};
|
|
const __m128 clamping = _mm_set1_ps(1/(m_minDist*m_minDist));
|
|
uint8_t temp[MTS_KD_INTERSECTION_TEMP*4];
|
|
|
|
const __m128 camTL[3] = {
|
|
_mm_set1_ps(m_cameraTL.x),
|
|
_mm_set1_ps(m_cameraTL.y),
|
|
_mm_set1_ps(m_cameraTL.z)
|
|
};
|
|
const __m128 camDx[3] = {
|
|
_mm_set1_ps(m_cameraDx.x),
|
|
_mm_set1_ps(m_cameraDx.y),
|
|
_mm_set1_ps(m_cameraDx.z)
|
|
};
|
|
const __m128 camDy[3] = {
|
|
_mm_set1_ps(m_cameraDy.x),
|
|
_mm_set1_ps(m_cameraDy.y),
|
|
_mm_set1_ps(m_cameraDy.z)
|
|
};
|
|
const __m128 lumPos[3] = {
|
|
_mm_set1_ps(m_vpl.its.p.x),
|
|
_mm_set1_ps(m_vpl.its.p.y),
|
|
_mm_set1_ps(m_vpl.its.p.z)
|
|
};
|
|
const __m128 lumDir[3] = {
|
|
_mm_set1_ps(m_vpl.its.shFrame.n.x),
|
|
_mm_set1_ps(m_vpl.its.shFrame.n.y),
|
|
_mm_set1_ps(m_vpl.its.shFrame.n.z)
|
|
};
|
|
|
|
/* Some local variables */
|
|
int pos = 0;
|
|
int numRays = 0;
|
|
RayPacket4 MM_ALIGN16 primRay4, secRay4;
|
|
Intersection4 MM_ALIGN16 its4, secIts4;
|
|
RayInterval4 MM_ALIGN16 itv4, secItv4;
|
|
SSEVector MM_ALIGN16 nSecD[3], cosThetaLight, invLengthSquared;
|
|
Spectrum emitted[4], direct[4];
|
|
Intersection its;
|
|
Vector wo, wi;
|
|
its.hasUVPartials = false;
|
|
|
|
bool diffuseVPL = false, vplOnSurface = false;
|
|
Spectrum vplWeight;
|
|
|
|
if (m_vpl.type == ESurfaceVPL && (m_diffuseSources || m_vpl.its.shape->getBSDF()->getType() == BSDF::EDiffuseReflection)) {
|
|
diffuseVPL = true;
|
|
vplOnSurface = true;
|
|
vplWeight = m_vpl.its.shape->getBSDF()->getDiffuseReflectance(m_vpl.its) * m_vpl.P / M_PI;
|
|
} else if (m_vpl.type == ELuminaireVPL) {
|
|
vplOnSurface = m_vpl.luminaire->getType() & Luminaire::EOnSurface;
|
|
diffuseVPL = m_vpl.luminaire->getType() & Luminaire::EDiffuseDirection;
|
|
EmissionRecord eRec(m_vpl.luminaire,
|
|
ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), m_vpl.its.shFrame.n);
|
|
vplWeight = m_vpl.P * m_vpl.luminaire->fDirection(eRec);
|
|
}
|
|
|
|
primRay4.o[0].ps = _mm_set1_ps(m_cameraO.x);
|
|
primRay4.o[1].ps = _mm_set1_ps(m_cameraO.y);
|
|
primRay4.o[2].ps = _mm_set1_ps(m_cameraO.z);
|
|
secItv4.mint.ps = _mm_set1_ps(ShadowEpsilon);
|
|
|
|
/* Work on 2x2 sub-blocks */
|
|
for (int y=sy; y<ey; y += 2, pos += width) {
|
|
for (int x=sx; x<ex; x += 2, pos += 2) {
|
|
/* Generate camera rays without normalization */
|
|
const __m128
|
|
xPixel = _mm_add_ps(xOffset.ps, _mm_set1_ps((float) x)),
|
|
yPixel = _mm_add_ps(yOffset.ps, _mm_set1_ps((float) y));
|
|
|
|
primRay4.d[0].ps = _mm_add_ps(camTL[0], _mm_add_ps(
|
|
_mm_mul_ps(xPixel, camDx[0]), _mm_mul_ps(yPixel, camDy[0])));
|
|
primRay4.d[1].ps = _mm_add_ps(camTL[1], _mm_add_ps(
|
|
_mm_mul_ps(xPixel, camDx[1]), _mm_mul_ps(yPixel, camDy[1])));
|
|
primRay4.d[2].ps = _mm_add_ps(camTL[2], _mm_add_ps(
|
|
_mm_mul_ps(xPixel, camDx[2]), _mm_mul_ps(yPixel, camDy[2])));
|
|
|
|
primRay4.dRcp[0].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[0].ps);
|
|
primRay4.dRcp[1].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[1].ps);
|
|
primRay4.dRcp[2].ps = _mm_div_ps(SSEConstants::one.ps, primRay4.d[2].ps);
|
|
|
|
/* Ray coherence test */
|
|
const int primSignsX = _mm_movemask_ps(primRay4.d[0].ps);
|
|
const int primSignsY = _mm_movemask_ps(primRay4.d[1].ps);
|
|
const int primSignsZ = _mm_movemask_ps(primRay4.d[2].ps);
|
|
|
|
const bool primCoherent =
|
|
(primSignsX == 0 || primSignsX == 0xF)
|
|
&& (primSignsY == 0 || primSignsY == 0xF)
|
|
&& (primSignsZ == 0 || primSignsZ == 0xF);
|
|
|
|
/* Trace the primary rays */
|
|
its4.t = SSEConstants::p_inf;
|
|
if (EXPECT_TAKEN(primCoherent)) {
|
|
primRay4.signs[0][0] = primSignsX ? 1 : 0;
|
|
primRay4.signs[1][0] = primSignsY ? 1 : 0;
|
|
primRay4.signs[2][0] = primSignsZ ? 1 : 0;
|
|
m_kdtree->rayIntersectPacket(primRay4, itv4, its4, temp);
|
|
} else {
|
|
m_kdtree->rayIntersectPacketIncoherent(primRay4, itv4, its4, temp);
|
|
}
|
|
numRays += 4;
|
|
|
|
/* Generate secondary rays */
|
|
secRay4.o[0].ps = _mm_add_ps(primRay4.o[0].ps, _mm_mul_ps(its4.t.ps, primRay4.d[0].ps));
|
|
secRay4.o[1].ps = _mm_add_ps(primRay4.o[1].ps, _mm_mul_ps(its4.t.ps, primRay4.d[1].ps));
|
|
secRay4.o[2].ps = _mm_add_ps(primRay4.o[2].ps, _mm_mul_ps(its4.t.ps, primRay4.d[2].ps));
|
|
secRay4.d[0].ps = _mm_sub_ps(lumPos[0], secRay4.o[0].ps);
|
|
secRay4.d[1].ps = _mm_sub_ps(lumPos[1], secRay4.o[1].ps);
|
|
secRay4.d[2].ps = _mm_sub_ps(lumPos[2], secRay4.o[2].ps);
|
|
|
|
/* Normalization */
|
|
const __m128
|
|
lengthSquared = _mm_add_ps(_mm_add_ps(
|
|
_mm_mul_ps(secRay4.d[0].ps, secRay4.d[0].ps),
|
|
_mm_mul_ps(secRay4.d[1].ps, secRay4.d[1].ps)),
|
|
_mm_mul_ps(secRay4.d[2].ps, secRay4.d[2].ps)),
|
|
invLength = _mm_rsqrt_ps(lengthSquared);
|
|
|
|
invLengthSquared.ps = _mm_min_ps(_mm_rcp_ps(lengthSquared), clamping);
|
|
|
|
nSecD[0].ps = _mm_mul_ps(secRay4.d[0].ps, invLength);
|
|
nSecD[1].ps = _mm_mul_ps(secRay4.d[1].ps, invLength);
|
|
nSecD[2].ps = _mm_mul_ps(secRay4.d[2].ps, invLength);
|
|
|
|
secRay4.dRcp[0].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[0].ps);
|
|
secRay4.dRcp[1].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[1].ps);
|
|
secRay4.dRcp[2].ps = _mm_div_ps(SSEConstants::one.ps, secRay4.d[2].ps);
|
|
|
|
cosThetaLight.ps = _mm_sub_ps(_mm_setzero_ps(),
|
|
_mm_add_ps(_mm_add_ps(
|
|
_mm_mul_ps(nSecD[0].ps, lumDir[0]),
|
|
_mm_mul_ps(nSecD[1].ps, lumDir[1])),
|
|
_mm_mul_ps(nSecD[2].ps, lumDir[2])));
|
|
secItv4.maxt.ps = _mm_set1_ps(1-ShadowEpsilon);
|
|
|
|
/* Shading (scalar) --- this is way too much work and should be
|
|
rewritten to be smarter in special cases */
|
|
for (int idx=0; idx<4; ++idx) {
|
|
if (EXPECT_NOT_TAKEN(its4.t.f[idx] == std::numeric_limits<float>::infinity())) {
|
|
/* Don't trace a secondary ray */
|
|
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]),
|
|
0.0f
|
|
));
|
|
memset(&direct[idx], 0, sizeof(Spectrum));
|
|
continue;
|
|
}
|
|
const unsigned int primIndex = its4.primIndex.i[idx];
|
|
const Shape *shape = (*m_shapes)[its4.shapeIndex.i[idx]];
|
|
const BSDF *bsdf = shape->getBSDF();
|
|
|
|
if (EXPECT_NOT_TAKEN(!bsdf)) {
|
|
memset(&emitted[idx], 0, sizeof(Spectrum));
|
|
memset(&direct[idx], 0, sizeof(Spectrum));
|
|
continue;
|
|
}
|
|
|
|
if (EXPECT_TAKEN(primIndex != KNoTriangleFlag)) {
|
|
const TriMesh *mesh = static_cast<const TriMesh *>(shape);
|
|
const Triangle &t = mesh->getTriangles()[primIndex];
|
|
const Normal *normals = mesh->getVertexNormals();
|
|
const Point2 *texcoords = mesh->getVertexTexcoords();
|
|
const Spectrum *colors = mesh->getVertexColors();
|
|
const TangentSpace * tangents = mesh->getVertexTangents();
|
|
const Float beta = its4.u.f[idx],
|
|
gamma = its4.v.f[idx],
|
|
alpha = 1.0f - beta - gamma;
|
|
const uint32_t idx0 = t.idx[0], idx1 = t.idx[1], idx2 = t.idx[2];
|
|
|
|
if (EXPECT_TAKEN(normals)) {
|
|
const Normal &n0 = normals[idx0],
|
|
&n1 = normals[idx1],
|
|
&n2 = normals[idx2];
|
|
its.shFrame.n = normalize(n0 * alpha + n1 * beta + n2 * gamma);
|
|
} else {
|
|
const Point *positions = mesh->getVertexPositions();
|
|
const Point &p0 = positions[idx0],
|
|
&p1 = positions[idx1],
|
|
&p2 = positions[idx2];
|
|
Vector sideA = p1 - p0, sideB = p2 - p0;
|
|
Vector n = cross(sideA, sideB);
|
|
Float nLengthSqr = n.lengthSquared();
|
|
if (nLengthSqr != 0)
|
|
n /= std::sqrt(nLengthSqr);
|
|
its.shFrame.n = Normal(n);
|
|
}
|
|
|
|
if (EXPECT_TAKEN(texcoords)) {
|
|
const Point2 &t0 = texcoords[idx0],
|
|
&t1 = texcoords[idx1],
|
|
&t2 = texcoords[idx2];
|
|
its.uv = t0 * alpha + t1 * beta + t2 * gamma;
|
|
} else {
|
|
its.uv = Point2(0.0f);
|
|
}
|
|
|
|
if (EXPECT_NOT_TAKEN(colors)) {
|
|
const Spectrum &c0 = colors[idx0],
|
|
&c1 = colors[idx1],
|
|
&c2 = colors[idx2];
|
|
its.color = c0 * alpha + c1 * beta + c2 * gamma;
|
|
}
|
|
|
|
if (EXPECT_NOT_TAKEN(tangents)) {
|
|
const TangentSpace &t0 = tangents[idx0],
|
|
&t1 = tangents[idx1],
|
|
&t2 = tangents[idx2];
|
|
its.dpdu = t0.dpdu * alpha + t1.dpdu * beta + t2.dpdu * gamma;
|
|
its.dpdv = t0.dpdv * alpha + t1.dpdv * beta + t2.dpdv * gamma;
|
|
}
|
|
} 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]),
|
|
0.0f
|
|
);
|
|
its.t = its4.t.f[idx];
|
|
shape->fillIntersectionRecord(ray, temp + idx * MTS_KD_INTERSECTION_TEMP + 8, its);
|
|
bsdf = its.shape->getBSDF();
|
|
}
|
|
|
|
wo.x = nSecD[0].f[idx]; wo.y = nSecD[1].f[idx]; wo.z = nSecD[2].f[idx];
|
|
|
|
if (EXPECT_TAKEN(!shape->isLuminaire())) {
|
|
memset(&emitted[idx], 0, sizeof(Spectrum));
|
|
} else {
|
|
Vector d(-primRay4.d[0].f[idx], -primRay4.d[1].f[idx], -primRay4.d[2].f[idx]);
|
|
emitted[idx] = shape->getLuminaire()->Le(ShapeSamplingRecord(its.p, its.shFrame.n), d);
|
|
}
|
|
|
|
if (EXPECT_TAKEN(bsdf->getType() == BSDF::EDiffuseReflection && diffuseVPL)) {
|
|
/* Fast path */
|
|
direct[idx] = (bsdf->getDiffuseReflectance(its) * vplWeight)
|
|
* (std::max((Float) 0.0f, dot(wo, its.shFrame.n))
|
|
* (vplOnSurface ? (std::max(cosThetaLight.f[idx], (Float) 0.0f) * INV_PI) : INV_PI)
|
|
* invLengthSquared.f[idx]);
|
|
} else {
|
|
wi.x = -primRay4.d[0].f[idx];
|
|
wi.y = -primRay4.d[1].f[idx];
|
|
wi.z = -primRay4.d[2].f[idx];
|
|
its.p.x = secRay4.o[0].f[idx];
|
|
its.p.y = secRay4.o[1].f[idx];
|
|
its.p.z = secRay4.o[2].f[idx];
|
|
if (EXPECT_NOT_TAKEN(bsdf->getType() & BSDF::EAnisotropicMaterial)) {
|
|
its.shFrame.s = normalize(its.dpdu - its.shFrame.n
|
|
* dot(its.shFrame.n, its.dpdu));
|
|
its.shFrame.t = cross(its.shFrame.n, its.shFrame.s);
|
|
} else {
|
|
coordinateSystem(its.shFrame.n, its.shFrame.s, its.shFrame.t);
|
|
}
|
|
const Float ctLight = cosThetaLight.f[idx];
|
|
wi = normalize(wi);
|
|
|
|
its.wi = its.toLocal(wi);
|
|
wo = its.toLocal(wo);
|
|
|
|
if (!diffuseVPL) {
|
|
if (m_vpl.type == ESurfaceVPL) {
|
|
BSDFQueryRecord bRec(m_vpl.its, m_vpl.its.toLocal(wi));
|
|
bRec.quantity = EImportance;
|
|
vplWeight = m_vpl.its.shape->getBSDF()->fCos(bRec) * m_vpl.P;
|
|
} else {
|
|
EmissionRecord eRec(m_vpl.luminaire,
|
|
ShapeSamplingRecord(m_vpl.its.p, m_vpl.its.shFrame.n), wi);
|
|
eRec.type = EmissionRecord::EPreview;
|
|
vplWeight = m_vpl.luminaire->fDirection(eRec) * m_vpl.P;
|
|
}
|
|
}
|
|
|
|
if (EXPECT_TAKEN(ctLight >= 0)) {
|
|
direct[idx] = (bsdf->fCos(BSDFQueryRecord(its, wo)) * vplWeight
|
|
* ((vplOnSurface ? std::max(ctLight, (Float) 0.0f) : 1.0f) * invLengthSquared.f[idx]));
|
|
} else {
|
|
memset(&direct[idx], 0, sizeof(Spectrum));
|
|
}
|
|
}
|
|
++numRays;
|
|
}
|
|
|
|
/* Shoot the secondary rays */
|
|
const int secSignsX = _mm_movemask_ps(secRay4.d[0].ps);
|
|
const int secSignsY = _mm_movemask_ps(secRay4.d[1].ps);
|
|
const int secSignsZ = _mm_movemask_ps(secRay4.d[2].ps);
|
|
|
|
const bool secCoherent =
|
|
(secSignsX == 0 || secSignsX == 0xF)
|
|
&& (secSignsY == 0 || secSignsY == 0xF)
|
|
&& (secSignsZ == 0 || secSignsZ == 0xF);
|
|
|
|
/* Shoot the secondary rays */
|
|
secIts4.t = SSEConstants::p_inf;
|
|
if (EXPECT_TAKEN(secCoherent)) {
|
|
secRay4.signs[0][0] = secSignsX ? 1 : 0;
|
|
secRay4.signs[1][0] = secSignsY ? 1 : 0;
|
|
secRay4.signs[2][0] = secSignsZ ? 1 : 0;
|
|
m_kdtree->rayIntersectPacket(secRay4, secItv4, secIts4, temp);
|
|
} else {
|
|
m_kdtree->rayIntersectPacketIncoherent(secRay4, secItv4, secIts4, temp);
|
|
}
|
|
|
|
for (int idx=0; idx<4; ++idx) {
|
|
if (EXPECT_TAKEN(secIts4.t.f[idx] == std::numeric_limits<float>::infinity()))
|
|
block->setPixel(pos+pixelOffset[idx], direct[idx]+emitted[idx]);
|
|
else
|
|
block->setPixel(pos+pixelOffset[idx], emitted[idx]);
|
|
}
|
|
}
|
|
}
|
|
block->setExtra(numRays);
|
|
#else
|
|
Log(EError, "Coherent raytracing support was not compiled into this binary!");
|
|
#endif
|
|
}
|
|
|
|
ref<WorkProcessor> PreviewWorker::clone() const {
|
|
return new PreviewWorker(m_blockSize, m_cameraO, m_cameraTL,
|
|
m_cameraDx, m_cameraDy, m_vpl, m_minDist, m_coherent,
|
|
m_diffuseSources, m_diffuseReceivers);
|
|
}
|
|
|
|
MTS_IMPLEMENT_CLASS(PreviewWorker, false, WorkProcessor)
|
|
MTS_NAMESPACE_END
|