//====================================================================================================================== //== INTERSECT TREE - test l'intersection du rayon r avec un arbre de boîtes englobantes == //====================================================================================================================== public ResIntersect intersectTree(AABBTree tree, Ray r) { ResIntersect res; res.t = -1; res.sph = null; if (tree.leaf) { res = Intersect(r, tree.sph); } else { if (AABBoxIntersect(tree.box, r)) { ResIntersect res1 = intersectTree(tree.tree1, r); ResIntersect res2 = intersectTree(tree.tree2, r); if (res1.t != -1) { if (res2.t != -1) { if (res1.t < res2.t) { res = res1; } else { res = res2; } } else { res = res1; } } else if (res2.t != -1) { res = res2; } } } return(res); }
public ResIntersect Intersects(Ray r) { ResIntersect res = intersectTree(spheresTree, r); foreach (Sphere s in bigSpheres) { ResIntersect res2 = Intersect(r, s); if (res2.t != -1) { if (res.t == -1 || res2.t < res.t) { res.t = res2.t; res.sph = res2.sph; } } } return(res); }
//====================================================================================================================== //== DIRECT LIGHTING - renvoi la lumière directe reçue au point d'intersection du rayon == //====================================================================================================================== public Vector3 directLighting(Vector3 interPoint, Vector3 normal, ResIntersect resInter) { Vector3 directLight = new Vector3(0.0f, 0.0f, 0.0f); foreach (Sphere l in lights) { Vector3 lightNormal = Vector3.Normalize(Vector3.Subtract(interPoint, l.center)); Vector3 rdmDir = transformToNewONBase(randomDirectionOnHemisphere(), NewONBase(lightNormal)); Vector3 rdmPoint = Vector3.Add(l.center, Vector3.Multiply(rdmDir, l.radius + 0.1f)); Vector3 directionToLight = Vector3.Subtract(rdmPoint, interPoint); Ray ray = new Ray(interPoint, directionToLight); ResIntersect resInterL = Intersects(ray); if (!(resInterL.t != -1 && resInterL.t <= 1.0f && resInterL.sph.material.type != MaterialType.Light)) { directLight = Vector3.Add(directLight, Vector3.Multiply(powerReceived(directionToLight, l), lightEmmited(Vector3.Normalize(directionToLight), normal, resInter.sph))); } } return(directLight); }
//====================================================================================================================== //== RADIANCE - lance un rayon dans la scene et renvoi la couleur obtenue == //====================================================================================================================== public Vector3 Radiance(Ray ray, int rebound) { Vector3 color = new Vector3(0, 0, 0); if (rebound != 5) { ResIntersect resInter = Intersects(ray); if (resInter.t != -1) { Vector3 interPoint = Vector3.Add(ray.point, Vector3.Multiply(ray.direction, resInter.t)); Vector3 normal = Vector3.Subtract(interPoint, resInter.sph.center); normal = Vector3.Normalize(normal); interPoint = Vector3.Add(interPoint, Vector3.Multiply(normal, 0.1f)); Vector3 newDir; Ray reflection; switch (resInter.sph.material.type) { case MaterialType.Difuse: Vector3 directLight = directLighting(interPoint, normal, resInter); newDir = transformToNewONBase(randomDirectionOnHemisphere(), NewONBase(normal)); reflection = new Ray(interPoint, newDir); color = Vector3.Add(directLight, Vector3.Multiply(Radiance(reflection, ++rebound), lightEmmited(newDir, normal, resInter.sph))); break; case MaterialType.Mirror: newDir = Vector3.Add(Vector3.Multiply(2 * -Vector3.Dot(ray.direction, normal), normal), ray.direction); reflection = new Ray(interPoint, newDir); color = Vector3.Multiply(resInter.sph.material.albedo, Radiance(reflection, ++rebound)); break; case MaterialType.Light: color = Vector3.Divide(resInter.sph.material.albedo, 1000000); break; } } } return(color); }
//public Vector3 Radiance(Ray ray, int stop) public Vector3 Radiance(Ray ray, int stop, Tree arbre) { Vector3 color = new Vector3(0, 0, 0); float nb_rebond = 10.0f; //tant qu'on a pas eu 100 rebonds if (stop != 10) { //recherche d'intersection pour sphere //ResIntersect resInter = Intersects(ray); //recherche d'intersection pour sphere AVEC structure acceleratrice ResIntersect resInter = IntersectTree(arbre, ray); //si on a une intersection if (resInter.t != -1) { //interpoint, coordonnées du point t'intersection Vector3 interPoint = Vector3.Add(ray.point, Vector3.Multiply(ray.direction, resInter.t)); //normal, vecteur normal a la surface de la sphere Vector3 normal = Vector3.Subtract(interPoint, resInter.sph.center); normal = Vector3.Normalize(normal); //ajout du petit décalage pour ne pas avoir d'interesection d'un point d'une sphere avec un autre point de la sphere interPoint = Vector3.Add(interPoint, Vector3.Multiply(normal, 0.1f)); //selon le materiau switch (resInter.sph.material.type) { //DIFFUS case MaterialType.Difuse: //directionToLight, vecteur poitant vers la lumiere à partir du point d'intersection sur la sphere Vector3 directionToLight = Vector3.Subtract(light.origin, interPoint); //création d'un Rayon à partir de cette direction ray = new Ray(interPoint, directionToLight); //cherche s'il y a un obstacle entre la lumiere et le point de la sphere ResIntersect resInterL = Intersects(ray); //lightPower contiendra les albedo additionnés à chaque rebond Vector3 lightPower = new Vector3(0.0f, 0.0f, 0.0f); //s'il n'y a pas d'obstacle et s'il ne s'agit pas de la lampe if (!(resInterL.t != -1 && resInterL.t <= 1.0f && resInterL.sph.material.type != MaterialType.Light)) { lightPower = ReceiveLight(light, interPoint, resInter.sph); } //calcul des coordonnées d'un point d'une sphere fictive sur le point d'intersection de la shpere pour calculer une nouvelle direction Vector3 mini_sphere_coord = RandomVector(interPoint); //création d'une base à partir du vecteur normal au point d'intersection de la sphere Vector3 randVect = new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()); Vector3 xBase = Vector3.Cross(normal, randVect); Vector3 yBase = Vector3.Cross(normal, xBase); Vector3 zBase = normal; //calcul d'une nouvelle direction grace à la nouvelle base Vector3 newDirect = Vector3.Add(Vector3.Add(xBase * mini_sphere_coord.X, yBase * mini_sphere_coord.Y), zBase * mini_sphere_coord.Z); Vector3 normalNewDirect = Vector3.Normalize(newDirect); //dans la generation de la direction aléatoire du rebond, pour ne pas avoir de vecteur qui va dans la sphere if (Vector3.Dot(normalNewDirect, normal) < 0) { newDirect = -newDirect; } //création d'un nouveau rayon faire le prochain rebond Ray rebond = new Ray(interPoint, newDirect); //cumul des albedo de toutes les surfaces sur lesquelles on rebondit color = Vector3.Add(lightPower, Vector3.Multiply(Vector3.Dot(normalNewDirect, normal), Vector3.Add(resInter.sph.material.albedo, Radiance(rebond, ++stop, arbre)))); //division du cumul d'albedo par le nombre de rebond color = Vector3.Divide(color, nb_rebond); break; //MIRROIR case MaterialType.Mirror: //calcul de la nouvelle direction Vector3 newDir = Vector3.Add(Vector3.Multiply(2 * -Vector3.Dot(ray.direction, normal), normal), ray.direction); Ray reflection = new Ray(interPoint, newDir); color = Vector3.Multiply(resInter.sph.material.albedo, Radiance(reflection, ++stop, arbre)); break; case MaterialType.Light: color = resInter.sph.material.albedo; break; } } } return(color); }