コード例 #1
0
ファイル: Sphere.cs プロジェクト: mkonicek/raytracer
        public override double GetIntersection(Ray ray)
        {
            double t1, t2;
            double A, A2, B, C, D, sqrtD;

            // move ray instead of sphere - same effect
            ray.Origin.X -= this.Position.X;
            ray.Origin.Y -= this.Position.Y;
            ray.Origin.Z -= this.Position.Z;

            // solve quadratic equation:
            C = Utils.Sqr(ray.Origin.X) + Utils.Sqr(ray.Origin.Y) + Utils.Sqr(ray.Origin.Z) - Utils.Sqr(Radius);
            A = Utils.Sqr(ray.Direction.X) + Utils.Sqr(ray.Direction.Y) + Utils.Sqr(ray.Direction.Z);
            B = 2 * ray.Origin.Dot(ray.Direction);
            D = B * B - 4 * A * C;

            if (D < 0)
            {
                // no solution
                return Constants.Infinity;
            }
            else
            {
                sqrtD = Math.Sqrt(D);
                A2 = 2 * A;
                t1 = (-B + sqrtD) / A2;
                t2 = (-B - sqrtD) / A2;
                t1 = Math.Min(t1, t2);

                return t1;
            }
        }
コード例 #2
0
ファイル: Plane.cs プロジェクト: mkonicek/raytracer
 public override double GetIntersection(Ray ray)
 {
     double dot = Normal.Dot(ray.Direction);
     // parallel to the plane ?
     if (Math.Abs(dot) < Constants.Epsilon)
     {
         return Constants.Infinity;
     }
     else
     {
         // linear equation
         double t = -(Normal.Dot(ray.Origin) + this.D) / dot;
         return t;
     }
 }
コード例 #3
0
ファイル: Scene.cs プロジェクト: mkonicek/raytracer
        /// <summary>
        /// Gets lightness and specular ligthness at given point in the scene.
        /// </summary>
        /// <param name="specularLightness">Returned specular lightness.</param>
        /// <param name="pos">Point in space where to calc ligthness.</param>
        /// <param name="reflectionDir">Direction of reflection.</param>
        /// <param name="normalDir">Direction of normal.</param>
        /// <param name="surfaceSpecular">Specular of the material.</param>
        /// <returns></returns>
        private Color lightColorAt(Vector pos, out double specularLightness, Vector vReflection, Vector normal, double surfaceSpecular)
        {
            Ray shadowRay = new Ray();
            shadowRay.Origin = pos;
            Color result = Color.Black;
            specularLightness = 0.0;

            foreach (Light light in this.lights)
            {
                int visibleRayCount = 0;

                // test all rays to this light
                for (int i = 0; i < light.GetRayCount(); i++)
                {
                    shadowRay.Direction = light.GetNextRaySource() - shadowRay.Origin;
                    // only front sides get lit
                    if (shadowRay.Direction.Dot(normal) >= Constants.Epsilon)
                    {
                        double isectDistance = 0;
                        objects.GetClosestIntersection(ref shadowRay, out isectDistance);
                        //double isectDistance2 = isectDistance * isectDistance;
                        //light visible from pos?
                        //if (!(isectDistance2 > Constants.Epsilon && isectDistance2 < shadowRay.Direction.LenSquared - Constants.Epsilon))
                        double lightDist2 = shadowRay.Direction.LenSquared;
                        shadowRay.Direction.Normalize();
                        if (!(isectDistance > Constants.Epsilon && isectDistance*isectDistance < lightDist2 - Constants.Epsilon))
                        {
                            visibleRayCount++;

                            Vector reflectionNorm = vReflection;
                            reflectionNorm.Normalize();

                            // is reflected ray pointing towards light?
                            double specularDot = reflectionNorm.Dot(shadowRay.Direction);
                            if (specularDot > -Constants.Epsilon)
                            {
                                specularDot *= specularDot;
                                specularDot *= specularDot;
                                specularDot *= specularDot;
                                specularDot *= specularDot;
                                specularDot *= specularDot; // ^32

                                specularLightness += specularDot;
                            }

                        }
                    }
                }
                result = Color.Combine(result, 1.0, light.Color,
                     visibleRayCount / (double)light.GetRayCount() * light.Value * shadowRay.Direction.Dot(normal));
            }

            specularLightness *= surfaceSpecular;
            return result;
        }
コード例 #4
0
ファイル: Scene.cs プロジェクト: mkonicek/raytracer
        /// <summary>
        /// Gets color by shooting a ray into scene. Recursive.
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="depth">Current depth of recursion (0 is primary ray).</param>
        /// <returns></returns>
        public Color tracePixel(Ray ray, int depth)
        {
            double isectDistance = Constants.Infinity;
            Primitive closest = objects.GetClosestIntersection(ref ray, out isectDistance);

            if (closest == null)
            {
                return this.settings.FillColor;
            }
            else
            {
                Vector isectPoint = ray.Origin + isectDistance * ray.Direction;

                Vector normal = closest.GetNormalAt(isectPoint);
                Material material = closest.GetMaterialAt(isectPoint);

                // reflection = v - 2*(v dot n)*n
                Vector vReflection = ray.Direction - (2 * normal.Dot(ray.Direction)) * normal;

                double specularLightness = 0.0;
                Color lightColor = lightColorAt(isectPoint, out specularLightness, vReflection, normal, material.Specular);

                Color primaryColor = material.Color * lightColor;
                Color reflectedColor = new Color();
                Color alphaColor = new Color();
                double reflectance = material.Reflectance;
                double opacity = material.Color.A;

                if (depth < Scene.maxRecursionDepth && reflectance > Constants.Epsilon)
                {
                    Ray rayReflection;
                    rayReflection.Direction = vReflection;
                    // move by a small epsilon along reflection vector
                    rayReflection.Origin = isectPoint + (Constants.Epsilon * vReflection);

                    reflectedColor = tracePixel(rayReflection, depth + 1);
                }
                if (depth < Scene.maxRecursionDepth && opacity < 1.0 - Constants.Epsilon)
                {
                    Ray rayAlpha;
                    // direction remains the same
                    rayAlpha.Direction = ray.Direction;
                    // progress by small epsilon forward
                    rayAlpha.Origin = isectPoint + (2 * Constants.Epsilon * rayAlpha.Direction);

                    alphaColor = tracePixel(rayAlpha, depth + 1);
                }

                // first reflection, then alpha (transparent mirror is still transparent)
                Color withoutAlpha = Color.Combine(primaryColor, 1 - reflectance, reflectedColor, reflectance);
                return Color.Combine(withoutAlpha, opacity, alphaColor, 1 - opacity) * (1 + specularLightness);

                // first alpha, then reflection (transparent mirror is still a mirror)
                /*Color withoutReflection = ColorCombine(primaryColor, opacity, alphaColor, 1 - opacity);
                return ColorCombine(withoutReflection, 1 - reflectance, reflectedColor, reflectance);*/
            }
        }
コード例 #5
0
ファイル: Scene.cs プロジェクト: mkonicek/raytracer
        public void Render(System.Drawing.Rectangle rect, Color[] buffer)
        {
            if (this.settings == null)
            {
                throw new InvalidOperationException("Scene settings must be set before rendering.");
            }
            if (buffer.Length != rect.Width * rect.Height)
                throw new InvalidOperationException("Buffer must be same size as the rectangle to render");

            Vector eye = settings.View.Origin;

            Ray ray;
            ray.Origin = eye;

            Parallel.For(0, rect.Height, delegate(int y)
            {
                int x = 0;
                for (x = 0; x < rect.Width; x++)
                {
                    Vector rayEnd =
                        // origin + linear combination of topSide (for x) and leftSide (for y)
                        this.settings.View.RenderRectOrigin +
                        ((rect.Left + x) / (double)this.settings.ImageWidth) * this.settings.View.RenderRectTopSide +
                        ((rect.Top + y) / (double)this.settings.ImageHeight) * this.settings.View.RenderRectLeftSide;

                    Ray r = new Ray();
                    r.Origin = ray.Origin;
                    r.Direction = rayEnd - r.Origin;

                    if (x == 92 && y == 76)
                    {
                        int a = 5;
                        int b = a;
                        if (b == 300)
                            throw new Exception();
                    }

                    Color c = this.tracePixel(r, 0);
                    int bufIndex = x + y * rect.Width;
                    // concurrent writing
                    lock (this)
                    {
                        buffer[bufIndex] = c;
                    }
                }
            });
        }
コード例 #6
0
ファイル: Triangle.cs プロジェクト: mkonicek/raytracer
        public override double GetIntersection(Ray ray)
        {
            double distance = this.plane.GetIntersection(ray);
            if (distance < Constants.Epsilon)
                return Constants.Infinity;
            Vector isect = Vector.Combine(ray.Origin, 1.0, ray.Direction, distance);

            // insert point into plane equation,
            // test if it lies on negative side -> outside triangle
            if (bounds[0].liesOnNegativeSide(ref isect))
                return Constants.Infinity;
            if (bounds[1].liesOnNegativeSide(ref isect))
                return Constants.Infinity;
            if (bounds[2].liesOnNegativeSide(ref isect))
                return Constants.Infinity;

            return distance;
        }
コード例 #7
0
ファイル: BoundingBox.cs プロジェクト: mkonicek/raytracer
 static double intersectPlaneZ(Ray ray, double planeZ)
 {
     return intersectPlane(ray.Origin.Z, ray.Direction.Z, planeZ);
 }
コード例 #8
0
ファイル: BoundingBox.cs プロジェクト: mkonicek/raytracer
 /// <summary>
 /// Intersects ray with plane with normal in X axis coming through point [x,0,0].
 /// </summary>
 static double intersectPlaneX(Ray ray, double planeX)
 {
     return intersectPlane(ray.Origin.X, ray.Direction.X, planeX);
 }
コード例 #9
0
ファイル: BoundingBox.cs プロジェクト: mkonicek/raytracer
 static double intersectPlaneY(Ray ray, double planeY)
 {
     return intersectPlane(ray.Origin.Y, ray.Direction.Y, planeY);
 }
コード例 #10
0
ファイル: BoundingBox.cs プロジェクト: mkonicek/raytracer
        public double GetIntersection(Ray ray)
        {
            // find largest tNear, smallest tFar
            double tNear = -Constants.Infinity;
            double tFar = Constants.Infinity;
            double t1, t2;

            // for x, y, z
            for (int i = 0; i < 3; i++)
            {
                // intersect in one axis
                // TODO t1 = intersectPlane(ref ray, ref this.LeftTopFront, i);
                //lock (typeof(BoundingBox))
                {
                    t1 = planeIntersectors[i](ray, this.LeftTopFront[i]);
                }
                // ray parallel to planes
                if (t1 == Constants.Infinity)
                {
                    //lock (typeof(BoundingBox))
                    {
                        // ray outside the box
                        if (ray.Origin[i] < this.LeftTopFront[i] || ray.Origin[i] > this.RightBottomBack[i])
                            return Constants.Infinity;
                    }
                }
                else
                {
                    //lock (typeof(BoundingBox))
                    {
                        // TODO t2 = intersectPlane(ref ray, ref this.RightBottomBack , i);
                        t2 = planeIntersectors[i](ray, this.RightBottomBack[i]);
                        if (t1 > t2) Utils.Swap<double>(ref t1, ref t2);
                        // want largest near intersection
                        tNear = Math.Max(t1, tNear);
                        // want smallest far intersection
                        tFar = Math.Min(t2, tFar);
                    }
                }
                // box missed
                if (tNear > tFar)
                    return Constants.Infinity;
                // box is behind
                if (tFar < -Constants.Epsilon)
                    return Constants.Infinity;
            }

            return tNear;
        }
コード例 #11
0
ファイル: BoxPrimitive.cs プロジェクト: mkonicek/raytracer
 public override double GetIntersection(Ray ray)
 {
     return this.box.GetIntersection(ray);
 }
コード例 #12
0
ファイル: Octree.cs プロジェクト: mkonicek/raytracer
        public Primitive GetClosestIntersection(ref Ray ray, out double distance)
        {
            LinkedList<OctreeNode> hitNodes = new LinkedList<OctreeNode>();
            if (root.boundingBox.GetIntersection(ray) != Constants.Infinity)
            {
                traverse(root, ray, hitNodes);
            }
            Primitive foundPrimitive = null;
            double minDist = Constants.Infinity;
            foreach (OctreeNode node in hitNodes)
            {
                double d = 0;
                Primitive p = node.primitives.GetClosestIntersection(ref ray, out d);
                if (d < minDist)
                {
                    minDist = d;
                    foundPrimitive = p;
                }
            }

            // test big objects
            double dBig = 0;
            Primitive pBig = bigObjects.GetClosestIntersection(ref ray, out dBig);
            if (dBig < minDist)
            {
                minDist = dBig;
                foundPrimitive = pBig;
            }

            distance = minDist;
            return foundPrimitive;
        }
コード例 #13
0
ファイル: Octree.cs プロジェクト: mkonicek/raytracer
 // returns all leaf nodes hit by the ray
 private void traverse(OctreeNode node, Ray ray, LinkedList<OctreeNode> list)
 {
     if (node.primitives != null)
     {
         list.AddLast(node);
     }
     if (node.childs != null)
     {
         for (int i = 0; i < 8; i++)
         {
             if (node.childs[i].boundingBox.GetIntersection(ray) != Constants.Infinity)
             {
                 traverse(node.childs[i], ray, list);
             }
         }
     }
 }
コード例 #14
0
ファイル: Primitive.cs プロジェクト: mkonicek/raytracer
 /// <summary>
 /// Finds intersection of this object with given ray.
 /// </summary>
 /// <param name="ray">Ray to intersect with.</param>
 /// <returns>Distance as ray.Direction multiplier, can be negative.</returns>
 public abstract double GetIntersection(Ray ray);