virtual Vec sample( Intersection const &isect, float u1, float u2, Vec& WiW, float& pdfResult, int &bxdfType) const { pdfResult = 1.f; WiW = isect.toWorld(cosineSampleHemisphere(u1, u2)); bxdfType = BxDF_DIFFUSE; return isect.texSample; }
// XXX importance sampling is only done into the positive hemisphere // ==> poor support for translucent materials Light_SampleRes AmbientLight_sample(const Light* super, const DifferentialGeometry& dg, const Vec2f& s) { AmbientLight* self = (AmbientLight*)super; Light_SampleRes res; const Vec3fa localDir = cosineSampleHemisphere(s); res.dir = frame(dg.Ns) * localDir; res.pdf = cosineSampleHemispherePDF(localDir); res.dist = inf; res.weight = self->radiance * rcp(res.pdf); return res; }
rgbColor substrate::sampleF(const float& u0, const float& u1, const vec3& wo, vec3& wi, float& pd) const{ if(u0 < 0.5f){ const float u = 2.f * u0; cosineSampleHemisphere(wi, u, u1); }else{ const float u = 2.f * (u0 - 0.5f); distrib->sampleF(u, u1, wo, wi, pd); if(wo.y * wi.y < 0){ return rgbColor(0.f); } } pd = pdf(wo, wi); return f(wo, wi); }
Light_SampleRes PointLight_sample(const Light* super, const DifferentialGeometry& dg, const Vec2f& s) { const PointLight* self = (PointLight*)super; Light_SampleRes res; // extant light vector from the hit point const Vec3fa dir = self->position - dg.P; const float dist2 = dot(dir, dir); const float invdist = rsqrt(dist2); // normalized light vector res.dir = dir * invdist; res.dist = dist2 * invdist; res.pdf = inf; // per default we always take this res // convert from power to radiance by attenuating by distance^2 res.weight = self->power * sqr(invdist); const float sinTheta = self->radius * invdist; if ((self->radius > 0.f) & (sinTheta > 0.005f)) { // res surface of sphere as seen by hit point -> cone of directions // for very small cones treat as point light, because float precision is not good enough if (sinTheta < 1.f) { const float cosTheta = sqrt(1.f - sinTheta * sinTheta); const Vec3fa localDir = uniformSampleCone(cosTheta, s); res.dir = frame(res.dir) * localDir; res.pdf = uniformSampleConePDF(cosTheta); const float c = localDir.z; res.dist = c*res.dist - sqrt(sqr(self->radius) - (1.f - c*c) * dist2); // TODO scale radiance by actual distance } else { // inside sphere const Vec3fa localDir = cosineSampleHemisphere(s); res.dir = frame(dg.Ns) * localDir; res.pdf = cosineSampleHemispherePDF(localDir); // TODO: res.weight = self->power * rcp(sqr(self->radius)); res.dist = self->radius; } } return res; }
/*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */ inline direction_sample cosineSampleHemisphere(real u, real v, const real3& N) { direction_sample s = cosineSampleHemisphere(u, v); return direction_sample(frameZ(N) * real3(s.value()), s.density()); }
/* renders a single pixel casting with ambient occlusion */ Vec3fa ambientOcclusionShading(int x, int y, RTCRay& ray) { RTCRay rays[AMBIENT_OCCLUSION_SAMPLES]; Vec3fa Ng = normalize(ray.Ng); if (dot(ray.dir,Ng) > 0.0f) Ng = neg(Ng); Vec3fa col = Vec3fa(min(1.0f,0.3f+0.8f*abs(dot(Ng,normalize(ray.dir))))); /* calculate hit point */ float intensity = 0; Vec3fa hitPos = ray.org + ray.tfar * ray.dir; RandomSampler sampler; RandomSampler_init(sampler,x,y,0); /* enable only valid rays */ for (int i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) { /* sample random direction */ Vec2f s = RandomSampler_get2D(sampler); Sample3f dir; dir.v = cosineSampleHemisphere(s); dir.pdf = cosineSampleHemispherePDF(dir.v); dir.v = frame(Ng) * dir.v; /* initialize shadow ray */ RTCRay& shadow = rays[i]; shadow.org = hitPos; shadow.dir = dir.v; bool mask = 1; { // invalidate inactive rays shadow.tnear = mask ? 0.001f : (float)(pos_inf); shadow.tfar = mask ? (float)(inf) : (float)(neg_inf); } shadow.geomID = RTC_INVALID_GEOMETRY_ID; shadow.primID = RTC_INVALID_GEOMETRY_ID; shadow.mask = -1; shadow.time = 0; // FIXME: invalidate inactive rays } RTCIntersectContext context; context.flags = RAYN_FLAGS; /* trace occlusion rays */ #if USE_INTERFACE == 0 rtcOccluded1M(g_scene,&context,rays,AMBIENT_OCCLUSION_SAMPLES,sizeof(RTCRay)); #elif USE_INTERFACE == 1 for (size_t i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) rtcOccluded(g_scene,rays[i]); #else for (size_t i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) rtcOccluded1M(g_scene,&context,&rays[i],1,sizeof(RTCRay)); #endif /* accumulate illumination */ for (int i=0; i<AMBIENT_OCCLUSION_SAMPLES; i++) { if (rays[i].geomID == RTC_INVALID_GEOMETRY_ID) intensity += 1.0f; } /* shade pixel */ return col * (intensity/AMBIENT_OCCLUSION_SAMPLES); }
void DebugRenderer::RenderJob::renderTile(size_t threadIndex, size_t threadCount, size_t taskIndex, size_t taskCount, TaskScheduler::Event* event) { size_t numRays = 0; if (taskIndex == taskCount-1) t0 = getSeconds(); /*! tile pick loop */ while (true) { /*! pick a new tile */ size_t tile = tileID++; if (tile >= numTilesX*numTilesY) break; /*! compute tile location */ Random rand(int(tile)*1024); size_t x0 = (tile%numTilesX)*TILE_SIZE; size_t y0 = (tile/numTilesX)*TILE_SIZE; Vec2i start((int)x0,(int)y0); Vec2i end (min(int(framebuffer->getWidth()),int(start.x+TILE_SIZE))-1,min(int(framebuffer->getHeight()),int(start.y+TILE_SIZE))-1); /*! loop over all pixels of the tile */ for (size_t dy=0; dy<TILE_SIZE; dy++) { size_t iy = y0+dy; float fy = iy*rcpHeight; if (iy >= framebuffer->getHeight()) continue; if (!swapchain->activeLine(iy)) continue; iy = swapchain->raster2buffer(iy); for (size_t dx=0; dx<TILE_SIZE; dx++) { /*! ignore tile pixels outside framebuffer */ size_t ix = x0+dx; float fx = ix*rcpWidth; if (ix >= framebuffer->getWidth()) continue; for (size_t i=0; i<renderer->spp; i++) { /*! create primary ray */ Ray ray; camera->ray(Vec2f(fx,fy), /*Vec2f(rand.getFloat(),rand.getFloat())*/ Vec2f(0.5f,0.5f), ray); for (size_t depth=0; depth<renderer->maxDepth; depth++) { /*! shoot current ray */ //scene->intersector->intersect(ray); rtcIntersect(scene->scene,(RTCRay&)ray); numRays++; if (!ray) break; /*! compute new ray through diffuse bounce */ if (depth+1<renderer->maxDepth) { Vector3f Nf = normalize(ray.Ng); if (dot(-ray.dir,Nf) < 0) Nf = -Nf; new (&ray) Ray(ray.org+0.999f*ray.tfar*ray.dir,cosineSampleHemisphere(rand.getFloat(),rand.getFloat(),Nf),4.0f*float(ulp)/**hit.error*/); } } #if 1 /*! update framebuffer */ if (!ray) framebuffer->set(ix,iy,one); //else framebuffer->get(ix,iy) = Vec4f(abs(hit.Ns.x),abs(hit.Ns.y),abs(hit.Ns.z),1.0f); /*else { hit.Ng = normalize(hit.Ng); framebuffer->set(ix,iy,Color(abs(hit.Ng.x),abs(hit.Ng.y),abs(hit.Ng.z))); }*/ //else framebuffer->set(ix,iy,Color(clamp(dot(ray.dir,normalize(ray.Ng))),0,0)); //else framebuffer->set(ix,iy,Color(hit.u,hit.v,1.0f-hit.u-hit.v)); //else framebuffer->get(ix,iy) = Vec4f(hit.st.x,hit.st.y,1.0f-hit.st.x-hit.st.y,1.0f); //else framebuffer->get(ix,iy) = Vec4f(hit.st.x,0,0,1.0f); //else framebuffer->get(ix,iy) = Vec4f(abs(dot(ray.dir,normalize(hit.dPds))),0,0,1.0f); else framebuffer->set(ix,iy,Color(((3434553*((unsigned)(ray.id0+ray.id1+3243)))%255)/255.0f, ((7342453*((unsigned)(ray.id0+ray.id1+8237)))%255)/255.0f, ((9234454*((unsigned)(ray.id0+ray.id1+2343)))%255)/255.0f)); #endif } } } framebuffer->finishTile(); } /*! we access the atomic ray counter only once per tile */ atomicNumRays += numRays; }
void DebugRenderer::renderThread() { size_t numRays = 0; /*! tile pick loop */ while (true) { /*! pick a new tile */ size_t tile = tileID++; if (tile >= numTilesX*numTilesY) break; /*! compute tile location */ Random rand(int(tile)*1024); size_t x0 = (tile%numTilesX)*TILE_SIZE; size_t y0 = (tile/numTilesX)*TILE_SIZE; Vec2i start((int)x0,(int)y0); Vec2i end (min(int(framebuffer->getWidth()),int(start.x+TILE_SIZE))-1,min(int(framebuffer->getHeight()),int(start.y+TILE_SIZE))-1); /*! loop over all pixels of the tile */ for (size_t dy=0; dy<TILE_SIZE; dy++) { for (size_t dx=0; dx<TILE_SIZE; dx++) { /*! ignore tile pixels outside framebuffer */ size_t ix = x0+dx, iy = y0+dy; if (ix >= framebuffer->getWidth() || iy >= framebuffer->getHeight()) continue; for (int s=0; s<spp; s++) { /*! create primary ray */ DifferentialGeometry hit; Ray ray; camera->ray(Vec2f(ix*rcpWidth,iy*rcpHeight), Vec2f(rand.getFloat(),rand.getFloat()), ray); for (ssize_t depth=0; depth<maxDepth; depth++) { /*! shoot current ray */ new (&hit) DifferentialGeometry; scene->intersector->intersect(ray,hit); scene->postIntersect(ray,hit); numRays++; if (!hit) break; /*! compute new ray through diffuse bounce */ Vec3f Nf = hit.Ng; if (dot(-ray.dir,Nf) < 0) Nf = -Nf; if (depth+1<maxDepth) { ray = Ray(ray.org+0.999f*hit.t*ray.dir,cosineSampleHemisphere(rand.getFloat(),rand.getFloat(),Nf),4.0f*float(ulp)*hit.error); } } /*! update framebuffer */ if (!hit) framebuffer->get(ix,iy) = zero; //else framebuffer->get(ix,iy) = Vec4f(-dot(ray.dir,hit.Ns),0,0,1.0f); else framebuffer->get(ix,iy) = Vec4f(hit.u,hit.v,1.0f-hit.u-hit.v,1.0f); //else framebuffer->get(ix,iy) = Vec4f(hit.st.x,hit.st.y,1.0f-hit.st.x-hit.st.y,1.0f); //else framebuffer->get(ix,iy) = Vec4f(hit.st.x,0,0,1.0f); //else framebuffer->get(ix,iy) = Vec4f(abs(dot(ray.dir,normalize(hit.dPds))),0,0,1.0f); //framebuffer->get(ix,iy) = Vec4f(ix*rcpWidth,iy*rcpHeight,0.0f,0.0f); } } } framebuffer->finishTile(); } /*! we access the atomic ray counter only once per tile */ atomicNumRays += numRays; }