Ejemplo n.º 1
0
        public static byte[] Render(Scene scene, byte[] pixels)
        {
            var eye = Vec3.Zero;
            Num h   = MATH.Tan(((fov / 360) * (2 * PI)) / 2) * 2;
            Num w   = (h * Width) / Height;

            for (int y = 0; y != Height; ++y)
            {
                for (int x = 0; x != Width; ++x)
                {
                    Num  xx = x, yy = y, ww = Width, hh = Height;
                    Vec3 dir;
                    dir.X = ((xx - (ww / 2.0f)) / ww) * w;
                    dir.Y = (((hh / 2.0f) - yy) / hh) * h;
                    dir.Z = -1.0f;
                    dir   = Vec3.Normalize(dir);

                    Ray r;
                    r.Org = eye;
                    r.Dir = dir;
                    var pixel = trace(r, scene, 0);
                    int i     = (x * 3) + (y * Width * 3);
                    pixels[i]     = (byte)MATH.Min(pixel.X * 255, 255);
                    pixels[i + 1] = (byte)MATH.Min(pixel.Y * 255, 255);
                    pixels[i + 2] = (byte)MATH.Min(pixel.Z * 255, 255);
                }
            }

            return(pixels);
        }
Ejemplo n.º 2
0
        private static Vec3 trace(Ray ray, Scene scene, int depth)
        {
            var    nearest = Num.MaxValue;
            Sphere obj     = null;

            // search the scene for nearest intersection
            foreach (var o in scene.Objects)
            {
                var distance = Num.MaxValue;
                if (Sphere.Intersect(o, ray, out distance))
                {
                    if (distance < nearest)
                    {
                        nearest = distance;
                        obj     = o;
                    }
                }
            }

            if (obj == null)
            {
                return(Vec3.Zero);
            }

            var  point_of_hit = ray.Org + (ray.Dir * nearest);
            var  normal       = Sphere.Normal(obj, point_of_hit);
            bool inside       = false;

            if (Vec3.Dot(normal, ray.Dir) > 0)
            {
                inside = true;
                normal = -normal;
            }

            Vec3 color            = Vec3.Zero;
            var  reflection_ratio = obj.Reflection;

            foreach (var l in scene.Lights)
            {
                var light_direction = Vec3.Normalize(l.Position - point_of_hit);
                Ray r;
                                #if BIT64
                r.Org = point_of_hit + (normal * 1e-5);
                                #else
                r.Org = point_of_hit + (normal * 1e-5f);
                                #endif
                r.Dir = light_direction;

                // go through the scene check whether we're blocked from the lights
                bool blocked = false;
                foreach (var o in scene.Objects)
                {
                    if (Sphere.Intersect(o, r))
                    {
                        blocked = true;
                        break;
                    }
                }

                if (!blocked)
                {
                    color += l.Color
                             * MATH.Max(0, Vec3.Dot(normal, light_direction))
                             * obj.Color
                             * (1.0f - reflection_ratio);
                }
            }

            var rayNormDot    = Vec3.Dot(ray.Dir, normal);
            Num facing        = MATH.Max(0, -rayNormDot);
            Num fresneleffect = reflection_ratio + ((1 - reflection_ratio) * MATH.Pow((1 - facing), 5));

            // compute reflection
            if (depth < maxDepth && reflection_ratio > 0)
            {
                var reflection_direction = ray.Dir + (normal * 2 * rayNormDot * (-1));
                Ray r;
                                #if BIT64
                r.Org = point_of_hit + (normal * 1e-5);
                                #else
                r.Org = point_of_hit + (normal * 1e-5f);
                                #endif
                r.Dir = reflection_direction;
                var reflection = trace(r, scene, depth + 1);
                color += reflection * fresneleffect;
            }

            // compute refraction
            if (depth < maxDepth && (obj.Transparency > 0))
            {
                                #if BIT64
                Num ior = 1.5;
                                #else
                Num ior = 1.5f;
                                #endif
                var CE = Vec3.Dot(ray.Dir, normal) * (-1);
                ior = inside ? 1 / ior : ior;
                Num eta      = 1 / ior;
                var GF       = (ray.Dir + normal * CE) * eta;
                Num sin_t1_2 = 1 - (CE * CE);
                Num sin_t2_2 = sin_t1_2 * (eta * eta);
                if (sin_t2_2 < 1)
                {
                    var GC = normal * MATH.Sqrt(1 - sin_t2_2);
                    var refraction_direction = GF - GC;
                    Ray r;
                                        #if BIT64
                    r.Org = point_of_hit - (normal * 1e-4);
                                        #else
                    r.Org = point_of_hit - (normal * 1e-4f);
                                        #endif
                    r.Dir = refraction_direction;
                    var refraction = trace(r, scene, depth + 1);
                    color += refraction * (1 - fresneleffect) * obj.Transparency;
                }
            }
            return(color);
        }
Ejemplo n.º 3
0
 public static Vec3 Normal(Sphere sphere, Vec3 pos)
 {
     return(Vec3.Normalize(pos - sphere.Center));
 }