public SLRay(SLVector3f o, SLVector3f d) { Origin = o; Direction = d; ClosestPointDistance = Max_Distance; ClosestPrimitive = null; }
static void Main(string[] args) { RayObjects = new List<SLRayPrimitive>(); Lights = new List<SLLight>(); ReadScene("scene.urt"); dir = EYE - SPOT; right = UP.Cross(dir); right.Normalize(); screenCenter = dir.Cross(right); screenV = screenCenter * (float)Math.Tan(FOVY * 0.5f); screenU = right * screenV.Magnitude() * ASPECT; WIDTH_DIV_2 = ImageWidth / 2; HEIGHT_DIV_2 = ImageHeight / 2; random = new Random(01478650229); Bitmap outputImage = new Bitmap(ImageWidth, ImageHeight); // add some objects float distance = 20.0f; float offset = distance / 2.0f; for (int i = 0; i < 5; i++) { float x = (float)(random.NextDouble() * distance) - offset; float y = (float)(random.NextDouble() * distance) - offset; float z = (float)(random.NextDouble() * 10.0f + 2.0f); Color c = Color.FromArgb(255, random.Next(255), random.Next(255), random.Next(255)); SLSphere s = new SLSphere(new SLVector3f(x, y, z), (float)(random.NextDouble() + 0.5), c); RayObjects.Add(s); } int dotPeriod = ImageHeight / 10; Stopwatch stopwatch = new Stopwatch(); System.Console.WriteLine("Rendering...\n"); System.Console.WriteLine("|0%---100%|"); stopwatch.Start(); for (int j = 0; j < ImageHeight; j++) { if ((j % dotPeriod) == 0) System.Console.Write("*"); for (int i = 0; i < ImageWidth; i++) { // Go through each pixel to get the color Color c = Render(i, j); outputImage.SetPixel(i, j, c); } } stopwatch.Stop(); TimeSpan ts = stopwatch.Elapsed; string output = ts.Minutes.ToString() + "_" + ts.Seconds.ToString() + ".png"; outputImage.Save(output); }
public SLVector3f Reflection(SLVector3f normal) { SLVector3f negVector = -this; SLVector3f reflectedDir = normal * (2.0f * negVector.Dot(normal)); return reflectedDir; }
public float Dot(SLVector3f b) { return (this.x * b.x + this.y * b.y + this.z * b.z); }
public SLVector3f Cross(SLVector3f v) { return new SLVector3f(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x); }
public override SLVector3f PointNormal(SLVector3f point) { SLVector3f pNormal = (point - position); pNormal.Normalize(); return pNormal; }
public SLSphere(SLVector3f pos, float rad, Color col) { position = pos; radius = rad; PrimitiveColor = col; }
public abstract SLVector3f PointNormal(SLVector3f point);
public SLLight( SLVector3f pos, float red = 1.0f, float green = 1.0f, float blue = 1.0f) { position = pos; color = Color.FromArgb((int)(red * 255.0f), (int)(green * 255.0f), (int)(blue * 255.0f)); }
static Color SetPixelColor(SLRay ray, int depth) { // Get closest intersection IF ANY GetClosestIntersection(ref ray); // Return if the ray didn't hit anything if (ray.ClosestPointDistance >= SLRay.Max_Distance || ray.ClosestPrimitive == null) return BG_COLOR; // Set ambient light float r = LaR * ray.ClosestPrimitive.PrimitiveColor.R; float g = LaG * ray.ClosestPrimitive.PrimitiveColor.G; float b = LaB * ray.ClosestPrimitive.PrimitiveColor.B; // Add contributions of each light SLVector3f normal = ray.ClosestPrimitive.PointNormal(ray.ClosestPoint); SLVector3f viewDir = -ray.Direction; foreach (SLLight light in Lights) { SLVector3f lightDir = new SLVector3f(); float lightDistance; // Find light direction and distance lightDir = light.position - ray.ClosestPoint; lightDistance = lightDir.Magnitude(); lightDir.Normalize(); SLRay pointToLight = new SLRay(ray.ClosestPoint + (lightDir * TINY), lightDir); pointToLight.ClosestPointDistance = lightDistance; GetClosestIntersection(ref pointToLight); if (pointToLight.ClosestPrimitive != null) continue; // DIFFUSE LIGHTING float lDotN = normal.Dot(lightDir); // Clamp if (lDotN <= 0) continue; float diffColorContrR = (light.color.R * lDotN)/255.0f; float diffColorContrG = (light.color.G * lDotN)/ 255.0f; float diffColorContrB = (light.color.B * lDotN)/ 255.0f; // Add this light's diffuse contribution to our running totals r += diffColorContrR * ray.ClosestPrimitive.PrimitiveColor.R; g += diffColorContrG * ray.ClosestPrimitive.PrimitiveColor.G; b += diffColorContrB * ray.ClosestPrimitive.PrimitiveColor.B; if (MATERIAL_SPECULAR_COEFFICIENT > TINY) { // Specular component - dot product of light's reflection vector and viewer direction // Direction to the viewer is simply negative of the ray direction SLVector3f lightReflectionDir = normal * (lDotN * 2) - lightDir; float specularFactor = viewDir.Dot(lightReflectionDir); if (specularFactor > 0) { // To get smaller, sharper highlights we raise it to a power and multiply it specularFactor = MATERIAL_SPECULAR_COEFFICIENT * (float)Math.Pow(specularFactor, MATERIAL_SPECULAR_POWER); // Add the specular contribution to our running totals r += MATERIAL_SPECULAR_COEFFICIENT * specularFactor * ray.ClosestPrimitive.PrimitiveColor.R; g += MATERIAL_SPECULAR_COEFFICIENT * specularFactor * ray.ClosestPrimitive.PrimitiveColor.G; b += MATERIAL_SPECULAR_COEFFICIENT * specularFactor * ray.ClosestPrimitive.PrimitiveColor.B; } } if (depth < MAX_DEPTH && MATERIAL_REFLECTION_COEFFICIENT > TINY) { // Set up the reflected ray - notice we move the origin out a tiny bit again SLVector3f reflectedDir = ray.Direction.Reflection(normal); SLRay reflectionRay = new SLRay(ray.ClosestPoint + reflectedDir * TINY, reflectedDir); // And trace! Color reflectionCol = SetPixelColor(reflectionRay, depth + 1); // Add reflection results to running totals, scaling by reflect coeff. r += MATERIAL_REFLECTION_COEFFICIENT * reflectionCol.R; g += MATERIAL_REFLECTION_COEFFICIENT * reflectionCol.G; b += MATERIAL_REFLECTION_COEFFICIENT * reflectionCol.B; } } // Clamp if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; // Take care of NaN if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; return (Color.FromArgb(255, (int)r, (int)g, (int)b)); }
static void ReadScene(string path) { StreamReader file = new StreamReader(path); string delim = file.ReadLine(); if (delim != "U5") return; // Get resolution string[] res = file.ReadLine().Split(' '); ImageWidth = Int32.Parse(res[0]); ImageHeight = Int32.Parse(res[1]); // Get Eye string[] eye = file.ReadLine().Split(' '); EYE = new SLVector3f(float.Parse(eye[0]), float.Parse(eye[1]), float.Parse(eye[2])); // Get Spot string[] spot = file.ReadLine().Split(' '); SPOT = new SLVector3f(float.Parse(spot[0]), float.Parse(spot[1]), float.Parse(spot[2])); // Get Up string[] up = file.ReadLine().Split(' '); UP = new SLVector3f(float.Parse(up[0]), float.Parse(up[1]), float.Parse(up[2])); // Get aspect string[] viewVol = file.ReadLine().Split(' '); FOVY = float.Parse(viewVol[0]); ASPECT = float.Parse(viewVol[1]); // Read in Ambient Values string[] ambient = file.ReadLine().Split(' '); LaR = float.Parse(ambient[0]); LaG = float.Parse(ambient[1]); LaB = float.Parse(ambient[2]); // Read in spheres while (!file.EndOfStream) { string[] line = file.ReadLine().Split(' '); string del = line[0]; switch(del) { case "l": // LIGHTS SLVector3f pos = new SLVector3f(float.Parse(line[1]), float.Parse(line[2]), float.Parse(line[3])); SLLight l = new SLLight(pos, float.Parse(line[4]), float.Parse(line[5]), float.Parse(line[6])); Lights.Add(l); break; case "s": // SPHERES SLSphere s = new SLSphere(new SLVector3f(float.Parse(line[1]), float.Parse(line[2]), float.Parse(line[3])), float.Parse(line[4]), Color.FromArgb((int)float.Parse(line[5])*255, (int)float.Parse(line[6])*255, (int)float.Parse(line[7])*255)); RayObjects.Add(s); break; case "p": // PLANES float offset; if (float.Parse(line[1]) != 0.0f) offset = float.Parse(line[1]); else if (float.Parse(line[2]) != 0.0f) offset = float.Parse(line[2]); else offset = float.Parse(line[3]); float pR = float.Parse(line[7]) * 255.0f; float pG = float.Parse(line[8]) * 255.0f; float pB = float.Parse(line[9]) * 255.0f; SLPlane p = new SLPlane(new SLVector3f(float.Parse(line[4]), float.Parse(line[5]), float.Parse(line[6])), offset, Color.FromArgb((int)pR, (int)pG, (int)pB)); RayObjects.Add(p); break; } } }
public override SLVector3f PointNormal(SLVector3f point) { return pNormal; }
public SLPlane(SLVector3f normal, float offset, Color color) { pNormal = normal; Offset = offset; PrimitiveColor = color; }