/*! Anisotropic power cosine distribution constructor. */ inline void AnisotropicBlinn__Constructor(AnisotropicBlinn* This, const Vec3fa& Kr, const Vec3fa& Kt, const Vec3fa& dx, float nx, const Vec3fa& dy, float ny, const Vec3fa& dz) { This->Kr = Kr; This->Kt = Kt; This->dx = dx; This->nx = nx; This->dy = dy; This->ny = ny; This->dz = dz; This->norm1 = sqrtf((nx+1)*(ny+1)) * float(one_over_two_pi); This->norm2 = sqrtf((nx+2)*(ny+2)) * float(one_over_two_pi); This->side = reduce_max(Kr)/(reduce_max(Kr)+reduce_max(Kt)); }
// We create packets and directly fill each zBuffer tile. Note that we // really store t values void TaskRayTraceHiZ::run(size_t taskID) { const uint32 taskX = taskID % this->taskXNum; const uint32 taskY = taskID / this->taskXNum; const uint32 startX = taskX * this->width; const uint32 startY = taskY * this->height; const uint32 endX = startX + this->width; const uint32 endY = startY + this->height; uint32 tileY = startY / HiZ::Tile::height; for (uint32 y = startY; y < endY; y += RayPacket::height, ++tileY) { uint32 tileX = startX / HiZ::Tile::width; for (uint32 x = startX; x < endX; x += RayPacket::width, ++tileX) { RayPacket pckt; PacketHit hit; gen.generate(pckt, x, y); intersector->traverse(pckt, hit); ssef zmin(inf), zmax(neg_inf); const uint32 tileID = tileX + tileY * zBuffer->tileXNum; PF_ASSERT(tileID < zBuffer->tileNum); HiZ::Tile &tile = zBuffer->tiles[tileID]; for (uint32 chunkID = 0; chunkID < HiZ::Tile::chunkNum; ++chunkID) { //const ssef t = hit.t[chunkID]; const ssef t = hit.t[chunkID] *dot(sse3f(view.x,view.y,view.z), pckt.dir[chunkID]); tile.z[chunkID] = t; zmin = min(zmin, t); zmax = max(zmax, t); } tile.zmin = reduce_min(zmin)[0]; tile.zmax = reduce_max(zmax)[0]; } } }
void ProbeWidget::render() { const float size = 0.25f * reduce_max(boundingBox.upper - boundingBox.lower); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glPushMatrix(); glTranslatef(coordinate.x, coordinate.y, coordinate.z); glScalef(size, size, size); glBegin(GL_LINES); glColor3f(1.f, 0.f, 0.f); glVertex3f(-0.5f, 0.f, 0.f); glVertex3f( 0.5f, 0.f, 0.f); glColor3f(0.f, 1.f, 0.f); glVertex3f(0.f, -0.5f, 0.f); glVertex3f(0.f, 0.5f, 0.f); glColor3f(0.f, 0.f, 1.f); glVertex3f(0.f, 0.f, -0.5f); glVertex3f(0.f, 0.f, 0.5f); glEnd(); glPopMatrix(); glPopAttrib(); }
//! \brief commit the material's parameters virtual void commit() override { if (getIE() == nullptr) ispcEquivalent = ispc::PathTracer_OBJ_create(); Texture2D *map_d = (Texture2D*)getParamObject("map_d"); affine2f xform_d = getTextureTransform("map_d"); Texture2D *map_Kd = (Texture2D*)getParamObject("map_Kd", getParamObject("map_kd", getParamObject("colorMap"))); affine2f xform_Kd = getTextureTransform("map_Kd") * getTextureTransform("map_kd") * getTextureTransform("colorMap"); Texture2D *map_Ks = (Texture2D*)getParamObject("map_Ks", getParamObject("map_ks")); affine2f xform_Ks = getTextureTransform("map_Ks") * getTextureTransform("map_ks"); Texture2D *map_Ns = (Texture2D*)getParamObject("map_Ns", getParamObject("map_ns")); affine2f xform_Ns = getTextureTransform("map_Ns") * getTextureTransform("map_ns"); Texture2D *map_Bump = (Texture2D*)getParamObject("map_Bump", getParamObject("map_bump", getParamObject("normalMap", getParamObject("bumpMap")))); affine2f xform_Bump = getTextureTransform("map_Bump") * getTextureTransform("map_bump") * getTextureTransform("normalMap") * getTextureTransform("BumpMap"); linear2f rot_Bump = xform_Bump.l.orthogonal().transposed(); const float d = getParam1f("d", getParam1f("alpha", 1.f)); vec3f Kd = getParam3f("Kd", getParam3f("kd", getParam3f("color", vec3f(0.8f)))); vec3f Ks = getParam3f("Ks", getParam3f("ks", vec3f(0.f))); const float Ns = getParam1f("Ns", getParam1f("ns", 10.f)); vec3f Tf = getParam3f("Tf", getParam3f("tf", vec3f(0.0f))); const float color_total = reduce_max(Kd + Ks + Tf); if (color_total > 1.0) { postStatusMsg() << "#osp:PT: warning: OBJ material produces energy " << "(Kd + Ks + Tf = " << color_total << ", should be <= 1). Scaling down to 1."; Kd /= color_total; Ks /= color_total; Tf /= color_total; } ispc::PathTracer_OBJ_set(ispcEquivalent, map_d ? map_d->getIE() : nullptr, (const ispc::AffineSpace2f&)xform_d, d, map_Kd ? map_Kd->getIE() : nullptr, (const ispc::AffineSpace2f&)xform_Kd, (const ispc::vec3f&)Kd, map_Ks ? map_Ks->getIE() : nullptr, (const ispc::AffineSpace2f&)xform_Ks, (const ispc::vec3f&)Ks, map_Ns ? map_Ns->getIE() : nullptr, (const ispc::AffineSpace2f&)xform_Ns, Ns, (const ispc::vec3f&)Tf, map_Bump ? map_Bump->getIE() : nullptr, (const ispc::AffineSpace2f&)xform_Bump, (const ispc::LinearSpace2f&)rot_Bump); }
void TriangleMeshWithNormals::postIntersect(const StreamRay& ray, const StreamRayExtra& rayExtra, const StreamHit& hit, DifferentialGeometry& dg) const { const Triangle& tri = triangles[hit.id1]; const Vertex& v0 = vertices[tri.v0]; const Vertex& v1 = vertices[tri.v1]; const Vertex& v2 = vertices[tri.v2]; float u = hit.u, v = hit.v, w = 1.0f-u-v, t = ray.tfar; Vector3f dPdu = v1.p - v0.p, dPdv = v2.p - v0.p; dg.P = rayExtra.org()+t*rayExtra.dir(); dg.Ng = normalize(_mm_load_ps(hit.Ng)); dg.st = Vec2f(u,v); Vector3f Ns = w*v0.n + u*v1.n + v*v2.n; float len2 = dot(Ns,Ns); Ns = len2 > 0 ? Ns*rsqrt(len2) : Vector3f(dg.Ng); if (dot(Ns,dg.Ng) < 0) Ns = -Ns; dg.Ns = Ns; dg.Tx = dPdu; dg.Ty = dPdv; dg.error = max(abs(ray.tfar),reduce_max(abs(dg.P))); }
/* task that renders a single screen tile */ Vec3fa renderPixelPathTrace(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { RandomSampler sampler; RandomSampler_init(sampler, x, y, g_accu_count); x += RandomSampler_get1D(sampler); y += RandomSampler_get1D(sampler); float time = RandomSampler_get1D(sampler); /* initialize ray */ RTCRay2 ray; ray.org = p; ray.dir = normalize(x*vx + y*vy + vz); ray.tnear = 0.0f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = time; ray.filter = nullptr; Vec3fa color = Vec3fa(0.0f); Vec3fa weight = Vec3fa(1.0f); size_t depth = 0; while (true) { /* terminate ray path */ if (reduce_max(weight) < 0.01 || depth > 20) return color; /* intersect ray with scene and gather all hits */ rtcIntersect(g_scene,*((RTCRay*)&ray)); /* exit if we hit environment */ if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return color + weight*Vec3fa(g_ambient_intensity); /* calculate transmissivity of hair */ AnisotropicBlinn brdf; float tnear_eps = 0.0001f; ISPCGeometry* geometry = g_ispc_scene->geometries[ray.geomID]; if (geometry->type == HAIR_SET) { /* calculate tangent space */ const Vec3fa dx = normalize(ray.Ng); const Vec3fa dy = normalize(cross(ray.dir,dx)); const Vec3fa dz = normalize(cross(dy,dx)); /* generate anisotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); brdf.Kr = hair_Kr; Vec3fa p = evalBezier(ray.geomID,ray.primID,ray.u); tnear_eps = 1.1f*p.w; } else if (geometry->type == TRIANGLE_MESH) { ISPCTriangleMesh* mesh = (ISPCTriangleMesh*) geometry; ISPCTriangle* triangle = &mesh->triangles[ray.primID]; OBJMaterial* material = (OBJMaterial*) &g_ispc_scene->materials[triangle->materialID]; if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); /* calculate tangent space */ const Vec3fa dz = normalize(ray.Ng); const Vec3fa dx = normalize(cross(dz,ray.dir)); const Vec3fa dy = normalize(cross(dz,dx)); /* generate isotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,Vec3fa(1.0f),Vec3fa(0.0f),dx,1.0f,dy,1.0f,dz); } /* sample directional light */ RTCRay2 shadow; shadow.org = ray.org + ray.tfar*ray.dir; shadow.dir = neg(Vec3fa(g_dirlight_direction)); shadow.tnear = tnear_eps; shadow.tfar = inf; shadow.time = time; Vec3fa T = occluded(g_scene,shadow); Vec3fa c = AnisotropicBlinn__eval(&brdf,neg(ray.dir),neg(Vec3fa(g_dirlight_direction))); color = color + weight*c*T*Vec3fa(g_dirlight_intensity); #if 1 /* sample BRDF */ Vec3fa wi; float ru = RandomSampler_get1D(sampler); float rv = RandomSampler_get1D(sampler); float rw = RandomSampler_get1D(sampler); c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,ru,rv,rw); if (wi.w <= 0.0f) return color; /* calculate secondary ray and offset it out of the hair */ float sign = dot(Vec3fa(wi),brdf.dz) < 0.0f ? -1.0f : 1.0f; ray.org = ray.org + ray.tfar*ray.dir + sign*tnear_eps*brdf.dz; ray.dir = Vec3fa(wi); ray.tnear = 0.001f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = time; ray.filter = nullptr; weight = weight * c/wi.w; #else /* continue with transparency ray */ ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.tnear = 1.001f*ray.tfar; ray.tfar = inf; weight *= brdf.Kt; #endif depth++; } return color; }
Col3f PathTraceIntegrator::Li(const LightPath& lightPathOrig, const Ref<BackendScene>& scene, Sampler* sampler, size_t& numRays) { bool done = false; Col3f coeff = Col3f(1,1,1); Col3f Lsum = zero; Col3f L = zero; LightPath lightPath = lightPathOrig; bool doneDiffuse = false; /*! while cycle instead of the recusrion call * throughput is accumulated and the resulting light addition is * multipliled by this throughput (coef) at each itteration */ while (!done) { BRDFType directLightingBRDFTypes = (BRDFType)(DIFFUSE); BRDFType giBRDFTypes = (BRDFType)(ALL); /*! Terminate path if too long or contribution too low. */ L = zero; /*! Terminate the path if maxDepth is reached */ if (lightPath.depth >= maxDepth) // || reduce_max(coeff) < minContribution) return Lsum; /*! Traverse ray. */ DifferentialGeometry dg; scene->accel->intersect(lightPath.lastRay,dg); scene->postIntersect(lightPath.lastRay,dg); const Vec3f wo = -lightPath.lastRay.dir; numRays++; /*! Environment shading when nothing hit. */ if (!dg) { if (backplate && lightPath.unbend) { Vec2f raster = sampler->getPrimary(); int width = sampler->getImageSize().x; int height = sampler->getImageSize().y; int x = (int)((raster.x / width) * backplate->width); x = clamp(x, 0, int(backplate->width)-1); int y = (int)((raster.y / height) * backplate->height); y = clamp(y, 0, int(backplate->height)-1); L = backplate->get(x, y); } else { if (!lightPath.ignoreVisibleLights) for (size_t i=0; i<scene->envLights.size(); i++) L += scene->envLights[i]->Le(wo); } return Lsum + L*coeff; } /*! Shade surface. */ CompositedBRDF brdfs; if (dg.material) dg.material->shade(lightPath.lastRay, lightPath.lastMedium, dg, brdfs); /*! face forward normals */ bool backfacing = false; #if defined(__EMBREE_CONSISTENT_NORMALS__) && __EMBREE_CONSISTENT_NORMALS__ > 1 return Col3f(abs(dg.Ns.x),abs(dg.Ns.y),abs(dg.Ns.z)); #else if (dot(dg.Ng, lightPath.lastRay.dir) > 0) { backfacing = true; dg.Ng = -dg.Ng; dg.Ns = -dg.Ns; } #endif /*! Sample BRDF - get the sample direction for * both the indirect illumination as well as for the MIS BRDF sampling */ Col3f c; Sample3f wi;BRDFType type; Vec2f s = sampler->getVec2f(firstScatterSampleID + lightPath.depth); float ss = sampler->getFloat(firstScatterTypeSampleID + lightPath.depth); c = brdfs.sample(wo, dg, wi, type, s, ss, giBRDFTypes); /*! Add light emitted by hit area light source. */ if (!lightPath.ignoreVisibleLights && dg.light && !backfacing) L += dg.light->Le(dg,wo); /*! Check if any BRDF component uses direct lighting. */ bool useDirectLighting = false; for (size_t i=0; i<brdfs.size(); i++) useDirectLighting |= (brdfs[i]->type & directLightingBRDFTypes) != NONE; /*! Direct lighting. */ if (useDirectLighting) { std::vector<float> illumFactor; // illumination factor for each ls float sum = 0; LightSample ls; if ( wi.pdf > 0.0f ) { Ray r( dg.P, wi.value, dg.error*epsilon, inf ); DifferentialGeometry diff; scene->accel->intersect( r, diff ); scene->postIntersect( r, diff ); // Col3f red = Col3f( 1.0f, 0.0f, 0.0f); Col3f radiance = Col3f( 0.0f,0.0f,0.0f ); if ( diff.light ) // if BRDF sampling hits the light { radiance = diff.light->Le(diff, -wi.value ); } if ( dot( diff.Ng, -r.dir ) > 0 && type != GLOSSY_REFLECTION) L += radiance * c / wi.pdf; } /*! Run through all the lightsources and sample or compute the distribution function for rnd gen */ for (size_t i=0; i<scene->allLights.size(); i++) { /*! Either use precomputed samples for the light or sample light now. */ if (scene->allLights[i]->precompute()) ls = sampler->getLightSample(precomputedLightSampleID[i]); else ls.L = scene->allLights[i]->sample(dg, ls.wi, ls.tMax, sampler->getVec2f(lightSampleID)); /*! Start using only one random lightsource after first Lambertian reflection * in case of the direct illumination MIS this heuristics is ommited */ if (true)//donedif { /*! run through all the lighsources and compute radiance accumulatively */ float boo = reduce_max(ls.L)/ls.tMax; // incomming illuminance heuristic sum += boo; illumFactor.push_back(boo); // illumination factor } else // if all the lights are sampled - take each sample and compute the addition { /*! Ignore zero radiance or illumination from the back. */ if (ls.L == Col3f(zero) || ls.wi.pdf == 0.0f || dot(dg.Ns,Vec3f(ls.wi)) <= 0.0f) continue; /*! Test for shadows. */ bool inShadow = scene->accel->occluded(Ray(dg.P, ls.wi, dg.error*epsilon, ls.tMax-dg.error*epsilon)); numRays++; if (inShadow) continue; /*! Evaluate BRDF. */ L += ls.L * brdfs.eval(wo, dg, ls.wi, directLightingBRDFTypes) * rcp(ls.wi.pdf); } } /*! After fisrt Lambertian reflection pick one random lightsource and compute contribution * in case of MIS active this heuristic is ommited */ if (true && scene->allLights.size() != 0)//donedif { /*! Generate the random value */ unsigned int RndVal; // random value // if (rand_s(&RndVal)) std::cout << "\nRND gen error!\n"; rand_r(&RndVal); float rnd((float)RndVal/(float)UINT_MAX); // compute the 0-1 rnd value /*! Pick the particular lightsource according the intensity-given distribution */ size_t i = 0; float accum = illumFactor[i]/sum; // accumulative sum while (i < scene->allLights.size() && rnd > accum) // get the lightsource index accirding the Pr { ++i; accum +=illumFactor[i]/sum; } /*! Sample the selected lightsource and compute contribution */ if ( i >= scene->allLights.size() ) i = scene->allLights.size() -1; // if (usedLight != NULL) // std::cout << "direct light " << scene->allLights[i].ptr << "\n"; float ql = illumFactor[i]/sum; // Pr of given lightsource // LightSample ls; if (scene->allLights[i]->precompute()) ls = sampler->getLightSample(precomputedLightSampleID[i]); else ls.L = scene->allLights[i]->sample(dg, ls.wi, ls.tMax, sampler->getVec2f(lightSampleID)); /*! Ignore zero radiance or illumination from the back. */ if (ls.L != Col3f(zero) && ls.wi.pdf != 0.0f && dot(dg.Ns,Vec3f(ls.wi)) > 0.0f) { /*! Test for shadows. */ bool inShadow = scene->accel->occluded(Ray(dg.P, ls.wi, dg.error*epsilon, ls.tMax-dg.error*epsilon)); numRays++; if (!inShadow) { /*! Evaluate BRDF. */ L += ls.L * brdfs.eval(wo, dg, ls.wi, directLightingBRDFTypes) * rcp(ls.wi.pdf*ql) * weight; } } } } /* Add the resulting light */ Lsum += coeff * L; /*! Global illumination. Pick one BRDF component and sample it. */ if (lightPath.depth < maxDepth) //always true { /*! Continue only if we hit something valid. */ if (c != Col3f(zero) && wi.pdf > 0.0f) { /*! detect the first diffuse */ if (wi.pdf < 0.33) doneDiffuse = true; /*! Compute simple volumetric effect. */ const Col3f& transmission = lightPath.lastMedium.transmission; if (transmission != Col3f(one)) c *= pow(transmission,dg.t); /*! Tracking medium if we hit a medium interface. */ Medium nextMedium = lightPath.lastMedium; if (type & TRANSMISSION) nextMedium = dg.material->nextMedium(lightPath.lastMedium); /*! Continue the path. */ float q = 1; if (doneDiffuse) { //std::cout << "\ndifusni\n"; q = min(abs(reduce_max(c) * rcp(wi.pdf)), (float)1); // std::cout << q << "\n"; unsigned int RndVal; // if (rand_s(&RndVal)) std::cout << "\nRND gen error!\n"; rand_r(&RndVal); if ((float)RndVal/(float)UINT_MAX > q) { // std::cout << "konec"; return Lsum;// + L*coeff; } } /*! Continue the path */ lightPath = lightPath.extended(Ray(dg.P, wi, dg.error*epsilon, inf), nextMedium, c, (type & directLightingBRDFTypes) != NONE); coeff = coeff * c * rcp(q * wi.pdf); }else done = true; // end the path } } return Lsum; }
/* task that renders a single screen tile */ Vec3fa renderPixelPathTrace(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { int seed = 21344*x+121233*y+234532*g_accu_count; float time = frand(seed); /* initialize ray */ RTCRay2 ray; ray.org = p; ray.dir = normalize(x*vx + y*vy + vz); ray.tnear = 0.0f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = time; ray.filter = NULL; Vec3fa color = Vec3fa(0.0f); Vec3fa weight = Vec3fa(1.0f); size_t depth = 0; while (true) { /* terminate ray path */ if (reduce_max(weight) < 0.01 || depth > 20) return color; /* intersect ray with scene and gather all hits */ rtcIntersect(g_scene,*((RTCRay*)&ray)); // FIXME: use (RTCRay&) cast /* exit if we hit environment */ if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return color + weight*Vec3fa(g_ambient_intensity); /* calculate transmissivity of hair */ AnisotropicBlinn brdf; float tnear_eps = 0.0001f; if (ray.geomID < g_ispc_scene->numHairSets) { /* calculate tangent space */ const Vec3fa dx = normalize(ray.Ng); const Vec3fa dy = normalize(cross(ray.dir,dx)); const Vec3fa dz = normalize(cross(dy,dx)); /* generate anisotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); brdf.Kr = hair_Kr; Vec3fa p = evalBezier(ray.geomID,ray.primID,ray.u); tnear_eps = 1.1f*p.w; } else { int meshID = ray.geomID-g_ispc_scene->numHairSets; ISPCMesh* mesh = g_ispc_scene->meshes[meshID]; ISPCTriangle* triangle = &mesh->triangles[ray.primID]; ISPCMaterial* material = &g_ispc_scene->materials[triangle->materialID]; if (material->illum == 1) { /* calculate tangent space */ const Vec3fa dx = normalize(Vec3fa(mesh->normals[triangle->v0])); const Vec3fa dy = normalize(cross(ray.dir,dx)); const Vec3fa dz = normalize(cross(dy,dx)); /* generate anisotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); brdf.Kr = hair_Kr; tnear_eps = 1.1f*mesh->texcoords[triangle->v0].x; } else { if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); /* calculate tangent space */ const Vec3fa dz = normalize(ray.Ng); const Vec3fa dx = normalize(cross(dz,ray.dir)); const Vec3fa dy = normalize(cross(dz,dx)); /* generate isotropic BRDF */ AnisotropicBlinn__Constructor(&brdf,Vec3fa(1.0f),Vec3fa(0.0f),dx,1.0f,dy,1.0f,dz); } } /* sample directional light */ RTCRay2 shadow; shadow.org = ray.org + ray.tfar*ray.dir; shadow.dir = neg(Vec3fa(g_dirlight_direction)); shadow.tnear = tnear_eps; shadow.tfar = inf; shadow.time = time; Vec3fa T = occluded(g_scene,shadow); Vec3fa c = AnisotropicBlinn__eval(&brdf,neg(ray.dir),neg(Vec3fa(g_dirlight_direction))); color = color + weight*c*T*Vec3fa(g_dirlight_intensity); // FIXME: use += operator #if 1 /* sample BRDF */ Vec3fa wi; c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,frand(seed),frand(seed),frand(seed)); if (wi.w <= 0.0f) return color; /* calculate secondary ray and offset it out of the hair */ float sign = dot(Vec3fa(wi),brdf.dz) < 0.0f ? -1.0f : 1.0f; ray.org = ray.org + ray.tfar*ray.dir + sign*tnear_eps*brdf.dz; ray.dir = Vec3fa(wi); ray.tnear = 0.001f; ray.tfar = inf; ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.primID = RTC_INVALID_GEOMETRY_ID; ray.mask = -1; ray.time = time; ray.filter = NULL; weight = weight * c/wi.w; // FIXME: use *= operator #else /* continue with transparency ray */ ray.geomID = RTC_INVALID_GEOMETRY_ID; ray.tnear = 1.001f*ray.tfar; ray.tfar = inf; weight *= brdf.Kt; #endif depth++; } return color; }
Color PathTraceIntegrator::Li(LightPath& lightPath, const Ref<BackendScene>& scene, IntegratorState& state) { /*! Terminate path if too long or contribution too low. */ if (lightPath.depth >= maxDepth || reduce_max(lightPath.throughput) < minContribution) return zero; /*! Traverse ray. */ DifferentialGeometry dg; //scene->intersector->intersect(lightPath.lastRay); rtcIntersect(scene->scene,(RTCRay&)lightPath.lastRay); scene->postIntersect(lightPath.lastRay,dg); state.numRays++; //return Color(dg.st.x,dg.st.y,0.0f); Color L = zero; const Vector3f wo = -lightPath.lastRay.dir; BRDFType directLightingBRDFTypes = (BRDFType)(DIFFUSE); BRDFType giBRDFTypes = (BRDFType)(ALL); if (sampleLightForGlossy) { directLightingBRDFTypes = (BRDFType)(DIFFUSE|GLOSSY); giBRDFTypes = (BRDFType)(SPECULAR); } /*! Environment shading when nothing hit. */ if (!lightPath.lastRay) { if (backplate && lightPath.unbend) { const int x = clamp(int(state.pixel.x * backplate->width ), 0, int(backplate->width )-1); const int y = clamp(int(state.pixel.y * backplate->height), 0, int(backplate->height)-1); L = backplate->get(x, y); } else { if (!lightPath.ignoreVisibleLights) for (size_t i=0; i<scene->envLights.size(); i++) L += scene->envLights[i]->Le(wo); } return L; } /*! face forward normals */ bool backfacing = false; if (dot(dg.Ng, lightPath.lastRay.dir) > 0) { backfacing = true; dg.Ng = -dg.Ng; dg.Ns = -dg.Ns; } /*! Shade surface. */ CompositedBRDF brdfs; if (dg.material) dg.material->shade(lightPath.lastRay, lightPath.lastMedium, dg, brdfs); /*! Add light emitted by hit area light source. */ if (!lightPath.ignoreVisibleLights && dg.light && !backfacing) L += dg.light->Le(dg,wo); /*! Global illumination. Pick one BRDF component and sample it. */ if (lightPath.depth < maxDepth) { /*! sample brdf */ Sample3f wi; BRDFType type; Vec2f s = state.sample->getVec2f(firstScatterSampleID + lightPath.depth); float ss = state.sample->getFloat(firstScatterTypeSampleID + lightPath.depth); Color c = brdfs.sample(wo, dg, wi, type, s, ss, giBRDFTypes); /*! Continue only if we hit something valid. */ if (c != Color(zero) && wi.pdf > 0.0f) { /*! Compute simple volumetric effect. */ const Color& transmission = lightPath.lastMedium.transmission; if (transmission != Color(one)) c *= pow(transmission,lightPath.lastRay.tfar); /*! Tracking medium if we hit a medium interface. */ Medium nextMedium = lightPath.lastMedium; if (type & TRANSMISSION) nextMedium = dg.material->nextMedium(lightPath.lastMedium); /*! Continue the path. */ LightPath scatteredPath = lightPath.extended(Ray(dg.P, wi, dg.error*epsilon, inf, lightPath.lastRay.time), nextMedium, c, (type & directLightingBRDFTypes) != NONE); L += c * Li(scatteredPath, scene, state) * rcp(wi.pdf); } } /*! Check if any BRDF component uses direct lighting. */ bool useDirectLighting = false; for (size_t i=0; i<brdfs.size(); i++) useDirectLighting |= (brdfs[i]->type & directLightingBRDFTypes) != NONE; /*! Direct lighting. Shoot shadow rays to all light sources. */ if (useDirectLighting) { for (size_t i=0; i<scene->allLights.size(); i++) { if ((scene->allLights[i]->illumMask & dg.illumMask) == 0) continue; /*! Either use precomputed samples for the light or sample light now. */ LightSample ls; if (scene->allLights[i]->precompute()) ls = state.sample->getLightSample(precomputedLightSampleID[i]); else ls.L = scene->allLights[i]->sample(dg, ls.wi, ls.tMax, state.sample->getVec2f(lightSampleID)); /*! Ignore zero radiance or illumination from the back. */ //if (ls.L == Color(zero) || ls.wi.pdf == 0.0f || dot(dg.Ns,Vector3f(ls.wi)) <= 0.0f) continue; if (ls.L == Color(zero) || ls.wi.pdf == 0.0f) continue; /*! Evaluate BRDF */ Color brdf = brdfs.eval(wo, dg, ls.wi, directLightingBRDFTypes); if (brdf == Color(zero)) continue; /*! Test for shadows. */ Ray shadowRay(dg.P, ls.wi, dg.error*epsilon, ls.tMax-dg.error*epsilon, lightPath.lastRay.time,dg.shadowMask); rtcOccluded(scene->scene,(RTCRay&)shadowRay); state.numRays++; if (shadowRay) continue; /*! Evaluate BRDF. */ L += ls.L * brdf * rcp(ls.wi.pdf); } } return L; }
void TriangleMeshFull::postIntersect(const StreamRay& ray, const StreamRayExtra& rayExtra, const StreamHit& hit, DifferentialGeometry& dg) const { const Triangle& tri = triangles[hit.id1]; const float u = hit.u, v = hit.v, w = 1.0f - u - v, t = ray.tfar; dg.P = rayExtra.org() + t*rayExtra.dir(); dg.Ng = normalize(_mm_load_ps(hit.Ng)); /* interpolate shading normal */ if (normal.size()) { const Vector3f n0 = normal[tri.v0], n1 = normal[tri.v1], n2 = normal[tri.v2]; Vector3f Ns = w*n0 + u*n1 + v*n2; Vector3f nNs = normalize(Ns); if (dot(Ns, dg.Ng) < 0) nNs = -nNs; dg.Ns = nNs; } else dg.Ns = dg.Ng; dg.error = max(abs(ray.tfar), reduce_max(abs(dg.P))); if (!dg.material || !dg.material->computeTextureCoordinates) return; /* interpolate texture coordinates */ float dsdu, dtdu; float dsdv, dtdv; if (texcoord.size()) { const Vec2f st0 = texcoord[tri.v0]; const Vec2f st1 = texcoord[tri.v1]; const Vec2f st2 = texcoord[tri.v2]; dg.st = st0*w + st1*u + st2*v; dsdu = st1.x - st0.x; dtdu = st1.y - st0.y; dsdv = st2.x - st0.x; dtdv = st2.y - st0.y; } else { dg.st = Vec2f(u, v); dsdu = 1; dtdu = 0; dsdv = 0; dtdv = 1; } if (!dg.material || !dg.material->computeTangentBasis) return; Vector3f p0 = position[tri.v0], p1 = position[tri.v1], p2 = position[tri.v2]; const Vector3f dPdu = p1 - p0, dPdv = p2 - p0; if (unlikely(motion.size())) { p0 += rayExtra.time * motion[tri.v0]; p1 += rayExtra.time * motion[tri.v1]; p2 += rayExtra.time * motion[tri.v2]; } /* interpolate x tangent direction */ if (tangent_x.size()) { const Vector3f t0 = tangent_x[tri.v0], t1 = tangent_x[tri.v1], t2 = tangent_x[tri.v2]; dg.Tx = w*t0 + u*t1 + v*t2; } else { const Vector3f dPds = dPdu*dtdv - dPdv*dtdu; dg.Tx = dPds-dot(dPds,dg.Ns)*dg.Ns; } /* interpolate y tangent direction */ if (tangent_y.size()) { const Vector3f t0 = tangent_y[tri.v0], t1 = tangent_y[tri.v1], t2 = tangent_y[tri.v2]; dg.Ty = w*t0 + u*t1 + v*t2; } else { const Vector3f dPdt = dPdv*dsdu - dPdu*dsdv; dg.Ty = dPdt-dot(dPdt,dg.Ns)*dg.Ns; } dg.Tx = normalize(dg.Tx); dg.Ty = normalize(dg.Ty); }
size_t BVH4MB::rotate(Base* nodeID, size_t depth) { /*! nothing to rotate if we reached a leaf node. */ if (nodeID->isLeaf()) return 0; Node* parent = nodeID->node(); /*! rotate all children first */ ssei cdepth; for (size_t c=0; c<4; c++) cdepth[c] = (int)rotate(parent->child[c],depth+1); /* compute current area of all children */ ssef sizeX = parent->upper_x-parent->lower_x; ssef sizeY = parent->upper_y-parent->lower_y; ssef sizeZ = parent->upper_z-parent->lower_z; ssef childArea = sizeX*(sizeY + sizeZ) + sizeY*sizeZ; /*! transpose node bounds */ ssef plower0,plower1,plower2,plower3; transpose(parent->lower_x,parent->lower_y,parent->lower_z,ssef(zero),plower0,plower1,plower2,plower3); ssef pupper0,pupper1,pupper2,pupper3; transpose(parent->upper_x,parent->upper_y,parent->upper_z,ssef(zero),pupper0,pupper1,pupper2,pupper3); BBox<ssef> other0(plower0,pupper0), other1(plower1,pupper1), other2(plower2,pupper2), other3(plower3,pupper3); /*! Find best rotation. We pick a target child of a first child, and swap this with an other child. We perform the best such swap. */ float bestCost = pos_inf; int bestChild = -1, bestTarget = -1, bestOther = -1; for (size_t c=0; c<4; c++) { /*! ignore leaf nodes as we cannot descent into */ if (parent->child[c]->isLeaf()) continue; Node* child = parent->child[c]->node(); /*! transpose child bounds */ ssef clower0,clower1,clower2,clower3; transpose(child->lower_x,child->lower_y,child->lower_z,ssef(zero),clower0,clower1,clower2,clower3); ssef cupper0,cupper1,cupper2,cupper3; transpose(child->upper_x,child->upper_y,child->upper_z,ssef(zero),cupper0,cupper1,cupper2,cupper3); BBox<ssef> target0(clower0,cupper0), target1(clower1,cupper1), target2(clower2,cupper2), target3(clower3,cupper3); /*! put other0 at each target position */ float cost00 = halfArea3f(merge(other0 ,target1,target2,target3)); float cost01 = halfArea3f(merge(target0,other0 ,target2,target3)); float cost02 = halfArea3f(merge(target0,target1,other0 ,target3)); float cost03 = halfArea3f(merge(target0,target1,target2,other0 )); ssef cost0 = ssef(cost00,cost01,cost02,cost03); ssef min0 = vreduce_min(cost0); int pos0 = (int)__bsf(movemask(min0 == cost0)); /*! put other1 at each target position */ float cost10 = halfArea3f(merge(other1 ,target1,target2,target3)); float cost11 = halfArea3f(merge(target0,other1 ,target2,target3)); float cost12 = halfArea3f(merge(target0,target1,other1 ,target3)); float cost13 = halfArea3f(merge(target0,target1,target2,other1 )); ssef cost1 = ssef(cost10,cost11,cost12,cost13); ssef min1 = vreduce_min(cost1); int pos1 = (int)__bsf(movemask(min1 == cost1)); /*! put other2 at each target position */ float cost20 = halfArea3f(merge(other2 ,target1,target2,target3)); float cost21 = halfArea3f(merge(target0,other2 ,target2,target3)); float cost22 = halfArea3f(merge(target0,target1,other2 ,target3)); float cost23 = halfArea3f(merge(target0,target1,target2,other2 )); ssef cost2 = ssef(cost20,cost21,cost22,cost23); ssef min2 = vreduce_min(cost2); int pos2 = (int)__bsf(movemask(min2 == cost2)); /*! put other3 at each target position */ float cost30 = halfArea3f(merge(other3 ,target1,target2,target3)); float cost31 = halfArea3f(merge(target0,other3 ,target2,target3)); float cost32 = halfArea3f(merge(target0,target1,other3 ,target3)); float cost33 = halfArea3f(merge(target0,target1,target2,other3 )); ssef cost3 = ssef(cost30,cost31,cost32,cost33); ssef min3 = vreduce_min(cost3); int pos3 = (int)__bsf(movemask(min3 == cost3)); /*! find best other child */ ssef otherCost = ssef(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)); int pos[4] = { pos0,pos1,pos2,pos3 }; sseb valid = ssei(int(depth+1))+cdepth <= ssei(maxDepth); // only select swaps that fulfill depth constraints if (none(valid)) continue; size_t n = select_min(valid,otherCost); float cost = otherCost[n]-childArea[c]; //< increasing the original child bound is bad, decreasing good /*! accept a swap when it reduces cost and is not swapping a node with itself */ if (cost < bestCost && n != c) { bestCost = cost; bestChild = (int)c; bestOther = (int)n; bestTarget = pos[n]; } } /*! if we did not find a swap that improves the SAH then do nothing */ if (bestCost >= 0) return 1+reduce_max(cdepth); /*! perform the best found tree rotation */ Node* child = parent->child[bestChild]->node(); swap(parent,bestOther,child,bestTarget); parent->lower_x[bestChild] = reduce_min(child->lower_x); parent->lower_y[bestChild] = reduce_min(child->lower_y); parent->lower_z[bestChild] = reduce_min(child->lower_z); parent->upper_x[bestChild] = reduce_max(child->upper_x); parent->upper_y[bestChild] = reduce_max(child->upper_y); parent->upper_z[bestChild] = reduce_max(child->upper_z); parent->lower_dx[bestChild] = reduce_min(child->lower_dx); parent->lower_dy[bestChild] = reduce_min(child->lower_dy); parent->lower_dz[bestChild] = reduce_min(child->lower_dz); parent->upper_dx[bestChild] = reduce_max(child->upper_dx); parent->upper_dy[bestChild] = reduce_max(child->upper_dy); parent->upper_dz[bestChild] = reduce_max(child->upper_dz); /*! This returned depth is conservative as the child that was * pulled up in the tree could have been on the critical path. */ cdepth[bestOther]++; // bestOther was pushed down one level return 1+reduce_max(cdepth); }
size_t BVHNRotate<4>::rotate(NodeRef parentRef, size_t depth) { /*! nothing to rotate if we reached a leaf node. */ if (parentRef.isBarrier()) return 0; if (parentRef.isLeaf()) return 0; Node* parent = parentRef.node(); /*! rotate all children first */ vint4 cdepth; for (size_t c=0; c<4; c++) cdepth[c] = (int)rotate(parent->child(c),depth+1); /* compute current areas of all children */ vfloat4 sizeX = parent->upper_x-parent->lower_x; vfloat4 sizeY = parent->upper_y-parent->lower_y; vfloat4 sizeZ = parent->upper_z-parent->lower_z; vfloat4 childArea = sizeX*(sizeY + sizeZ) + sizeY*sizeZ; /*! get node bounds */ BBox<vfloat4> child1_0,child1_1,child1_2,child1_3; parent->bounds(child1_0,child1_1,child1_2,child1_3); /*! Find best rotation. We pick a first child (child1) and a sub-child (child2child) of a different second child (child2), and swap child1 and child2child. We perform the best such swap. */ float bestArea = 0; size_t bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1; for (size_t c2=0; c2<4; c2++) { /*! ignore leaf nodes as we cannot descent into them */ if (parent->child(c2).isBarrier()) continue; if (parent->child(c2).isLeaf()) continue; Node* child2 = parent->child(c2).node(); /*! transpose child bounds */ BBox<vfloat4> child2c0,child2c1,child2c2,child2c3; child2->bounds(child2c0,child2c1,child2c2,child2c3); /*! put child1_0 at each child2 position */ float cost00 = halfArea3f(merge(child1_0,child2c1,child2c2,child2c3)); float cost01 = halfArea3f(merge(child2c0,child1_0,child2c2,child2c3)); float cost02 = halfArea3f(merge(child2c0,child2c1,child1_0,child2c3)); float cost03 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_0)); vfloat4 cost0 = vfloat4(cost00,cost01,cost02,cost03); vfloat4 min0 = vreduce_min(cost0); int pos0 = (int)__bsf(movemask(min0 == cost0)); /*! put child1_1 at each child2 position */ float cost10 = halfArea3f(merge(child1_1,child2c1,child2c2,child2c3)); float cost11 = halfArea3f(merge(child2c0,child1_1,child2c2,child2c3)); float cost12 = halfArea3f(merge(child2c0,child2c1,child1_1,child2c3)); float cost13 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_1)); vfloat4 cost1 = vfloat4(cost10,cost11,cost12,cost13); vfloat4 min1 = vreduce_min(cost1); int pos1 = (int)__bsf(movemask(min1 == cost1)); /*! put child1_2 at each child2 position */ float cost20 = halfArea3f(merge(child1_2,child2c1,child2c2,child2c3)); float cost21 = halfArea3f(merge(child2c0,child1_2,child2c2,child2c3)); float cost22 = halfArea3f(merge(child2c0,child2c1,child1_2,child2c3)); float cost23 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_2)); vfloat4 cost2 = vfloat4(cost20,cost21,cost22,cost23); vfloat4 min2 = vreduce_min(cost2); int pos2 = (int)__bsf(movemask(min2 == cost2)); /*! put child1_3 at each child2 position */ float cost30 = halfArea3f(merge(child1_3,child2c1,child2c2,child2c3)); float cost31 = halfArea3f(merge(child2c0,child1_3,child2c2,child2c3)); float cost32 = halfArea3f(merge(child2c0,child2c1,child1_3,child2c3)); float cost33 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_3)); vfloat4 cost3 = vfloat4(cost30,cost31,cost32,cost33); vfloat4 min3 = vreduce_min(cost3); int pos3 = (int)__bsf(movemask(min3 == cost3)); /*! find best other child */ vfloat4 area0123 = vfloat4(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)) - vfloat4(childArea[c2]); int pos[4] = { pos0,pos1,pos2,pos3 }; const size_t mbd = BVH4::maxBuildDepth; vbool4 valid = vint4(int(depth+1))+cdepth <= vint4(mbd); // only select swaps that fulfill depth constraints valid &= vint4(c2) != vint4(step); if (none(valid)) continue; size_t c1 = select_min(valid,area0123); float area = area0123[c1]; if (c1 == c2) continue; // can happen if bounds are NANs /*! accept a swap when it reduces cost and is not swapping a node with itself */ if (area < bestArea) { bestArea = area; bestChild1 = c1; bestChild2 = c2; bestChild2Child = pos[c1]; } } /*! if we did not find a swap that improves the SAH then do nothing */ if (bestChild1 == size_t(-1)) return 1+reduce_max(cdepth); /*! perform the best found tree rotation */ Node* child2 = parent->child(bestChild2).node(); BVH4::swap(parent,bestChild1,child2,bestChild2Child); parent->set(bestChild2,child2->bounds()); BVH4::compact(parent); BVH4::compact(child2); /*! This returned depth is conservative as the child that was * pulled up in the tree could have been on the critical path. */ cdepth[bestChild1]++; // bestChild1 was pushed down one level return 1+reduce_max(cdepth); }