public virtual List<ZBufferItem> Trace(Ray ray, Matrix transform, Vector3 translation) { var intersections = new List<ZBufferItem>(); foreach (var primitive in Triangles) { var items = primitive.Trace(ray, transform, translation); intersections.AddRange(items); } return intersections; }
/// <summary> /// Get the colour at this point on this triangle /// </summary> public Color Colorise(Scene scene, Shapes.Ray ray, Matrix transform, Vector3 translation, Vector3 intersection) { var colour = new Color(); foreach (var light in scene.Lights) { // get the vector between the light and the point var lightv = Vector3.Normalize(intersection - light.Position); var distance = Vector3.Distance(intersection, light.Position); // get the texture colour var a = Shader.Ambient(light, distance); colour += a; var lightraydir = light.Position - intersection; lightraydir.Normalize(); // don't intersect with the object i'm on var lightrayorigin = intersection + 0.01f*lightraydir; var lightray = new Ray(lightrayorigin, lightraydir); var lightx = scene.Trace(lightray, transform, translation); if (!lightx.Any()) { var l = Shader.Lambertian(Normal, light, lightv, distance); var s = Shader.Specular(Normal, ray.Direction, light, lightv, distance); colour += l; colour += s; } } return colour; }
/// <summary> /// Möller–Trumbore ray-triangle intersection algorithm /// </summary> /// <param name="ray">ray to test</param> /// <param name="transform">world rotation transform</param> /// <param name="translation">translation vector</param> /// <returns>list of intersections</returns> public List<ZBufferItem> Trace(Ray ray, Matrix transform, Vector3 translation) { var buffer = new List<ZBufferItem>(); var ts = Vertices.Select(vertex => Vector3.TransformCoordinate(vertex, transform)).Select(vertex => vertex + translation).ToArray(); // find vectors for two edges sharing ts[0] var edge1 = ts[1] - ts[0]; var edge2 = ts[2] - ts[0]; var cross = Vector3.Cross(ray.Direction, edge2); var det = Vector3.Dot(edge1, cross); // if det is near 0 then ray is in the plane of the triangle i.e. parallel if (det > -float.Epsilon && det < float.Epsilon) { return buffer; } var invDet = 1f/det; var T = ray.Origin - ts[0]; var u = Vector3.Dot(T, cross)*invDet; // if u is not 0->1 then intersection is outside the triangle if (u < 0f || u > 1f) { return buffer; } var Q = Vector3.Cross(T, edge1); var v = Vector3.Dot(ray.Direction, Q)*invDet; // then intersection is outside the triangle if (v < 0f || u + v > 1f) { return new List<ZBufferItem>(); } var t = Vector3.Dot(edge2, Q)*invDet; // ray intersection! if (t > float.Epsilon) { // get the point of intersection var ix = ray.Origin + t*ray.Direction; buffer.Add(new ZBufferItem(this, ix, translation)); } return buffer; }
public Color Colorise(Scene scene, Ray ray, Matrix transform, Vector3 translation, Vector3 intersection) { // this is never called return Color.BlanchedAlmond; }
private Color TraceRay(Matrix transform, int x, int y, int width, int height) { var camPositionScaled = Vector3.Divide(_scene.Camera.Position, _scene.Camera.Scale); // work out the orientation of the image plane var camDir = _scene.Camera.Target - camPositionScaled; var xDir = Vector3.Cross(Vector3.UnitY, camDir); var yDir = Vector3.Cross(camDir, xDir); // now correct the up dir camDir.Normalize(); xDir.Normalize(); yDir.Normalize(); // now get the uv coordinates on our image plane, scaled by unitsize const float unitsize = 0.1f; var u = (float)((x - 0.5 * width) * unitsize); var v = (float)((y - 0.5 * height) * unitsize); // now move u units along x, v units along y, starting at camposition var uv = camPositionScaled + u * xDir + v * yDir; // now the direction of the ray from uv to the target var rayDir = _scene.Camera.Target - uv; rayDir.Normalize(); // get the actual ray var ray = new Shapes.Ray(uv, rayDir); var bounces = new List<ZBufferItem>(); const int iterations = 2; for (var i = 0; i < iterations; i++) { var items = _scene.Trace(ray, transform, _scene.Origin); if (items.Any()) { var closest = items.OrderByDescending(d => d.Distance(ray.Origin)).First(); bounces.Add(closest); if (closest.Primitive.Shader.IsReflective) { var reflectedRay = -ray.Direction - 2*Vector3.Dot(-ray.Direction, closest.Primitive.Normal)* closest.Primitive.Normal; reflectedRay.Normalize(); // don't want to intersect the reflection plane var reflectionOrigin = closest.Intersection + 0.01f*reflectedRay; ray = new Shapes.Ray(reflectionOrigin, reflectedRay); //var reflections = _scene.Trace(ray, transform, _scene.Origin); //if (reflections.Any()) //{ // bounces.Add(reflections.OrderByDescending(d => d.Distance(ray.Origin)).First()); //} } } } if (bounces.Any()) { var c = new Color(); foreach (var bounce in bounces) { var closestColour = bounce.Primitive.Colorise(_scene, ray, transform, bounce.Translation, bounce.Intersection); var avgColour = Color.Scale(closestColour, 1f/bounces.Count); c += avgColour; } c.A = 255; return c; } return _scene.Ambient(); }