Exemplo n.º 1
0
//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;
}