/// <summary> /// Determina si hay interseccion entre un rayo y un modelo determinado. /// En la estructura info se devuelve la informacion relacionada al punto de interseccion. /// </summary> /// modificado public static bool Intersect(Ray r, Model model, out IntersectionInfo info) { bool intersect; switch (model) { case Model.Cube: intersect = IntersectCube(r, out info); break; case Model.Cone: intersect = IntersectCone(r, out info); break; case Model.Cylinder: intersect = IntersectCylinder(r, out info); break; case Model.Disk: intersect = IntersectDisk(r, out info); break; case Model.Plane: intersect = IntersectPlane(r, out info); break; case Model.Sphere: intersect = IntersectSphere(r, out info); break; default: throw new NotImplementedException(); } if (intersect) info.TextureCoordenates = model.TextureCoordenates(info.Position); return intersect; }
private static bool Intersect2DModel(Ray r, out IntersectionInfo info, Func<vec3, bool> func) { info = new IntersectionInfo(); if (r.From.Y < 0 && r.Direction.Y > 0 && (func(info.Position = r.From + r.Direction*((0 - r.From.Y)/r.Direction.Y)))) { info.Normal = new vec3(0, -1, 0); return true; } if (r.From.Y > 0 && r.Direction.Y < 0 && (func(info.Position = r.From + r.Direction*((0 - r.From.Y)/r.Direction.Y)))) { info.Normal = new vec3(0, 1, 0); return true; } return false; }
//modificado para annadir el ModelGraphic a info private bool Intersect(Ray r, ModelGraphic model, out IntersectionInfo info) { if (Intersecter.Intersect(r, model.Model, out info)) { info.ModelGraphic = model; return true; } return false; }
//modificado para transformar la normal y la posicion del punto private bool Intersect(Ray r, TransformedGraphic graphic, out IntersectionInfo info) { Ray transformedRay = r.Transformed(graphic.Transform.Inverse); if (Intersect(transformedRay, graphic.Graphic, out info)) { info.Position = (vec3)(new vec4(info.Position, 1) * graphic.Transform); info.Normal = info.Normal * ((mat3x3)graphic.Transform); return true; } return false; }
//modificado escogia el color por la pos del punto private vec4 CalculateIlumination(IntersectionInfo info, Ray r, int depth) { Material material = info.ModelGraphic.Material; //Ver si el material es emisivo vec4 result = new vec4(); if (material is EmissiveMaterial) result = ((EmissiveMaterial)material).LightColor; //Ver si el material es bump if (material is BumpMaterial) { var image = material.Diffuse; int px = (int)(info.TextureCoordenates.X * (image.Width - 1)); int py = (int)(info.TextureCoordenates.Y * (image.Height - 1)); info.Normal = info.Normal + 10 * (vec3)((BumpMaterial)material).Normals[px, py]; } //Buscando el color en el punto (se puede variar el modo de Sampling) vec4 colorOfPoint = material.Diffuse.BilinearSample(info.TextureCoordenates.X, 1-info.TextureCoordenates.Y); ; //Aporte de la luz ambiental result += (1 - material.Translucence) * colorOfPoint * Scene.AmbientLight; #region Aporte de cada luz al punto foreach (var light in Lights) { Ray ray = Ray.FromTo(info.Position, light.Position); bool eclipsedLight = false; //Detectar si la luz es eclipsada por otro objeto foreach (var graphic in Scene.Graphics) { IntersectionInfo infoAux; if (Intersect(ray, graphic, out infoAux) && (infoAux.Position - ray.From).Length < (light.Position - ray.From).Length && (infoAux.ModelGraphic != light.ModelGraphic) && (infoAux.ModelGraphic != info.ModelGraphic)) { eclipsedLight = true; break; } } //Procesar el aporte de la luz si no esta eclipsada if (!eclipsedLight) { //este vector tiene la direccion desde el pto a la luz vec3 lightDirection = (light.Position - info.Position).Normalized; //Aporte de la reflexion difusa //la intensidad de la luz es directamente proporcional al coseno del angulo entre el rayo de luz y la normal result += PutInRange(light.Intensity * colorOfPoint * (vec3.dot(lightDirection, info.Normal))); //Aporte de la reflexion especular result += PutInRange(light.Intensity * colorOfPoint * (float)Math.Pow(vec3.dot(info.Normal, lightDirection - r.Direction), material.Shinness)); } } #endregion if (depth > 0) { //Aporte de la luz reflejada por otros objetos Ray reflectionRay = Ray.FromDirection(info.Position, r.Direction - 2 * vec3.dot(r.Direction, info.Normal) * info.Normal); vec4 reflectionColor = GetRayColor(reflectionRay, depth - 1, false); result += material.Reflectance * reflectionColor; //Aporte de la luz refractada if(material.Translucence > 0) { float desc = (float)(1 + (Math.Pow(vec3.dot(-1 * r.Direction, info.Normal), 2) - 1) / Math.Pow(material.Density, 2)); if (desc > 0) { vec3 refractionDirection = (r.Direction*(1f/material.Density)) + ((vec3.dot(-1 * r.Direction, info.Normal) * (1f / material.Density)) - (float) Math.Sqrt(desc))*info.Normal; Ray refractionRay = Ray.FromDirection(info.Position, refractionDirection); vec4 refractionColor = GetRayColor(refractionRay, depth - 1, false); result += material.Translucence *refractionColor; } } } return PutInRange(result); }
//modificado para annadir depthReflection y refle private vec4 GetRayColor(Ray r, int depth = 4, bool firstRay = true) { /// Variable para identificar el primer "hit" bool find = false; /// Interseccion mas cercana al punto de partida del rayo. IntersectionInfo nearest = new IntersectionInfo(); /// Para cada grafico en la escena foreach (var o in Scene.Graphics) { IntersectionInfo info; /// Si se intersecta if ((Intersect(r, o, out info)) && (!find || (info.Position - r.From).Length < (nearest.Position - r.From).Length) && ((info.Position - r.From).Length > 0.01f)) { nearest = info; find = true; } } if (find) { /// Aqui vendria el calculo de iluminacion para el punto de interseccion. return CalculateIlumination(nearest, r, depth); } if (firstRay) return BackColor.ToVec4(); return Color.Empty.ToVec4(); }
private static bool IntersectPlane(Ray r, out IntersectionInfo info) { //el disco esta en el plano XZ Func<vec3, bool> isInPlane = v => Math.Abs(v.X) <= 0.50001 && Math.Abs(v.Z) <= 0.50001; return Intersect2DModel(r, out info, isInPlane); }
private static bool IntersectSphere(Ray r, out IntersectionInfo info) { info = new IntersectionInfo(); //esfera con centro en (0, 0, 0) y radio 1 float a = 1; float b = 2 * (r.From.X * r.Direction.X + r.From.Y * r.Direction.Y + r.From.Z * r.Direction.Z); float c = r.From.X * r.From.X + r.From.Y * r.From.Y + r.From.Z * r.From.Z - 1; float t; if (FindSolution(a, b, c, out t)) { info.Position = r.From + r.Direction * t; info.Normal = info.Position; return true; } return false; }
private static bool IntersectDisk(Ray r, out IntersectionInfo info) { //el disco esta en el plano XZ Func<vec3, bool> isInDisk = v => v.X * v.X + v.Z * v.Z <= 1.00001; return Intersect2DModel(r, out info, isInDisk); }
private static bool IntersectCylinder(Ray r, out IntersectionInfo info) { info = new IntersectionInfo(); Func<vec3, bool> isInDisk = v => v.X * v.X + v.Z * v.Z <= 1.00001; // Top Intersection if (r.From.Y > 1 && r.Direction.Y < 0 && (isInDisk(info.Position = r.From + r.Direction * ((1 - r.From.Y) / r.Direction.Y)))) { info.Normal = new vec3(0, 1, 0); return true; } // Bottom Intersection if (r.From.Y < 0 && r.Direction.Y > 0 && (isInDisk(info.Position = r.From + r.Direction * ((0 - r.From.Y) / r.Direction.Y)))) { info.Normal = new vec3(0, -1, 0); return true; } float a = r.Direction.X * r.Direction.X + r.Direction.Z * r.Direction.Z; float b = 2 * (r.From.X * r.Direction.X + r.From.Z * r.Direction.Z); float c = r.From.X * r.From.X + r.From.Z * r.From.Z - 1; float t; if (FindSolution(a, b, c, out t)) { info.Position = r.From + r.Direction * t; if (0.00001 <= info.Position.Y && info.Position.Y <= 1.00001) //hay interseccion con las paredes { info.Normal = new vec3(info.Position.X, 0, info.Position.Z); return true; } } return false; }
/// modificado private static bool IntersectCube(Ray r, out IntersectionInfo info) { Func<vec3, bool> isInCube = v => v.X >= -0.00001 && v.X <= 1.00001 && v.Y >= -0.00001 && v.Y <= 1.00001 && v.Z >= -0.00001 && v.Z <= 1.00001; info = new IntersectionInfo(); // Front Intersection if (r.From.Z < 0 && r.Direction.Z > 0 && (isInCube(info.Position = r.From + r.Direction * ((0 - r.From.Z) / r.Direction.Z)))) { info.Position = new vec3(info.Position.X, info.Position.Y, 0); info.Normal = new vec3(0, 0, -1); return true; } // Back Intersection if (r.From.Z > 1 && r.Direction.Z < 0 && (isInCube(info.Position = r.From + r.Direction * ((1 - r.From.Z) / r.Direction.Z)))) { info.Position = new vec3(info.Position.X, info.Position.Y, 1); info.Normal = new vec3(0, 0, 1); return true; } // Left Intersection if (r.From.X < 0 && r.Direction.X > 0 && (isInCube(info.Position = r.From + r.Direction * ((0 - r.From.X) / r.Direction.X)))) { info.Position = new vec3(0, info.Position.Y, info.Position.Z); info.Normal = new vec3(-1, 0, 0); return true; } // Right Intersection if (r.From.X > 1 && r.Direction.X < 0 && (isInCube(info.Position = r.From + r.Direction * ((1 - r.From.X) / r.Direction.X)))) { info.Position = new vec3(1, info.Position.Y, info.Position.Z); info.Normal = new vec3(1, 0, 0); return true; } // Bottom Intersection if (r.From.Y < 0 && r.Direction.Y > 0 && (isInCube(info.Position = r.From + r.Direction * ((0 - r.From.Y) / r.Direction.Y)))) { info.Position = new vec3(info.Position.X, 0, info.Position.Z); info.Normal = new vec3(0, -1, 0); return true; } // Top Intersection if (r.From.Y > 1 && r.Direction.Y < 0 && (isInCube(info.Position = r.From + r.Direction * ((1 - r.From.Y) / r.Direction.Y)))) { info.Position = new vec3(info.Position.X, 1, info.Position.Z); info.Normal = new vec3(0, 1, 0); return true; } return false; }
/// <summary> /// Permite determinar si un rayo intersecta un grafico. /// En la variable info queda almacenada la informacion referente a la interseccion. /// </summary> private bool Intersect(Ray r, Graphic graphic, out IntersectionInfo info) { if (graphic is ModelGraphic) return Intersect(r, (ModelGraphic)graphic, out info); if (graphic is TransformedGraphic) return Intersect(r, (TransformedGraphic)graphic, out info); if (graphic is CSGGraphic) return Intersect(r, (CSGGraphic)graphic, out info); throw new NotSupportedException(); }
/// <summary> /// Permite determinar si un rayo intersecta un grafico CSG. /// En la variable info queda almacenada la informacion referente a la interseccion. /// </summary> private bool Intersect(Ray r, CSGGraphic graphic, out IntersectionInfo info) { throw new NotSupportedException(); }