public override bool IsHit(Ray ray, HitRecord record, float near, float far) { Vector newCenter; if (Velocity.IsBlack()) newCenter = Center; else { newCenter = this.Center + ray.Time * this.Velocity; } //e - c Vector eMinusC = ray.Start - newCenter; //d.(e-c) float dDotEMinusC = Vector.Dot3(ray.Direction, eMinusC); float dDotD = Vector.Dot3(ray.Direction, ray.Direction); //d.(e-c)^2 - (d.d)((e-c).(e-c) - R^2)) float discriminant = dDotEMinusC * dDotEMinusC - dDotD * (Vector.Dot3(eMinusC, eMinusC) - this.Radius * this.Radius); //Intersection occurs float t1 = 0, t2 = 0, first_t = 0; if (discriminant >= 0) { t1 = (-dDotEMinusC + (float)Math.Sqrt(discriminant)) / dDotD; t2 = (-dDotEMinusC - (float)Math.Sqrt(discriminant)) / dDotD; Vector diff; Vector worldCoords; if (t2 >= 0) first_t = t2; else if (t1 >= 0) first_t = t1; else return false; // t*d diff = ray.Direction * first_t; // e + t*d worldCoords = diff + ray.Start; float distance = diff.Magnitude3(); if (distance <= record.Distance && distance <= ray.MaximumTravelDistance) { if (ray.UseBounds) { float cameraOrthogonalDistance = Math.Abs(Vector.Dot3(diff, ray.CameraLookDirection)); if (cameraOrthogonalDistance > far && cameraOrthogonalDistance < near) { return false; } } record.T = first_t; record.HitPoint = ray.Start + diff; record.Distance = distance; record.Material = this.Material; record.SurfaceNormal = SurfaceNormal(record.HitPoint, ray.Direction); if (Material.TextureImage != null) { double cos = (record.HitPoint.z - newCenter.z) / Radius; if (cos < -1) cos = -1; else if (cos > 1) cos = 1; double theta = Math.Acos(cos); double phi = Math.Atan2(record.HitPoint.y - newCenter.y, record.HitPoint.x - newCenter.x); if (phi < 0) phi += 2 * Math.PI; float u = (float)(phi / (2 * Math.PI)); float v = (float)((Math.PI - theta) / Math.PI); //Console.WriteLine(this.textureWidth); //Console.WriteLine(this.Material.TextureImage.Height); //int i = (int)(u * (this.textureWidth - 1) + 0.5); //int j = (int)(v * (this.textureHeight - 1) + 0.5); record.TextureColor = this.Material.GetTexturePixelColor(u, v); } return true; } } return false; }
public override bool IsHit(Ray ray, HitRecord record, float near, float far) { throw new NotImplementedException(); }
private bool MakesShadow(Ray shadowRay, SceneLight light, int reflections, int refractions, float refractive, float time) { if (refractions > 5) return false; bool makesShadow = false; shadowRay.Time = time; float lightDistance = (light.Position - shadowRay.Start).Magnitude3(); shadowRay.MaximumTravelDistance = lightDistance; //////////////////////////////////////////////////////////////// HitRecord shadowRecord = new HitRecord(); foreach (SceneObject shadowObject in scene.Objects) { makesShadow = shadowObject.IsHit(shadowRay, shadowRecord, float.MinValue, float.MaxValue) || makesShadow; } if (makesShadow) { if (shadowRecord.Material.RefractionIndex.x != 0.0f) { Ray refractedShadow = CastRefractionRay(shadowRay, shadowRecord, refractive); refractive = shadowRecord.Material.RefractionIndex.x; makesShadow = MakesShadow(refractedShadow, light, reflections, refractions + 1, shadowRecord.Material.RefractionIndex.x, time); if (RenderingParameters.showMouse && makesShadow) { Console.WriteLine("Shadow made after getting out from traslucent material."); } return makesShadow; } else { if (RenderingParameters.showMouse) Console.WriteLine("Made shadow from " + shadowRecord.Material.Name); return true; } } return makesShadow; }
public override bool IsHit(Ray ray, HitRecord record, float near, float far) { //(d.h)h Vector dDotHTimesH = Vector.Dot3(ray.Direction, HeightDirection) * HeightDirection; Vector deltaP = ray.Start - this.BasePoint; Vector deltaPDotHTimesH = Vector.Dot3(deltaP, HeightDirection) * HeightDirection; Vector deltaPMinusdeltaPDotHTimesH = deltaP - deltaPDotHTimesH; Vector dMinusdDotHTimesH = ray.Direction - dDotHTimesH; float B = 2 * Vector.Dot3(dMinusdDotHTimesH, deltaPMinusdeltaPDotHTimesH); float A = Vector.Dot3(dMinusdDotHTimesH, dMinusdDotHTimesH); float C = Vector.Dot3(deltaPMinusdeltaPDotHTimesH, deltaPMinusdeltaPDotHTimesH) - this.Radius * this.Radius; Vector diff, worldCoords; float discriminant = B * B - 4 * A * C; float t1 = 0, t2 = 0, first_t = float.MaxValue; List<float> candidates = new List<float>(); IntersectionType intersectionType = IntersectionType.Cylinder; if (discriminant >= 0) { t1 = (-B - (float)Math.Sqrt(discriminant)) / (2 * A); t2 = (-B + (float)Math.Sqrt(discriminant)) / (2 * A); if (t1 >= 0 && IsInside(ray.Start + ray.Direction*t1)) { first_t = t1; } if (t2 >= 0 && IsInside(ray.Start + ray.Direction*t2) && t2 < first_t) { first_t = t2; } } float hDotd = Vector.Dot3(this.HeightDirection, ray.Direction); if (hDotd != 0) { float basePlaneT = Vector.Dot3(this.HeightDirection, this.BasePoint) - Vector.Dot3(this.HeightDirection, ray.Start); basePlaneT = basePlaneT / hDotd; if (basePlaneT > 0 && IsCap(this.BasePoint, basePlaneT * ray.Direction + ray.Start) && basePlaneT < first_t) { intersectionType = IntersectionType.Base; first_t = basePlaneT; } float endPlaneT = Vector.Dot3(this.HeightDirection, this.EndPoint) - Vector.Dot3(this.HeightDirection, ray.Start); endPlaneT = endPlaneT / hDotd; if (endPlaneT > 0 && IsCap(this.EndPoint, endPlaneT * ray.Direction + ray.Start) && endPlaneT < first_t) { intersectionType = IntersectionType.End; first_t = endPlaneT; } } if (first_t == float.MaxValue) return false; // t*d diff = ray.Direction * first_t; // e + t*d worldCoords = diff + ray.Start; float distance = diff.Magnitude3(); if (distance <= record.Distance && distance <= ray.MaximumTravelDistance) { if (ray.UseBounds) { float cameraOrthogonalDistance = Math.Abs(Vector.Dot3(diff, ray.CameraLookDirection)); if (cameraOrthogonalDistance > far && cameraOrthogonalDistance < near) { return false; } } record.T = first_t; record.HitPoint = ray.Start + diff; record.Distance = distance; record.Material = this.Material; if (intersectionType == IntersectionType.Cylinder) { record.SurfaceNormal = SurfaceNormal(record.HitPoint, ray.Direction); if (Material.TextureImage != null) { float heightReached = Vector.Dot3(HeightDirection, record.HitPoint - this.BasePoint); float u = heightReached / Height; Vector circCenter = BasePoint + HeightDirection * heightReached; Vector projection = record.HitPoint - circCenter; projection.Normalize3(); float similarity = Vector.Dot3(projection, Tangent); float theta = (float)Math.Acos(similarity); float v = (float)((Math.PI - theta) / Math.PI); v = v < 0 ? -v : v; record.TextureColor = this.Material.GetTexturePixelColor(u, v); // float v = } } else { record.SurfaceNormal = PlaneNormal(record.HitPoint, ray.Direction); if (Material.TextureImage != null) { Vector circCenter = intersectionType == IntersectionType.Base ? BasePoint : EndPoint; Vector projection = record.HitPoint - circCenter; float length = projection.Magnitude3(); projection.Normalize3(); float similarity = Vector.Dot3(projection, Tangent); float theta = (float)Math.Acos(similarity); float u = length / Radius; float v = (float)((Math.PI - theta) / Math.PI); v = v < 0 ? -v : v; record.TextureColor = this.Material.GetTexturePixelColor(u, v); // float v = } } // record.SurfaceNormal = SurfaceNormal(record.HitPoint, ray.Direction); return true; } return false; }
private Ray CastRefractionRay(Ray ray, HitRecord record, float refractive) { Vector rayDirection = ray.Direction; Vector surfaceNormal = record.SurfaceNormal; Vector refractedColor = new Vector(); float newRefractive = record.Material.RefractionIndex.x; if (newRefractive == refractive) { newRefractive = 1.0f; } //rayDirection = -surfaceNormal; float dDotn = Vector.Dot3(ray.Direction, surfaceNormal); float sqrtArgs = 1.0f - (refractive * refractive * (1 - dDotn * dDotn)) / (newRefractive * newRefractive); Vector refractiveDir = new Vector(); Ray refractionRay; if (sqrtArgs > 0.0f) { Vector nSqrt = surfaceNormal * (float)Math.Sqrt(sqrtArgs); refractiveDir = (refractive * (rayDirection - surfaceNormal * dDotn)) / newRefractive - nSqrt; refractiveDir.Normalize3(); //refractiveDir = rayDirection; refractionRay = new Ray(record.HitPoint + refractiveDir * 0.1f, refractiveDir); refractionRay.Time = ray.Time; if (RenderingParameters.showMouse) { //Console.WriteLine("Refracting"); // Console.WriteLine("Ray direction: "); // Console.WriteLine(rayDirection); // Console.WriteLine("Refraction direction: "); // Console.WriteLine(refractiveDir); // Console.WriteLine(); } return refractionRay; } else return ray; }
private Vector CalculateColor(Ray ray, float minDistance, float maxDistance, int reflections, int refractions, float refractive) { HitRecord record = new HitRecord(); Vector finalColor = new Vector(); Vector lightDirection = new Vector(); bool hitSomething = false; Vector surfaceNormal = new Vector(); Vector rayDirection = ray.Direction; foreach (SceneObject sceneObject in scene.Objects) { //First check intersection bool intersects = sceneObject.IsHit(ray, record, minDistance, maxDistance); //If it intersects, diffuse color is set, so set shading color if (intersects) { hitSomething = true; surfaceNormal = record.SurfaceNormal; if (record.Material.RefractionIndex.x > 0.0f && record.Material.Refractiveness.x == 1.0f) { continue; } record.ShadedColors.Clear(); foreach (SceneLight light in scene.Lights) { Vector currentLightColor = new Vector(); lightDirection = light.Position - record.HitPoint; lightDirection.Normalize3(); //Get cosine of angle between vectors float similarity = Vector.Dot3(surfaceNormal, lightDirection); Vector lambertColor = new Vector(); if (record.Material.TextureImage != null) { lambertColor = Vector.ColorMultiplication(light.Color, record.TextureColor) * Math.Max(0, similarity); } else { lambertColor = Vector.ColorMultiplication(light.Color, record.Material.Diffuse) * Math.Max(0, similarity); } //Get half vector between camera direction and light direction Vector halfVector = -1 * rayDirection + lightDirection; halfVector.Normalize3(); //Phong shading calculations float normalHalfSimilarity = Vector.Dot3(surfaceNormal, halfVector); Vector phongLightCoefficient = Vector.ColorMultiplication(light.Color, record.Material.Specular); float shininessComponent = (float)Math.Pow(Math.Max(0, normalHalfSimilarity), record.Material.Shininess); Vector phongColor = phongLightCoefficient * shininessComponent; //Add colors and ambient light //Assume no transparency currentLightColor = Vector.LightAdd(lambertColor, phongColor); record.ShadedColors.Add(currentLightColor); } } } if (hitSomething) { if (RenderingParameters.showMouse) { Console.WriteLine("Hit material " + record.Material.Name); } finalColor = new Vector(); ////////////////////////////////////////////////////////////// ///////////////////////SHADOWS/////////////////////////////// ///////////////////////////////////////////////////////////// if (RenderingParameters.showMouse) { Console.WriteLine("Checking for shadows!"); } for (int i = 0; i < scene.Lights.Count; i++) //For each light { if (renderingParameters.EnableShadows) { if (record.Material.RefractionIndex.x == 0.0f) //Not refractive surface { Vector direction = scene.Lights[i].Position - record.HitPoint; direction.Normalize3(); Vector shadowStart = record.HitPoint + direction * 0.1f; Ray shadowRay = new Ray(shadowStart, direction); bool makesShadow = MakesShadow(shadowRay, scene.Lights[i], reflections, refractions, refractive, ray.Time); if (makesShadow) { record.ShadedColors[i] = new Vector(); } } } if (record.Material.Refractiveness.x != 1.0f) { finalColor = Vector.LightAdd(finalColor, record.ShadedColors[i]); finalColor.w = 1.0f; } } /////////////////////////////////////////////////////////////// //////////////////////REFRACTIONS///////////////////////////// ////////////////////////////////////////////////////////////// if (renderingParameters.EnableRefractions && refractions < 10 && !record.Material.RefractionIndex.IsBlack()) { if (record.Material.Refractiveness.x < 1.0f) { int a = 1; } Ray refractedRay = CastRefractionRay(ray, record, refractive); Vector refractiveNess = record.Material.Refractiveness; if (RenderingParameters.showMouse) Console.WriteLine("REFRACTING"); finalColor = Vector.ColorMultiplication(refractiveNess, CalculateColor(refractedRay, float.MinValue, float.MaxValue, reflections, refractions + 1, record.Material.RefractionIndex.x)) + Vector.ColorMultiplication(new Vector(1.0f, 1.0f, 1.0f) - refractiveNess, finalColor); } /////////////////////////////////////////////////////////////// //////////////////////REFLECTIONS///////////////////////////// ////////////////////////////////////////////////////////////// if (renderingParameters.EnableReflections && reflections < 20 && !record.Material.Reflective.IsBlack() ) { Vector d = rayDirection; //Check for reflections Vector reflection = d -2* Vector.Dot3(d, surfaceNormal) * surfaceNormal; reflection.Normalize3(); HitRecord reflectionRecord = new HitRecord(); Ray reflectionRay = new Ray(record.HitPoint + reflection * 0.01f, reflection); reflectionRay.Time = ray.Time; //if (showMouse) //{ // Console.WriteLine("Reflection direction: "); // Console.WriteLine(reflection); // Console.WriteLine(); //} Vector reflectiveColor = record.Material.Reflective; if (RenderingParameters.showMouse) { Console.WriteLine("REFLECTING - NORMAL: " + surfaceNormal + "\tReflection: " + reflection); } Vector reflectedObjectColor = CalculateColor(reflectionRay, float.MinValue, float.MaxValue, reflections + 1, refractions, refractive); finalColor = Vector.LightAdd(finalColor, Vector.ColorMultiplication(reflectiveColor, reflectedObjectColor)); finalColor = Vector.LightAdd(finalColor, scene.Background.AmbientLight); } } if (reflections == 0 && refractions == 0) { //finalColor = Vector.LightAdd(finalColor, scene.Background.AmbientLight); if (RenderingParameters.showMouse) { RenderingParameters.showMouse = false; Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("-------------------------------------------------------"); } } finalColor.w = 1.0f; return finalColor; }
public override bool IsHit(Ray ray, HitRecord record, float near, float far) { bool isHit = false; foreach (SceneTriangle triangle in triangles) { isHit = triangle.IsHit(ray, record, near, far) || isHit; } if (isHit) { record.ObjectName = this.Name; if (Material.TextureImage != null) { Vector l1 = Vertex[1] - Vertex[0]; Vector l2 = Vertex[3] - Vertex[0]; float f = l1.x; float g = l2.x; float h = record.HitPoint.x; float i = Vertex[0].x; float j = l1.y; float k = l2.y; float l = record.HitPoint.y; float m = Vertex[0].y; float n = l1.z; float o = l2.z; float p = record.HitPoint.z; float q = Vertex[0].z; float det = g * j - f * k; if (det == 0) { det = o * j - n * k; if (det == 0) { det = g * n - f * o; j = n; k = o; l = p; m = q; } else { f = n; h = o; h = p; i = q; } } if (det != 0) { float alpha = (g * l - g * m - h * k + i * k) / det; float beta = (-f * l + f * m + h * j - i * j) / det; //if (RenderingParameters.showMouse) //{ //Console.WriteLine("alpha: " + alpha + "\tbeta: " + beta); record.TextureColor = this.Material.GetTexturePixelColor(alpha, beta); } // } } } return isHit; }
public abstract bool IsHit(Ray ray, HitRecord record, float near, float far);
public override bool IsHit(Ray ray, HitRecord record, float near, float far) { //Vamos precalculando variables auxiliares para facilitar el calculo y aumentar eficiencia //Convencion de nombres usada es la misma del libro "Fundamentals of Computer Graphics": /* * | a d g | | beta | | j | * | b e h | | gamma | = | k | * | c f i | | t | = | l | */ float a = Vertex[0].x - Vertex[1].x; float b = Vertex[0].y - Vertex[1].y; float c = Vertex[0].z - Vertex[1].z; float d = Vertex[0].x - Vertex[2].x; float e = Vertex[0].y - Vertex[2].y; float f = Vertex[0].z - Vertex[2].z; float g = ray.Direction.x; float h = ray.Direction.y; float i = ray.Direction.z; float j = Vertex[0].x - ray.Start.x; float k = Vertex[0].y - ray.Start.y; float l = Vertex[0].z - ray.Start.z; float eiMinushf = e * i - h * f; float gfMinusdi = g * f - d * i; float dhMinuseg = d * h - e * g; float akMinusjb = a * k - j * b; float jcMinusal = j * c - a * l; float blMinuskc = b * l - k * c; float M = a * eiMinushf + b * gfMinusdi + c * dhMinuseg; //e + td = punto triangulo float t = -(f * akMinusjb + e * jcMinusal + d * blMinuskc) / M; if (t >= 0) { float gamma = (i * akMinusjb + h * jcMinusal + g * blMinuskc) / M; if (gamma >= 0) { float beta = (j * eiMinushf + k * gfMinusdi + l * dhMinuseg) / M; //alpha = 1 - beta - gamma if (beta >= 0 && 1 - beta - gamma >= 0) { Vector diff = t * ray.Direction; float distance = diff.Magnitude3(); if (distance <= record.Distance && distance <= ray.MaximumTravelDistance) { if (ray.UseBounds) { float cameraOrthogonalDistance = Math.Abs(Vector.Dot3(diff, ray.CameraLookDirection)); if (cameraOrthogonalDistance > far && cameraOrthogonalDistance < near) { return false; } } record.T = t; record.HitPoint = ray.Start + diff; record.Distance = distance; record.Material = Materials[0]; record.SurfaceNormal = SurfaceNormal(record.HitPoint, ray.Direction); if (record.Material.TextureImage != null) { float alpha = 1 - beta - gamma; float u = alpha * U[0] + beta * U[1] + gamma * U[2]; float v = alpha * V[0] + beta * V[1] + gamma * V[2]; record.TextureColor = record.Material.GetTexturePixelColor(u, v); } return true; } } } } return false; }