Spectrum SubsurfaceOctreeNode::Mo(const BBox &nodeBound, const Point &pt, const DiffusionReflectance &Rd, float maxError) { // Compute $M_\roman{o}$ at node if error is low enough float dw = sumArea / DistanceSquared(pt, p); if (dw < maxError && !nodeBound.Inside(pt)) { PBRT_SUBSURFACE_ADDED_INTERIOR_CONTRIBUTION(const_cast<SubsurfaceOctreeNode *>(this)); return Rd(DistanceSquared(pt, p)) * E * sumArea; } // Otherwise comupte $M_\roman{o}$ from points in leaf or recursively visit children Spectrum Mo = 0.f; if (isLeaf) { // Accumulate $M_\roman{o}$ from leaf node for (int i = 0; i < 8; ++i) { if (!ips[i]) break; PBRT_SUBSURFACE_ADDED_POINT_CONTRIBUTION(const_cast<IrradiancePoint *>(ips[i])); Mo += Rd(DistanceSquared(pt, ips[i]->p)) * ips[i]->E * ips[i]->area; } } else { // Recursively visit children nodes to compute $M_\roman{o}$ Point pMid = .5f * nodeBound.pMin + .5f * nodeBound.pMax; for (int child = 0; child < 8; ++child) { if (!children[child]) continue; BBox childBound = octreeChildBound(child, nodeBound, pMid); Mo += children[child]->Mo(childBound, pt, Rd, maxError); } } return Mo; }
bool GridAccel::IntersectP(const Ray &ray) const { if (!gridForRefined) { // NOBOOK rayTests.Add(0, 1); // NOBOOK rayHits.Add(0, 1); // NOBOOK } // NOBOOK int rayId = ++curMailboxId; // Check ray against overall grid bounds float rayT; if (bounds.Inside(ray(ray.mint))) rayT = ray.mint; else if (!bounds.IntersectP(ray, &rayT)) return false; Point gridIntersect = ray(rayT); // Set up 3D DDA for ray float NextCrossingT[3], DeltaT[3]; int Step[3], Out[3], Pos[3]; for (int axis = 0; axis < 3; ++axis) { // Compute current voxel for axis Pos[axis] = PosToVoxel(gridIntersect, axis); if (ray.d[axis] >= 0) { // Handle ray with positive direction for voxel stepping NextCrossingT[axis] = rayT + (VoxelToPos(Pos[axis]+1, axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = Width[axis] / ray.d[axis]; Step[axis] = 1; Out[axis] = NVoxels[axis]; } else { // Handle ray with negative direction for voxel stepping NextCrossingT[axis] = rayT + (VoxelToPos(Pos[axis], axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = -Width[axis] / ray.d[axis]; Step[axis] = -1; Out[axis] = -1; } } // Walk grid for shadow ray for (;;) { int offset = Offset(Pos[0], Pos[1], Pos[2]); Voxel *voxel = voxels[offset]; if (voxel && voxel->IntersectP(ray, rayId)) return true; // Advance to next voxel // Find _stepAxis_ for stepping to next voxel int bits = ((NextCrossingT[0] < NextCrossingT[1]) << 2) + ((NextCrossingT[0] < NextCrossingT[2]) << 1) + ((NextCrossingT[1] < NextCrossingT[2])); const int cmpToAxis[8] = { 2, 1, 2, 1, 2, 2, 0, 0 }; int stepAxis = cmpToAxis[bits]; if (ray.maxt < NextCrossingT[stepAxis]) break; Pos[stepAxis] += Step[stepAxis]; if (Pos[stepAxis] == Out[stepAxis]) break; NextCrossingT[stepAxis] += DeltaT[stepAxis]; } return false; }
TEST_F(BBoxTest, InsideDetectsPointOnBorderAsInside) { BBox b (Point (1, 1, 1), Point (3, 3, 3)); Point p (3, 3, 3); bool result = b.Inside (p); EXPECT_TRUE (result); }
TEST_F(BBoxTest, InsideDetectsPointOutside) { BBox b (Point (1, 1, 1), Point (3, 3, 3)); Point p (4, 4, 4); bool result = b.Inside (p); EXPECT_FALSE (result); }
float VolumeGrid::Density(const Point &Pobj) const { if (!extent.Inside(Pobj)) return 0; // Compute voxel coordinates and offsets for _Pobj_ float voxx = (Pobj.x - extent.pMin.x) / (extent.pMax.x - extent.pMin.x) * nx - .5f; float voxy = (Pobj.y - extent.pMin.y) / (extent.pMax.y - extent.pMin.y) * ny - .5f; float voxz = (Pobj.z - extent.pMin.z) / (extent.pMax.z - extent.pMin.z) * nz - .5f; int vx = Floor2Int(voxx); int vy = Floor2Int(voxy); int vz = Floor2Int(voxz); float dx = voxx - vx, dy = voxy - vy, dz = voxz - vz; // Trilinearly interpolate density values to compute local density float d00 = Lerp(dx, D(vx, vy, vz), D(vx+1, vy, vz)); float d10 = Lerp(dx, D(vx, vy+1, vz), D(vx+1, vy+1, vz)); float d01 = Lerp(dx, D(vx, vy, vz+1), D(vx+1, vy, vz+1)); float d11 = Lerp(dx, D(vx, vy+1, vz+1),D(vx+1, vy+1, vz+1)); float d0 = Lerp(dy, d00, d10); float d1 = Lerp(dy, d01, d11); return Lerp(dz, d0, d1); }
// get/update camera from values in node GvBool GvViewpoint::getCamera(GCamera &camera, BBox &bbox, float visibilityLimitNear,float visibilityLimit, Matrix *cameraTransform) { Matrix m; float viewAngle = 0.785398; float aspectRatio = 1.0f; orientation.get(m); camera.position=position; viewAngle = (float) fieldOfView; Point dir(0,0,-1.0); Point up(0,1.0,0); // apply orientation to standard dir and up vectors dir *= m; up *= m; up.Normalize(); if (cameraTransform) { camera.position *= *cameraTransform; dir = RotateOnly(*cameraTransform,dir); up = RotateOnly(*cameraTransform,up); // near far focalDistance ?????????? } dir.Normalize(); up.Normalize(); Point size = bbox.Size(); // computed bounding box float field = max(max(fabs(size.x),fabs(size.y)),fabs(size.z)); int positionInBox = bbox.Inside(camera.position); if (bbox.IsEmpty() || (field<=1E-20f)) field = 2.0f; // no bounding box yet, bad // compute distance to target point //xx float targetDistance = field*2.0f; float targetDistance = field*1.0f; // viewpoint inside scene if (positionInBox) targetDistance = 0.2 * field; camera.targetDistanceIsDefault=1; camera.zrangeIsDefault=1; // compute a reasonable z-range if (visibilityLimit >0.0f) { camera.zfar = visibilityLimit; camera.zrangeIsDefault=0; } else { if (positionInBox) camera.zfar = field*1.5; else camera.zfar = field*3.0f; Point center = bbox.Center(); Point d = camera.position - center; float dist = d.Length(); // make shure object is visible from viewpoint if ((dist+field) > camera.zfar) camera.zfar = dist + field; } if (visibilityLimitNear > 0.0f) camera.znear = visibilityLimitNear; else camera.znear = camera.zfar * camera.znearFactor; // compute target camera.target = camera.position + targetDistance*dir; camera.up = up; // field of view camera.height = 2.0 * tan(viewAngle * 0.5)*targetDistance; camera.width = camera.height * aspectRatio; if (!bbox.IsEmpty()) camera.SetWorldReference(bbox); camera.ComputeWorldUpFromUp(); camera.OnChanged(); return gtrue; }