//Ray Tracing glm::vec3 RayTracing::rayTracing(Ray ray, int depth, float ior){ glm::vec3 normal; glm::vec3 point; glm::vec3 color(0); //Objecto mais proximo Object * oB = Scene::getInstance().GetNearestObject(ray, point, normal); //Se nao existir uma intercepcao deve ser dada a cor do background if (oB == NULL) return Scene::getInstance().GetBckgColor(); //Se ainda nao atingimos o limite temos de calcular os raios secundarios if (depth < MAX_DEPTH){ //Refleccao glm::vec3 r1Color; calculateReflection(ray, oB, point, normal, depth, ior, r1Color); //Refraccao glm::vec3 r2Color; calculateRefraction(ray, oB, point, normal, depth, ior, r2Color); color += r1Color + r2Color; } //Cor final return color + shade(oB, normal, point); }
glm::vec3 MonteCarloRayTracer::iterateRay(Ray &ray, const Octree &tree, int depth, bool kill) { IntersectionPoint ip; glm::vec3 color(0.0f); glm::vec3 rad(0.0f); if(tree.intersect(ray, ip)) { if (ip.getMaterial().getMaterialType() == LIGHT) { return ip.getMaterial().getDiffuseColor(); } // Do russian roulette to terminate rays. float russianRandom = _rgen.nextFloat(); float killRange = 0.98f; if (killRange < russianRandom) kill = true; if(depth < _maxDepth || !kill) { rad = ip.getMaterial().getEmission(); bool isInsideObj = ( glm::dot(ray.getDirection(), ip.getNormal() ) > 0.0f) ? true : false; if(isInsideObj) { // If coming from inside obj going out into air (refraction needed) //std::cout<<"No!!!\n"; float n2overn1 = REFRACTION_AIR / ray.getRefractionIndex(); float critical_angle = asin(n2overn1); float cosIn = glm::dot(ip.getNormal(), -ray.getDirection()); if(acos(cosIn) > critical_angle) { // Total internal reflection ip.setNormal(-1.0f*ip.getNormal()); Ray new_ray = calculateReflection(ray, ip); rad += ip.getMaterial().getDiffuseColor()*iterateRay(new_ray, tree, ++depth, kill); } else { // Calc and spawn refracted and reflected rays Material m = ip.getMaterial(); m.setRefractionIndex(REFRACTION_AIR); ip.setMaterial(m); Ray new_ray = calculateRefraction(ray, ip); rad += (1.0f-ip.getMaterial().getOpacity()) * ip.getMaterial().getDiffuseColor()*iterateRay(new_ray, tree, ++depth, kill); new_ray = calculateReflection(ray, ip); rad += ip.getMaterial().getOpacity() * ip.getMaterial().getDiffuseColor()*iterateRay(new_ray, tree, ++depth, kill); } } else { // Check for opacity (-> refraction + reflection), otherwise just reflect glm::vec3 origin = ip.getPoint(); // // Calc vectors for plane of intersection point // glm::vec3 a = glm::vec3(1,0,0)*ip.getNormal() - origin; // glm::vec3 b = glm::cross(a,ip.getNormal()); // // Diffuse refl in random direction // float phi = glm::linearRand(0.0f,2.0f*PI); // float rand = _rgen.nextFloat(); // glm::vec3 diffuse_dir = a*rand*glm::cos(phi) + b*rand*glm::sin(phi) + ip.getNormal()*glm::sqrt(1.0f-rand*rand); // float x1 = _rgen.nextFloat(), x2 = , x3 = _rgen.nextFloat(); glm::vec3 diffuse_dir = glm::vec3(2.f * _rgen.nextFloat() - 1.f, 2.f * _rgen.nextFloat() - 1.f, 2.f * _rgen.nextFloat() - 1.f); glm::normalize(diffuse_dir); // float x1, x2, S; // do { // x1 = 2.0f * _rgen.nextFloat() - 1.0f; // x2 = 2.0f * _rgen.nextFloat() - 1.0f; // S = x1 * x1 + x2 * x2; // } while (S > 1.f); // glm::vec3 diffuse_dir = glm::vec3(2.0f * x1 * sqrt(1.0f - S), // 2.0f * x2 * sqrt(1.0f - S), // abs(1.0f - 2.0f * S)); if (glm::dot(diffuse_dir, ip.getNormal()) < 0) { diffuse_dir = -diffuse_dir; } // Not sure if the diffuse dir is in sphere or half-sphere. Seems like // sphere. // Perfect refl ray Ray refl_ray = calculateReflection(ray,ip); // Interpolate between diffuse and perf refl to get new reflected ray float t = 0.f; // ip.getMaterial().getSpecular(); glm::vec3 dir = glm::normalize(diffuse_dir*(1.0f-t) + refl_ray.getDirection()*t); refl_ray = Ray(origin + dir * 0.0001f, dir); if(ip.getMaterial().getOpacity() < 1.f) { // Do refraction + reflection //std::cout<<"Should not happen yet!\n"; float n2overn1 = ip.getMaterial().getRefractionIndex() / REFRACTION_AIR; float critical_angle = asin(n2overn1); float cosIn = glm::dot(ip.getNormal(), -ray.getDirection()); if(acos(cosIn) < critical_angle) { // Refraction + reflection Ray refr_ray = calculateRefraction(ray, ip); rad += /*(1.0f-ip.getMaterial().getOpacity())*/0.5f*ip.getMaterial().getDiffuseColor()*iterateRay(refr_ray, tree, ++depth, kill); rad += /*ip.getMaterial().getOpacity()*/0.5f*ip.getMaterial().getDiffuseColor()*iterateRay(refl_ray, tree, ++depth, kill); } } else { // Only reflection Ray new_ray = calculateReflection(ray, ip); rad +=ip.getMaterial().getDiffuseColor() * iterateRay(refl_ray, tree, ++depth, kill); } } } else { addToMeanDepth(depth); //rad += ip.getMaterial().getDiffuseColor(); } } return rad; }