float *renderBlock(const Vector3i &blockIdx) const { float *result = new float[m_blockRes*m_blockRes*m_blockRes]; Point offset = m_aabb.min + Vector( blockIdx.x * m_blockSize * m_voxelWidth, blockIdx.y * m_blockSize * m_voxelWidth, blockIdx.z * m_blockSize * m_voxelWidth); int idx = 0; bool nonempty = false; for (int z = 0; z<m_blockRes; ++z) { for (int y = 0; y<m_blockRes; ++y) { for (int x = 0; x<m_blockRes; ++x) { Point p = offset + Vector((Float) x, (Float) y, (Float) z) * m_voxelWidth; float value = (float) m_nested->lookupFloat(p); result[idx++] = value; nonempty |= (value != 0); } } } ++statsCreate; statsEmpty.incrementBase(); if (nonempty) { return result; } else { ++statsEmpty; delete[] result; return NULL; } }
void VPLShaderManager::drawAllGeometryForVPL(const VPL &vpl, const Sensor *sensor) { const Emitter *currentEmitter = NULL; const BSDF *currentBSDF = NULL; bool currentHasNormals = false; m_renderer->setDepthTest(true); Matrix4x4 currentObjTrafo; currentObjTrafo.setIdentity(); m_shadowMap->bind(0); m_renderer->beginDrawingMeshes(); size_t nTriangles = 0; for (std::vector<Renderer::TransformedGPUGeometry>::const_iterator it = m_geometry.begin(); it != m_geometry.end(); ++it) { const GPUGeometry *geo = (*it).first; const Matrix4x4 &trafo = (*it).second; const BSDF *bsdf = geo->getTriMesh()->getBSDF(); const Emitter *emitter = geo->getTriMesh()->getEmitter(); bool hasNormals = !geo->getTriMesh()->hasVertexNormals(); nTriangles += geo->getTriMesh()->getTriangleCount(); if (emitter != currentEmitter || bsdf != currentBSDF || hasNormals != currentHasNormals) { currentBSDF = bsdf; currentEmitter = emitter; currentHasNormals = hasNormals; if (m_currentProgram.program) { m_currentProgram.program->unbind(); m_currentProgram.program = NULL; m_targetConfiguration.unbind(); } bind(vpl, bsdf, sensor, emitter, trafo, hasNormals); currentObjTrafo = trafo; } else if (trafo != currentObjTrafo) { if (m_currentProgram.program) m_currentProgram.program->setParameter( m_currentProgram.param_instanceTransform, trafo); currentObjTrafo = trafo; } if (m_alpha != 1.0f && sampleTEAFloat((uint32_t) (it - m_geometry.begin()), m_vplIndex, 8) > m_alpha) continue; m_renderer->drawMesh(geo); } statsMaxTriangles.recordMaximum(nTriangles); m_renderer->endDrawingMeshes(); unbind(); m_renderer->checkError(); }
// GridAccel Method Definitions GridAccel::GridAccel(const vector<Reference<Primitive> > &p, bool forRefined, bool refineImmediately) : gridForRefined(forRefined) { // Initialize _prims_ with primitives for grid vector<Reference<Primitive> > prims; if (refineImmediately) for (u_int i = 0; i < p.size(); ++i) p[i]->FullyRefine(prims); else prims = p; // Initialize mailboxes for grid nMailboxes = prims.size(); mailboxes = (MailboxPrim *)AllocAligned(nMailboxes * sizeof(MailboxPrim)); for (u_int i = 0; i < nMailboxes; ++i) new (&mailboxes[i]) MailboxPrim(prims[i]); // Compute bounds and choose grid resolution for (u_int i = 0; i < prims.size(); ++i) bounds = Union(bounds, prims[i]->WorldBound()); Vector delta = bounds.pMax - bounds.pMin; // Find _voxelsPerUnitDist_ for grid int maxAxis = bounds.MaximumExtent(); float invMaxWidth = 1.f / delta[maxAxis]; Assert(invMaxWidth > 0.f); // NOBOOK float cubeRoot = 3.f * powf(float(prims.size()), 1.f/3.f); float voxelsPerUnitDist = cubeRoot * invMaxWidth; for (int axis = 0; axis < 3; ++axis) { NVoxels[axis] = Round2Int(delta[axis] * voxelsPerUnitDist); NVoxels[axis] = Clamp(NVoxels[axis], 1, 64); } // Compute voxel widths and allocate voxels for (int axis = 0; axis < 3; ++axis) { Width[axis] = delta[axis] / NVoxels[axis]; InvWidth[axis] = (Width[axis] == 0.f) ? 0.f : 1.f / Width[axis]; } int nVoxels = NVoxels[0] * NVoxels[1] * NVoxels[2]; voxels = (Voxel **)AllocAligned(nVoxels * sizeof(Voxel *)); memset(voxels, 0, nVoxels * sizeof(Voxel *)); // Add primitives to grid voxels for (u_int i = 0; i < prims.size(); ++i) { // Find voxel extent of primitive BBox pb = prims[i]->WorldBound(); int vmin[3], vmax[3]; for (int axis = 0; axis < 3; ++axis) { vmin[axis] = PosToVoxel(pb.pMin, axis); vmax[axis] = PosToVoxel(pb.pMax, axis); } // Add primitive to overlapping voxels for (int z = vmin[2]; z <= vmax[2]; ++z) for (int y = vmin[1]; y <= vmax[1]; ++y) for (int x = vmin[0]; x <= vmax[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) { // Allocate new voxel and store primitive in it voxels[offset] = new (voxelArena) Voxel(&mailboxes[i]); } else { // Add primitive to already-allocated voxel voxels[offset]->AddPrimitive(&mailboxes[i]); } } static StatsRatio nPrimitiveVoxels("Grid Accelerator", // NOBOOK "Voxels covered vs # / primitives"); // NOBOOK nPrimitiveVoxels.Add((1 + vmax[0]-vmin[0]) * (1 + vmax[1]-vmin[1]) * // NOBOOK (1 + vmax[2]-vmin[2]), 1); // NOBOOK } // Update grid statistics static StatsPercentage nEmptyVoxels("Grid Accelerator", "Empty voxels"); static StatsRatio avgPrimsInVoxel("Grid Accelerator", "Average # of primitives in voxel"); static StatsCounter maxPrimsInVoxel("Grid Accelerator", "Max # of primitives in a grid voxel"); nEmptyVoxels.Add(0, NVoxels[0] * NVoxels[1] * NVoxels[2]); avgPrimsInVoxel.Add(0,NVoxels[0] * NVoxels[1] * NVoxels[2]); for (int z = 0; z < NVoxels[2]; ++z) for (int y = 0; y < NVoxels[1]; ++y) for (int x = 0; x < NVoxels[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) nEmptyVoxels.Add(1, 0); else { int nPrims = voxels[offset]->nPrimitives; maxPrimsInVoxel.Max(nPrims); avgPrimsInVoxel.Add(nPrims, 0); } } }
void PBRT_KDTREE_CREATED_LEAF(int nprims, int depth) { ++kdTreeLeafNodes; kdTreeMaxPrims.Max(nprims); kdTreeMaxDepth.Max(depth); }
bool CausticPerturbation::sampleMutation( Path &source, Path &proposal, MutationRecord &muRec) { int k = source.length(), m = k - 1, l = m - 1; if (k < 4 || !source.vertex(l)->isConnectable()) return false; --l; while (l >= 0 && !source.vertex(l)->isConnectable()) --l; if (l < 1) return false; muRec = MutationRecord(ECausticPerturbation, l, m, m-l, source.getPrefixSuffixWeight(l, m)); statsAccepted.incrementBase(); statsGenerated.incrementBase(); /* Heuristic perturbation size computation (Veach, p.354) */ Float lengthE = source.edge(m-1)->length; Float lengthL = 0; for (int i=l; i<m-1; ++i) lengthL += source.edge(i)->length; Float factor = lengthE/lengthL, theta1 = m_theta1 * factor, theta2 = m_theta2 * factor; Vector woSource = normalize(source.vertex(l+1)->getPosition() - source.vertex(l)->getPosition()); Float phi = m_sampler->next1D() * 2 * M_PI; Float theta = theta2 * math::fastexp(m_logRatio * m_sampler->next1D()); Vector wo = Frame(woSource).toWorld(sphericalDirection(theta, phi)); /* Allocate memory for the proposed path */ proposal.clear(); proposal.append(source, 0, l+1); proposal.append(m_pool.allocEdge()); for (int i=l+1; i<m; ++i) { proposal.append(m_pool.allocVertex()); proposal.append(m_pool.allocEdge()); } proposal.append(source, m, k+1); proposal.vertex(l) = proposal.vertex(l)->clone(m_pool); proposal.vertex(m) = proposal.vertex(m)->clone(m_pool); BDAssert(proposal.vertexCount() == source.vertexCount()); BDAssert(proposal.edgeCount() == source.edgeCount()); Float dist = source.edge(l)->length + perturbMediumDistance(m_sampler, source.vertex(l+1)); /* Sample a perturbation and propagate it through specular interactions */ if (!proposal.vertex(l)->perturbDirection(m_scene, proposal.vertex(l-1), proposal.edge(l-1), proposal.edge(l), proposal.vertex(l+1), wo, dist, source.vertex(l+1)->getType(), EImportance)) { proposal.release(l, m+1, m_pool); return false; } Vector woProposal = normalize(proposal.vertex(l+1)->getPosition() - source.vertex(l)->getPosition()); theta = unitAngle(woSource, woProposal); if (theta >= theta2 || theta <= theta1) { proposal.release(l, m+1, m_pool); return false; } /* If necessary, propagate the perturbation through a sequence of ideally specular interactions */ for (int i=l+1; i<m-1; ++i) { Float dist = source.edge(i)->length + perturbMediumDistance(m_sampler, source.vertex(i+1)); if (!proposal.vertex(i)->propagatePerturbation(m_scene, proposal.vertex(i-1), proposal.edge(i-1), proposal.edge(i), proposal.vertex(i+1), source.vertex(i)->getComponentType(), dist, source.vertex(i+1)->getType(), EImportance)) { proposal.release(l, m+1, m_pool); return false; } } if (!PathVertex::connect(m_scene, proposal.vertex(m-2), proposal.edge(m-2), proposal.vertex(m-1), proposal.edge(m-1), proposal.vertex(m), proposal.edge(m), proposal.vertex(m+1))) { proposal.release(l, m+1, m_pool); return false; } proposal.vertex(k-1)->updateSamplePosition( proposal.vertex(k-2)); ++statsGenerated; return true; }
bool BidirectionalMutator::sampleMutation( Path &source, Path &proposal, MutationRecord &muRec) { TwoTailedGeoDistr desiredLength(2), deletionLength(2); int k = source.length(); /* Sample the desired path length of the proposal. This is done using a two-tailed geometric distribution that is centered around the current path length, and which respects the specified minimum and maximum length constraints. */ desiredLength.configure(k, m_kmin, m_kmax); int kPrime = desiredLength.sample(m_sampler->next1D()); /* Sample the length of the deletion (in # of edges, 1 means no vertices are removed). When kPrime is smaller than k, we must delete at least k-kPrime+1 edges to be able to achieve the desired path length. When k==kPrime, we must delete *something*, or the mutation is trivial, hence the conditional below expression. */ int minDeletion = std::max((k == kPrime) ? 2 : 1, k-kPrime+1); deletionLength.configure(2, minDeletion, k); int kd = deletionLength.sample(m_sampler->next1D()); /* Based on the desired length, this tells us how many edges need to be added (k' = k - kd + ka) */ int ka = kPrime-k+kd; /* Sample the left endpoint of the deleted range */ int lMin = 0, lMax = k - kd; if (kd == 1 || ka == 1) { /* This will help to avoid certain path changes that would otherwise always be rejected. Specifically, we don't want to remove the sensor or emitter sample vertex, and we don't want to insert vertices between a sensor/emitter sample and its supernode */ lMin++; lMax--; } m_temp.clear(); for (int l=lMin; l<=lMax; ++l) { int m = l+kd; if (!source.vertex(l)->isDegenerate() && !source.vertex(m)->isDegenerate()) m_temp.push_back(l); } if (m_temp.size() == 0) return false; int l = m_temp[std::min((int) (m_temp.size() * m_sampler->next1D()), (int) m_temp.size()-1)]; int m = l+kd; /* Don't try to hit the emitter or sensor if they are degenerate */ int sMin = 0, sMax = ka-1; if (l == 0 && m_scene->hasDegenerateEmitters()) ++sMin; else if (m == k && m_scene->hasDegenerateSensor()) --sMax; /* Sample the number of SIS-type steps to take from the emitter direction */ int s = std::min(sMin + (int) ((sMax-sMin+1) * m_sampler->next1D()), sMax); int t = ka - s - 1; /* Check a few assumptions */ BDAssert(ka >= 1 && kd >= 1 && kd <= k && l >= lMin && l <= lMax && kPrime == k - kd + ka && kPrime >= m_kmin && kPrime <= m_kmax); /* Construct a mutation record */ muRec = MutationRecord(EBidirectionalMutation, l, m, ka, source.getPrefixSuffixWeight(l, m)); /* Keep some statistics */ statsGenerated.incrementBase(); statsAccepted.incrementBase(); proposal.clear(); proposal.append(source, 0, l+1); proposal.vertex(l) = proposal.vertex(l)->clone(m_pool); /* Perform a random walk from the emitter direction */ if (proposal.randomWalk(m_scene, m_sampler, s, -1, EImportance, m_pool) != s) { proposal.release(l, proposal.vertexCount(), m_pool); return false; } /* Perform a random walk from the sensor direction */ m_tempPath.clear(); m_tempPath.append(source, m, k+1, true); m_tempPath.vertex(k-m) = m_tempPath.vertex(k-m)->clone(m_pool); if (m_tempPath.randomWalk(m_scene, m_sampler, t, -1, ERadiance, m_pool) != t) { proposal.release(l, proposal.vertexCount(), m_pool); m_tempPath.release(k-m, m_tempPath.vertexCount(), m_pool); return false; } PathEdge *connectionEdge = m_pool.allocEdge(); proposal.append(connectionEdge); proposal.append(m_tempPath, 0, m_tempPath.vertexCount(), true); BDAssert(proposal.length() == kPrime && proposal.vertexCount() == proposal.edgeCount() + 1); const PathVertex *vsPred = l+s > 0 ? proposal.vertex(l+s-1) : NULL, *vtPred = l+s+2 <= kPrime ? proposal.vertex(l+s+2) : NULL; const PathEdge *vsEdge = l+s > 0 ? proposal.edge(l+s-1) : NULL, *vtEdge = l+s+1 < kPrime ? proposal.edge(l+s+1) : NULL; /* Now try to connect the two subpaths and reject the proposal if there is no throughput */ PathVertex *vs = proposal.vertex(l+s), *vt = proposal.vertex(l+s+1); if (!PathVertex::connect(m_scene, vsPred, vsEdge, vs, connectionEdge, vt, vtEdge, vtPred)) { proposal.release(l, l+ka+1, m_pool); return false; } if (m >= k-1) proposal.vertex(kPrime-1)->updateSamplePosition( proposal.vertex(kPrime-2)); ++statsGenerated; return true; }