/** * @brief * Get index of color */ int ImagePalette::GetColorIndex(const Color3 &cColor) const { // Do we need to build the color index? if (m_mapColors.GetNumOfElements() == 0) { // Build color index for (uint32 i=0; i<m_nColors; i++) { // Map color to index const uint32 nColorInt = cColor.ToUInt32(); m_mapColors.Add(nColorInt, i); } } // Look up color index const uint32 nColorInt = cColor.ToUInt32(); int nIndex = m_mapColors.Get(nColorInt); // If nIndex is 0, it can be either invalid or really index 0, so check if the colors are equal if (nIndex == 0) { // Check if color is valid const Color3 cColorLookup = GetColor(0); if (cColorLookup != cColor || cColorLookup == Color3::Null) { // Invalid index nIndex = -1; } } // Return color index return nIndex; }
/** * @brief * Called when the scene node modifier needs to be updated */ void SNMLightRandomAnimation::OnUpdate() { // Update timer m_fTimer += Timing::GetInstance()->GetTimeDifference()*Speed; // Set current scene node scale SNLight &cLight = static_cast<SNLight&>(GetSceneNode()); // Animate color Color3 cColor = cLight.Color.Get(); const Color3 cColorT = Color.Get()*((Math::Cos(m_fTimer)+1)/2)*Radius; if (GetFlags() & Multiply) { // Red cColor.r = (GetFlags() & NR) ? FixColor.Get().r : FixColor.Get().r*cColorT.r; // Green cColor.g = (GetFlags() & NG) ? FixColor.Get().g : FixColor.Get().g*cColorT.g; // Blue cColor.b = (GetFlags() & NB) ? FixColor.Get().b : FixColor.Get().b*cColorT.b; } else { // Red cColor.r = (GetFlags() & NR) ? FixColor.Get().r : FixColor.Get().r+cColorT.r; // Green cColor.g = (GetFlags() & NG) ? FixColor.Get().g : FixColor.Get().g+cColorT.g; // Blue cColor.b = (GetFlags() & NB) ? FixColor.Get().b : FixColor.Get().b+cColorT.b; } // Clamp the color values between 0.0 and 1.0 cColor.Saturate(); // Finally, set the new color of the light cLight.Color.Set(cColor); }
static Color3 finalGathering(KdTree<Photon> *map , Scene& scene , Intersection& inter , RNG& rng , const Vector3& wo , int gatherSamples , int knn , Real maxSqrDis) { Color3 res = Color3(0.0 , 0.0 , 0.0); for (int i = 0; i < gatherSamples; i++) { Real pdf; Vector3 wi = sampleCosHemisphere(rng.randVector3() , &pdf); Ray ray = Ray(inter.p + wi * EPS , wi); Intersection _inter; Geometry *_g = scene.intersect(ray , _inter); if (_g == NULL) continue; Color3 tmp = estimate(map , 0 , knn , scene , _inter , -wi , maxSqrDis); BSDF bsdf(wi , _inter , scene); Real cosine , bsdfPdf; Color3 brdf = bsdf.f(scene , wo , cosine , &bsdfPdf); if (brdf.isBlack()) continue; pdf *= bsdfPdf; res = res + (tmp | brdf) * (cosine / pdf); } res = res / gatherSamples; return res; }
Color3 BidirPathTracing::getLightRadiance(AbstractLight *light , BidirPathState& cameraState , const Vector3& hitPos , const Vector3& rayDir) { int lightCount = scene.lights.size(); Real lightPickProb = 1.f / lightCount; Real directPdfArea , emissionPdf; Color3 radiance = light->getRadiance(scene.sceneSphere , rayDir , hitPos , &directPdfArea , &emissionPdf); Color3 res(0); if (radiance.isBlack()) return res; if (cameraState.pathLength == 1) return radiance; directPdfArea *= lightPickProb; emissionPdf *= lightPickProb; Real wCamera = mis(directPdfArea) * cameraState.dVCM + mis(emissionPdf) * cameraState.dVC; Real weight = 1.f / (1.f + wCamera); return radiance * weight; }
Color3 getDiffuse(const Vector3& lightDir , const Vector3& normal , const Color3& lightIntensity , const Color3& diffuse) { Real coe = std::max(0.0 , lightDir ^ normal); Color3 res = (lightIntensity | diffuse) * coe; res.clamp(); return res; }
Color3 getSpecular(const Vector3& reflecDir , const Vector3& visionDir , const Color3& lightIntensity , const Color3& specular) { Real coe = std::max(0.0 , reflecDir ^ visionDir); coe = pow(coe , specularCoefficient); Color3 res = (lightIntensity | specular) * coe; res.clamp(); return res; }
Color3 BidirPathTracing::connectToCamera(BidirPathState& lightState , const Vector3& hitPos , BSDF& bsdf) { Color3 res(0); Camera& camera = scene.camera; Vector3 dirToCamera = camera.pos - hitPos; if (((-dirToCamera) ^ camera.forward) <= 0) return res; Real distEye2 = dirToCamera.sqrLength(); Real dist = std::sqrt(distEye2); dirToCamera = dirToCamera / dist; Real cosToCamera , bsdfDirPdf , bsdfRevPdf; Color3 bsdfFactor = bsdf.f(scene , dirToCamera , cosToCamera , &bsdfDirPdf , &bsdfRevPdf); if (bsdfFactor.isBlack()) return res; bsdfRevPdf *= bsdf.continueProb; Real cosAtCamera = ((-dirToCamera) ^ camera.forward); Real imagePointToCameraDist = camera.imagePlaneDist / cosAtCamera; Real imageToSolidAngleFactor = SQR(imagePointToCameraDist) / cosAtCamera; Real imageToSurfaceFactor = imageToSolidAngleFactor * std::abs(cosToCamera) / distEye2; Real cameraPdfA = imageToSurfaceFactor /* * 1.f */; // pixel area is 1 Real surfaceToImageFactor = 1.f / imageToSurfaceFactor; // We divide the contribution by surfaceToImageFactor to convert the (already // divided) pdf from surface area to image plane area, w.r.t. which the // pixel integral is actually defined. We also divide by the number of samples // this technique makes res = (lightState.throughput | bsdfFactor) / (lightPathNum * surfaceToImageFactor); if (res.isBlack()) return res; if (scene.occluded(hitPos , dirToCamera , camera.pos)) return Color3(0); Real wLight = mis(cameraPdfA / lightPathNum) * (lightState.dVCM + mis(bsdfRevPdf) * lightState.dVC); Real weight = 1.f / (wLight + 1.f); //fprintf(fp , "weight = %.6f\n" , weight); return res * weight; }
// we force to connect eye path to light path Color3 BidirPathTracing::connectVertices(BidirPathState& lightState , BSDF& cameraBsdf , const Vector3& hitPos , BidirPathState& cameraState) { Vector3 dir = lightState.pos - hitPos; Real dist2 = dir.sqrLength(); Real dist = std::sqrt(dist2); dir = dir / dist; Color3 res(0); Real cosAtCamera , cameraBsdfDirPdf , cameraBsdfRevPdf; Color3 cameraBsdfFactor = cameraBsdf.f(scene , dir , cosAtCamera , &cameraBsdfDirPdf , &cameraBsdfRevPdf); if (cameraBsdfFactor.isBlack()) return res; Real cameraContProb = cameraBsdf.continueProb; cameraBsdfDirPdf *= cameraContProb; cameraBsdfRevPdf *= cameraContProb; Real cosAtLight , lightBsdfDirPdf , lightBsdfRevPdf; Color3 lightBsdfFactor = lightState.bsdf.f(scene , -dir , cosAtLight , &lightBsdfDirPdf , &lightBsdfRevPdf); if (lightBsdfFactor.isBlack()) return res; Real lightContProb = lightState.bsdf.continueProb; lightBsdfDirPdf *= lightContProb; lightBsdfRevPdf *= lightContProb; Real geometryTerm = cosAtLight * cosAtCamera / dist2; if (cmp(geometryTerm) < 0) return res; Real cameraBsdfDirPdfArea = pdfWtoA(cameraBsdfDirPdf , dist , cosAtLight); Real lightBsdfDirPdfArea = pdfWtoA(lightBsdfDirPdf , dist , cosAtCamera); res = (cameraBsdfFactor | lightBsdfFactor) * geometryTerm; if (res.isBlack() || scene.occluded(hitPos , dir , hitPos + dir * dist)) return Color3(0); Real wLight = mis(cameraBsdfDirPdfArea) * (lightState.dVCM + mis(lightBsdfRevPdf) * lightState.dVC); Real wCamera = mis(lightBsdfDirPdfArea) * (cameraState.dVCM + mis(cameraBsdfRevPdf) * cameraState.dVC); Real weight = 1.f / (wLight + 1.f + wCamera); return res * weight; }
float Surfel::ExpressiveParameters::boost(const Color3& diffuseReflectivity) const { // Avoid computing the HSV transform in the common case if (unsaturatedMaterialBoost == saturatedMaterialBoost) { return unsaturatedMaterialBoost; } const float m = diffuseReflectivity.max(); const float saturation = (m == 0.0f) ? 0.0f : ((m - diffuseReflectivity.min()) / m); return lerp(unsaturatedMaterialBoost, saturatedMaterialBoost, saturation); }
/** * Raytraces some portion of the scene. Should raytrace for about * max_time duration and then return, even if the raytrace is not copmlete. * The results should be placed in the given buffer. * @param buffer The buffer into which to place the color data. It is * 32-bit RGBA (4 bytes per pixel), in row-major order. * @param max_time, If non-null, the maximum suggested time this * function raytrace before returning, in seconds. If null, the raytrace * should run to completion. * @return true if the raytrace is complete, false if there is more * work to be done. */ bool Raytracer::raytrace( unsigned char *buffer, real_t* max_time ) { // TODO Add any modifications to this algorithm, if needed. static long start_time; // used to show how long time ray tracing cost if (0 == current_row) start_time = clock(); static const size_t PRINT_INTERVAL = 64; // the time in milliseconds that we should stop unsigned int end_time = 0; bool is_done = false; if ( max_time ) { // convert duration to milliseconds unsigned int duration = (unsigned int) ( *max_time * 1000 ); end_time = SDL_GetTicks() + duration; } // until time is up, run the raytrace. we render an entire row at once // for simplicity and efficiency. for ( ; !max_time || end_time > SDL_GetTicks(); ++current_row ) { if ( current_row % PRINT_INTERVAL == 0 ) { printf( "Raytracing (row %u)...\n", current_row ); } // we're done if we finish the last row is_done = current_row == height; // break if we finish if ( is_done ) break; for ( size_t x = 0; x < width; ++x ) { // trace a pixel Color3 color = trace_pixel( scene, x, current_row, width, height ); // write the result to the buffer, always use 1.0 as the alpha color.to_array( &buffer[4 * ( current_row * width + x )] ); } } if ( is_done ) { printf( "Done raytracing!\n" ); printf( "Used %d milliseconds.\n", clock()-start_time ); } return is_done; }
void PS3GCMCGEffect::setUniform(const Color3& uniformData, const char* uniformName) const { { CGparameter parameter = cellGcmCgGetNamedParameter(vertexProgram_, uniformName); if (parameter) { cellGcmSetVertexProgramParameter(parameter, uniformData.valuePtr()); } } { CGparameter parameter = cellGcmCgGetNamedParameter(fragmentProgram_, uniformName); if (parameter) { cellGcmSetFragmentProgramParameter(fragmentProgram_, parameter, uniformData.valuePtr(), fragmentProgramOffset_); } } }
bool Raytracer::scatter(const SurfaceSample& s, Photon* p) const { bool scatter = false; float t = _random.uniform(0, 1); // Check Impulses SuperBSDF::Ref bsdf = s.material->bsdf(); SmallArray<SuperBSDF::Impulse, 3> impulseArray; bsdf->getImpulses(s.shadingNormal, s.texCoord, p->direction, impulseArray); // todo: check p.direction Color3 impulseSum; for (int i = 0; i < impulseArray.size(); ++i) { if (impulseArray[i].coefficient.average() < 0) { int sures = 234; } //t -= impulseArray[i].coefficient.average(); impulseSum += impulseArray[i].coefficient; if (t - impulseArray[i].coefficient.average() < 0) { scatter = true; p->direction = impulseArray[i].w; p->power = p->power * t / impulseArray[i].coefficient.average(); check(p->power.average()); break; } } // Check Diffuse if (!scatter) { const Component4 lambertian = bsdf->lambertian(); //t - (s.lambertianReflect * (1 - impulseSum.average())).average(); if (t - (s.lambertianReflect * (1 - impulseSum.average())).average() < 0) { scatter = true; p->direction = Vector3::cosHemiRandom(s.shadingNormal); //p->power = p->power * (t / (s.lambertianReflect * (1 - impulseSum.average())).average()); p->power = p->power * (t / (s.lambertianReflect.average()));// * (1 - impulseSum.average())).average()); check(p->power.average()); } } return scatter; }
ustring sample (const Vec3 &Ng, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, float randu, float randv, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, float &pdf, Color3 &eval) const { Vec3 R, dRdx, dRdy; Vec3 T, dTdx, dTdy; bool inside; fresnel_dielectric(m_eta, m_N, omega_out, domega_out_dx, domega_out_dy, R, dRdx, dRdy, T, dTdx, dTdy, inside); if (!inside) { pdf = 1; eval.setValue(1.0f, 1.0f, 1.0f); omega_in = T; domega_in_dx = dTdx; domega_in_dy = dTdy; } return Labels::TRANSMIT; }
ustring sample(const Vec3 &Ng, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, float randu, float randv, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, float &pdf, Color3 &eval) const { // we are viewing the surface from the right side - send a ray out with cosine // distribution over the hemisphere sample_cos_hemisphere(m_N, omega_out, randu, randv, omega_in, pdf); if (Ng.dot(omega_in) > 0) { // TODO: account for sheen when sampling float cosNO = m_N.dot(omega_out); float sinNO2 = 1 - cosNO * cosNO; float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0; eval.setValue(westin, westin, westin); // TODO: find a better approximation for the diffuse bounce domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dx *= 125; domega_in_dy *= 125; } else { pdf = 0; } return Labels::REFLECT; }
/** * @brief * Set color */ void ImagePalette::SetColor(uint32 nIndex, const Color3 &cColor) { // Do we have to resize the palette? if (nIndex >= m_nColors) Resize(nIndex); // Set color if (m_pData) { m_pData[nIndex*3+0] = cColor.GetRInt(); m_pData[nIndex*3+1] = cColor.GetGInt(); m_pData[nIndex*3+2] = cColor.GetBInt(); } // Rebuild color index RebuildColorIndex(); }
Material::Ref createMaterial(const ArticulatedModel::Preprocess& preprocess) const { debugPrintf("Creating material %s...", name.c_str()); Material::Specification spec; if ((diffuseMap != "") && ! preprocess.stripMaterials) { Texture::Specification s; s.dimension = Texture::DIM_2D_NPOT; // If we turn this off, the BSDF just does it anyway s.preprocess.computeMinMaxMean = true; s.settings.maxAnisotropy = 2.0f; s.filename = diffuseMap; spec.setLambertian(s); } else { spec.setLambertian(diffuseConstant); } // Assume in air spec.setEta(max(1.0f, eta), 1.0f); // OBJ models are way too specular and not shiny enough spec.setSpecular(specularConstant.pow(9.0f) * 0.4f); spec.setGlossyExponentShininess(shininess * 100.0f); // spec.setBump(bumpMap); Material::Ref m = Material::create(spec); debugPrintf("Done\n"); return m; }
bool BidirPathTracing::sampleScattering(BSDF& bsdf , const Vector3& hitPos , BidirPathState& pathState) { Real bsdfDirPdf , cosWo; int sampledBSDFType; Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() , pathState.dir , bsdfDirPdf , cosWo , &sampledBSDFType); if (bsdfFactor.isBlack()) return 0; Real bsdfRevPdf = bsdfDirPdf; if ((sampledBSDFType & BSDF_SPECULAR) == 0) bsdfRevPdf = bsdf.pdf(scene , pathState.dir , 1); Real contProb = bsdf.continueProb; if (rng.randFloat() > contProb) return 0; bsdfDirPdf *= contProb; bsdfRevPdf *= contProb; // Partial sub-path MIS quantities // the evaluation is completed when the actual hit point is known! // i.e. after tracing the ray, out of the procedure if (sampledBSDFType & BSDF_SPECULAR) { pathState.specularVertexNum++; pathState.dVCM = 0.f; pathState.dVC *= mis(cosWo); } else { pathState.specularPath &= 0; pathState.dVC = mis(1.f / bsdfDirPdf) * (pathState.dVCM + pathState.dVC * mis(bsdfRevPdf)); pathState.dVCM = mis(1.f / bsdfDirPdf); } pathState.origin = hitPos; pathState.throughput = (pathState.throughput | bsdfFactor) * (cosWo / bsdfDirPdf); return 1; }
void Raytracer::trace_packet(PacketRegion region, float refractive, unsigned char *buffer) { Int2 ll = region.ll; Int2 lr = region.lr; Int2 ul = region.ul; Int2 ur = region.ur; IsectInfo infos[rays_per_packet]; bool intersected[rays_per_packet]; Packet packet; get_viewing_frustum(ll, lr, ul, ur, packet.frustum); Vector3 eye = scene->camera.get_position(); Int2 pixels[rays_per_packet]; int r = 0; // counter for rays in packet for (int y = ll.y; y <= ul.y; y++) { for (int x = ll.x; x <= lr.x; x++) { Int2 pixel(x, y); packet.rays[r].eye = eye; packet.rays[r].dir = get_viewing_ray(pixel); pixels[r] = pixel; intersected[r] = false; r++; } } for (size_t i = 0; i < scene->num_geometries(); i++) { scene->get_geometries()[i]->intersect_packet(packet, infos, intersected); } for (int i = 0; i < rays_per_packet; i++) { if (intersected[i]) { Color3 color = trace_pixel_end(0, packet.rays[i], refractive, infos[i]); color.to_array(&buffer[4 * (pixels[i].y * width + pixels[i].x)]); } else { Color3 color = scene->background_color; color.to_array(&buffer[4 * (pixels[i].y * width + pixels[i].x)]); } } }
Color3 getPhong(const Vector3& p , const Vector3& visionDir , const Vector3& normal , const Vector3& lightSourcePos , const Color3& lightIntensity , Geometry* obj , const Real& directCoe) { Vector3 lightDir = lightSourcePos - p; lightDir.normalize(); Vector3 reflecDir = normal * ((normal ^ lightDir) * 2.0) - lightDir; reflecDir.normalize(); Color3 diffuseIntensity = getDiffuse(lightDir , normal , lightIntensity , obj->get_diffuse_color(p)); Color3 specularIntensity = getSpecular(reflecDir , visionDir , lightIntensity , obj->get_material().specular); Color3 ambientIntensity = getAmbient(lightIntensity , obj->get_material().ambient); Color3 res = (diffuseIntensity + specularIntensity) * directCoe + ambientIntensity; res.clamp(); return res; }
/** * @brief get material property to be added to the mesh */ Niflib::NiPropertyRef getMatProp(){ using namespace Niflib; NiMaterialPropertyRef matPropRef = new NiMaterialProperty; matPropRef->SetName("01 - Default"); //set base nif colours Color3 colour; colour.Set(0.588, 0.588, 0.588); matPropRef->SetAmbientColor(colour); matPropRef->SetDiffuseColor(colour); colour.Set(0.9, 0.9, 0.9); matPropRef->SetSpecularColor(colour); colour.Set(0, 0, 0); matPropRef->SetEmissiveColor(colour); return DynamicCast<NiProperty>( matPropRef ); }
bool ShadingSystemImpl::set_colorspace (ustring colorspace) { for (int i = 0; colorSystems[i].name; ++i) { if (colorspace == colorSystems[i].name) { m_Red.setValue (colorSystems[i].xRed, colorSystems[i].yRed, 0.0f); m_Green.setValue (colorSystems[i].xGreen, colorSystems[i].yGreen, 0.0f); m_Blue.setValue (colorSystems[i].xBlue, colorSystems[i].yBlue, 0.0f); m_White.setValue (colorSystems[i].xWhite, colorSystems[i].yWhite, 0.0f); // set z values to normalize m_Red[2] = 1.0f - (m_Red[0] + m_Red[1]); m_Green[2] = 1.0f - (m_Green[0] + m_Green[1]); m_Blue[2] = 1.0f - (m_Blue[0] + m_Blue[1]); m_White[2] = 1.0f - (m_White[0] + m_White[1]); const Color3 &R(m_Red), &G(m_Green), &B(m_Blue), &W(m_White); // xyz -> rgb matrix, before scaling to white. Color3 r (G[1]*B[2] - B[1]*G[2], B[0]*G[2] - G[0]*B[2], G[0]*B[1] - B[0]*G[1]); Color3 g (B[1]*R[2] - R[1]*B[2], R[0]*B[2] - B[0]*R[2], B[0]*R[1] - R[0]*B[1]); Color3 b (R[1]*G[2] - G[1]*R[2], G[0]*R[2] - R[0]*G[2], R[0]*G[1] - G[0]*R[1]); Color3 w (r.dot(W), g.dot(W), b.dot(W)); // White scaling factor if (W[1] != 0.0f) // divide by W[1] to scale luminance to 1.0 w *= 1.0f/W[1]; // xyz -> rgb matrix, correctly scaled to white. r /= w[0]; g /= w[1]; b /= w[2]; m_XYZ2RGB = Matrix33 (r[0], g[0], b[0], r[1], g[1], b[1], r[2], g[2], b[2]); m_RGB2XYZ = m_XYZ2RGB.inverse(); m_luminance_scale = Color3 (m_RGB2XYZ[0][1], m_RGB2XYZ[1][1], m_RGB2XYZ[2][1]); // Precompute a table of blackbody values m_blackbody_table.clear (); float lastT = 0; for (int i = 0; lastT <= BB_MAX_TABLE_RANGE; ++i) { float T = powf (float(i), BB_TABLE_XPOWER) * BB_TABLE_SPACING + BB_DRAPER; lastT = T; bb_spectrum spec (T); Color3 rgb = XYZ_to_RGB (spectrum_to_XYZ (spec)); clamp_zero (rgb); rgb = colpow (rgb, 1.0f/BB_TABLE_YPOWER); m_blackbody_table.push_back (rgb); // std::cout << "Table[" << i << "; T=" << T << "] = " << rgb << "\n"; } // std::cout << "Made " << m_blackbody_table.size() << " table entries for blackbody\n"; #if 0 // Sanity checks std::cout << "m_XYZ2RGB = " << m_XYZ2RGB << "\n"; std::cout << "m_RGB2XYZ = " << m_RGB2XYZ << "\n"; std::cout << "m_luminance_scale = " << m_luminance_scale << "\n"; #endif return true; } } return false; }
// Raytraces some portion of the scene bool Raytracer::raytrace( unsigned char *buffer, real_t* max_time ) { static const size_t PRINT_INTERVAL = 64; unsigned int end_time = 0; bool is_done; if ( max_time ) { // convert duration to milliseconds unsigned int duration = (unsigned int) ( *max_time * 1000 ); end_time = SDL_GetTicks() + duration; } // until time is up, run the raytrace. we render an entire row at once for ( ; !max_time || end_time > SDL_GetTicks(); ++current_row ) { if ( current_row % PRINT_INTERVAL == 0 ) { printf( "Raytracing (row %u)...\n", current_row ); } // we're done if we finish the last row is_done = current_row == height; if ( is_done ) break; for ( size_t x = 0; x < width; ++x ) { // trace a pixel Color3 color = trace_pixel( scene, x, current_row, width, height ); color.to_array( &buffer[4 * ( current_row * width + x )] ); } } if ( is_done ) { printf( "Done raytracing!\n" ); } return is_done; }
static Color3 directIllumination(Scene& scene , Intersection& inter , RNG& rng , const Vector3& visionDir) { Color3 res = Color3(0.0 , 0.0 , 0.0); Vector3 lightDir; Real cosine; Color3 brdf; Ray ray; BSDF bsdf(visionDir , inter , scene); int N = 1; for (int i = 0; i < N; i++) { int k = rand() % scene.lights.size(); AbstractLight *l = scene.lights[k]; Vector3 dirToLight; Real dist , directPdf; Color3 illu = l->illuminance(scene.sceneSphere , inter.p , rng.randVector3() , dirToLight , dist , directPdf); illu = illu / (directPdf / scene.lights.size()); if (scene.occluded(inter.p + dirToLight * EPS , dirToLight , inter.p + dirToLight * (inter.t - EPS))) continue; Real bsdfPdf; brdf = bsdf.f(scene , dirToLight , cosine , &bsdfPdf); if (brdf.isBlack()) continue; res = res + (illu | brdf) * (cosine / bsdfPdf); } res = res / N; return res; }
Radiance3 RayTracer::L_scatteredDirect(const shared_ptr<Surfel>& surfel, const Vector3& wo, Random& rnd) const { //Downcast to universalSurfel to allow getting lambertianReflectivity (Not used now) const shared_ptr<UniversalSurfel>& u = dynamic_pointer_cast<UniversalSurfel>(surfel); debugAssertM(notNull(u), "Encountered a Surfel that was not a UniversalSurfel"); Radiance3 L(0,0,0); //For each light, compute the scatteredRadiance and sum them for (int i = 0; i < m_lighting->lightArray.size(); ++i){ const shared_ptr<Light> light(m_lighting->lightArray[i]); Vector3 Y = light->position().xyz(); Vector3 X = u->position; //Distance from light source to surface. Compute Birandiance using this. Vector3 distance = Y - X; //Computes stuff necessary for visibility function Vector3 wi = distance.direction(); Vector3 n = u->shadingNormal; //Check visibility if ((wi.dot(n) > 0) && (wo.dot(n) > 0) && light->inFieldOfView(distance)){ //Casting shadow ray from light source to surfel. To avoid intersecting the original surfel, bump the light a bit Color3 visibility = visiblePercentage(G3D::Ray(Y,-wi), light, distance.magnitude() - 0.1); //Add direct ilumination when visible, multiply biranciance by partial coverage if (!visibility.isZero()){ Biradiance3 Bi = light->bulbPower()/(4.0*G3D::pi()*square(distance.magnitude())); //Unit: W/m^2 L += Bi * (u->finiteScatteringDensity(wi,wo)/G3D::pi()) * abs(wi.dot(n)) * visibility; //Commented out, used when assuming Lambertian surface //L += Bi * (u->lambertianReflectivity/G3D::pi()) * abs(wi.dot(n)); } } } //Set the pixel values greater than one to one. return L.clamp(0,1); }
void PrimitivesExample::drawEvent() { GL::defaultFramebuffer.clear( GL::FramebufferClear::Color|GL::FramebufferClear::Depth); _shader.setLightPosition({7.0f, 5.0f, 2.5f}) .setLightColor(Color3{1.0f}) .setDiffuseColor(_color) .setAmbientColor(Color3::fromHsv({_color.hue(), 1.0f, 0.3f})) .setTransformationMatrix(_transformation) .setNormalMatrix(_transformation.rotationScaling()) .setProjectionMatrix(_projection); _mesh.draw(_shader); swapBuffers(); }
ustring sample (const Vec3 &Ng, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, float randu, float randv, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, float &pdf, Color3 &eval) const { // we are viewing the surface from the right side - send a ray out with cosine // distribution over the hemisphere sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf); if (Ng.dot(omega_in) > 0) { eval.setValue(pdf, pdf, pdf); // TODO: find a better approximation for the diffuse bounce domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx; domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy; domega_in_dx *= 125; domega_in_dy *= 125; } else pdf = 0; return Labels::REFLECT; }
ustring sample(const Vec3 &Ng, const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy, float randu, float randv, Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy, float &pdf, Color3 &eval) const { float cosNO = m_N.dot(omega_out); if (cosNO > 0) { domega_in_dx = domega_out_dx; domega_in_dy = domega_out_dy; Vec3 T, B; make_orthonormals(omega_out, T, B); float phi = 2 * (float) M_PI * randu; float cosTheta = powf(randv, 1 / (m_invroughness + 1)); float sinTheta2 = 1 - cosTheta * cosTheta; float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; omega_in = (cosf(phi) * sinTheta) * T + (sinf(phi) * sinTheta) * B + (cosTheta) * omega_out; if (Ng.dot(omega_in) > 0) { // common terms for pdf and eval float cosNI = m_N.dot(omega_in); // make sure the direction we chose is still in the right hemisphere if (cosNI > 0) { pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness); pdf = (m_invroughness + 1) * pdf; eval.setValue(pdf, pdf, pdf); // Since there is some blur to this reflection, make the // derivatives a bit bigger. In theory this varies with the // exponent but the exact relationship is complex and // requires more ops than are practical. domega_in_dx *= 10; domega_in_dy *= 10; } } } return Labels::REFLECT; }
void PhotonIntegrator::buildPhotonMap(Scene& scene) { if (scene.lights.size() <= 0) return; causticPhotons.clear(); indirectPhotons.clear(); bool causticDone = 0 , indirectDone = 0; int nShot = 0; bool specularPath; int nIntersections; Intersection inter; Real lightPickProb = 1.f / scene.lights.size(); while (!causticDone || !indirectDone) { nShot++; /* generate initial photon ray */ int k = (int)(rng.randFloat() * scene.lights.size()); Vector3 lightPos , lightDir; Real emissionPdf , directPdfArea , cosAtLight; Color3 alpha; AbstractLight *l = scene.lights[k]; alpha = l->emit(scene.sceneSphere , rng.randVector3() , rng.randVector3() , lightPos , lightDir , emissionPdf , &directPdfArea , &cosAtLight); alpha = alpha * cosAtLight / (emissionPdf * lightPickProb); Ray photonRay(lightPos , lightDir); if (!alpha.isBlack()) { specularPath = 1; nIntersections = 0; Geometry *g = scene.intersect(photonRay , inter); while (g != NULL && inter.matId > 0) { BSDF bsdf(-photonRay.dir , inter , scene); nIntersections++; bool hasNonSpecular = (cmp(bsdf.componentProb.diffuseProb) > 0 || cmp(bsdf.componentProb.glossyProb) > 0); if (hasNonSpecular) { Photon photon(inter.p , -photonRay.dir , alpha); if (specularPath && nIntersections > 1) { if (!causticDone) { causticPhotons.push_back(photon); if (causticPhotons.size() == nCausticPhotons) { causticDone = 1; nCausticPaths = nShot; causticMap = new KdTree<Photon>(causticPhotons); } } } else { if (nIntersections > 1 && !indirectDone) { indirectPhotons.push_back(photon); if (indirectPhotons.size() == nIndirectPhotons) { indirectDone = 1; nIndirectPaths = nShot; indirectMap = new KdTree<Photon>(indirectPhotons); } } } } if (nIntersections > maxPathLength) break; /* find new photon ray direction */ /* handle specular reflection and transmission first */ Real pdf , cosWo; int sampledType; Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() , photonRay.dir , pdf , cosWo , &sampledType); if (bsdfFactor.isBlack()) break; if (sampledType & BSDF_NON_SPECULAR) specularPath = 0; // Russian Roulette Real contProb = bsdf.continueProb; if (cmp(contProb - 1.f) < 0) { if (cmp(rng.randFloat() - contProb) > 0) break; pdf *= contProb; } alpha = (alpha | bsdfFactor) * (cosWo / pdf); photonRay.origin = inter.p + photonRay.dir * EPS; photonRay.tmin = 0.f; photonRay.tmax = INF; g = scene.intersect(photonRay , inter); } } } }
Color3 PhotonIntegrator::raytracing(const Ray& ray , int dep) { Color3 res = Color3(0.0 , 0.0 , 0.0); if (dep > 2) return res; Geometry *g = NULL; Intersection inter; Ray reflectRay , transRay; g = scene.intersect(ray , inter); if (g == NULL) return res; if (inter.matId < 0) { AbstractLight *l = scene.lights[-inter.matId - 1]; return l->getIntensity() * 100.f; } res = res + directIllumination(scene , inter , rng , -ray.dir); res = res + estimate(indirectMap , nIndirectPaths , knnPhotons , scene , inter , -ray.dir , maxSqrDis); // final gathering is too slow! //res = res + finalGathering(indirectMap , scene , inter , rng , -ray.dir , 50 , knnPhotons , maxSqrDis); res = res + estimate(causticMap , nCausticPaths , knnPhotons , scene , inter , -ray.dir , maxSqrDis); BSDF bsdf(-ray.dir , inter , scene); Real pdf , cosWo; int sampledType; Ray newRay; Color3 bsdfFactor = bsdf.sample(scene , rng.randVector3() , newRay.dir , pdf , cosWo , &sampledType); if (bsdfFactor.isBlack()) return res; // Russian Roulette Real contProb = bsdf.continueProb; if (cmp(contProb - 1.f) < 0) { if (cmp(rng.randFloat() - contProb) > 0) return res; pdf *= contProb; } newRay.origin = inter.p + newRay.dir * EPS; newRay.tmin = 0; newRay.tmax = INF; Color3 contrib = raytracing(newRay , dep + 1); res = res + (contrib | bsdfFactor) * (cosWo / pdf); return res; }
static Color3 estimate(KdTree<Photon> *map , int nPaths , int knn , Scene& scene , Intersection& inter , const Vector3& wo , Real maxSqrDis) { Color3 res = Color3(0.0 , 0.0 , 0.0); if (map == NULL) return res; Photon photon; photon.pos = inter.p; ClosePhotonQuery query(knn , 0); Real searchSqrDis = maxSqrDis; Real msd; /* max square distance */ while (query.kPhotons.size() < knn) { msd = searchSqrDis; query.init(msd); map->searchKnn(0 , photon.pos , query); searchSqrDis *= 2.0; } int nFoundPhotons = query.kPhotons.size(); if (nFoundPhotons == 0) return res; Vector3 nv; if (cmp(wo ^ inter.n) < 0) nv = -inter.n; else nv = inter.n; Real scale = 1.0 / (PI * msd * nFoundPhotons); BSDF bsdf(wo , inter , scene); Real cosTerm , pdf; for (int i = 0; i < nFoundPhotons; i++) { /* Real k = kernel(kPhotons[i].photon , p , msd); k = 1.0 / PI; Real scale = k / (nPaths * msd); */ if (cmp(nv ^ query.kPhotons[i].photon->wi) > 0) { Color3 brdf = bsdf.f(scene , query.kPhotons[i].photon->wi , cosTerm , &pdf); if (brdf.isBlack()) continue; res = res + (brdf | query.kPhotons[i].photon->alpha) * (cosTerm * scale / pdf); } else { Vector3 wi(query.kPhotons[i].photon->wi); wi.z *= -1.f; Color3 brdf = bsdf.f(scene , wi , cosTerm , &pdf); if (brdf.isBlack()) continue; res = res + (brdf | query.kPhotons[i].photon->alpha) * (cosTerm * scale / pdf); } } return res; }