static void Main()
        {
            const int width  = 640; // image width
            const int height = 480; // image height

            const float w2 = width / 2.0f;
            const float h2 = height / 2.0f;

            const float fov = 3.1415f / 3.0f; // field of view angle

            var dirz = ( float )(-h2 / Math.Tan(fov / 2f));

            var framebuffer = new Vec3f[width * height];

            // Load background.
            var bmp = ( Bitmap )Bitmap.FromFile("envmap.jpg");

            int pixelSize = 4;

            switch (bmp.PixelFormat)
            {
            case PixelFormat.Format24bppRgb: pixelSize = 3; break;
            }

            BitmapData bmpData = null;

            try
            {
                bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

                var kx = .5f * 3.1415f / Math.Atan(w2 / -dirz);

                var ky = .4f * 3.1415f * 2f / fov;

                var x0 = bmp.Width / 4 - ( int )(kx * width / 2);

                var y0 = bmp.Height / 2 - ( int )(ky * height / 2);

                for (var y = 0; y < height; ++y)
                {
                    unsafe
                    {
                        var row = ( byte * )bmpData.Scan0 + ( int )(y0 + ky * y) % bmp.Height * bmpData.Stride;

                        for (var x = 0; x < width; ++x)
                        {
                            var rx = ( int )(x0 + kx * x) * pixelSize % bmpData.Stride;

                            var r = row[rx + 2];
                            var g = row[rx + 1];
                            var b = row[rx + 0];

                            var c = new Vec3f(r, g, b) / 255f;

                            var i = y * width + x;

                            framebuffer[i] = c;
                        }
                    }
                }
            }
            finally
            {
                if (bmpData != null)
                {
                    bmp.UnlockBits(bmpData);
                }
            }

            pixelSize = 4;

            // The camera is placed to (0,0,3) and it looks along the -z axis.
            var vcam = new Vec3f(0, 0, 3);

            // One light is placed to (10,10,10).
            var vlight = new Vec3f(10, 10, 10);

            var hit = new Vec3f();

            // Actual rendering loop.
            for (var j = 0; j < height; j++)
            {
                for (var i = 0; i < width; i++)
                {
                    // This flips the image at the same time.
                    var dirx = (i + 0.5f) - w2;
                    var diry = -(j + 0.5f) + h2;

                    var vdir = new Vec3f(dirx, diry, dirz).normalize();

                    if (sphere_trace(vcam, vdir, ref hit))
                    {
                        var noiseLevel = (SphereRadius - hit.norm()) / NoiseAmplitude;

                        var lightDir = (vlight - hit).normalize();

                        var lightIntensity = Math.Max(0.4f, lightDir * distance_field_normal(hit));

                        framebuffer[i + j * width] = palette_fire((-0.2f + noiseLevel) * 2) * lightIntensity;
                    }
                }
            }

            // Save the framebuffer as image.
            bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);

            try
            {
                bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

                for (var y = 0; y < height; ++y)
                {
                    unsafe
                    {
                        var targetRow = ( byte * )bmpData.Scan0 + y * bmpData.Stride;

                        for (var x = 0; x < width; ++x)
                        {
                            var i = y * width + x;

                            var c = framebuffer[i];

                            var max = Math.Max(c[0], Math.Max(c[1], c[2]));

                            if (max > 1)
                            {
                                c = c / max;
                            }

                            targetRow[x * pixelSize + 0] = ( byte )(255 * Math.Max(0f, Math.Min(1f, c[2])));
                            targetRow[x * pixelSize + 1] = ( byte )(255 * Math.Max(0f, Math.Min(1f, c[1])));
                            targetRow[x * pixelSize + 2] = ( byte )(255 * Math.Max(0f, Math.Min(1f, c[0])));
                            targetRow[x * pixelSize + 3] = 255;
                        }
                    }
                }
            }
            finally
            {
                if (bmpData != null)
                {
                    bmp.UnlockBits(bmpData);
                }
            }

            bmp.Save("out.jpg", ImageFormat.Jpeg);
        }
Beispiel #2
0
        static void test_func_call()
        {
            test_name("func_call");

            // TVector
            Vec3f v31 = new Vec3f(1.0f, 2.0f, 3.0f);

            put("Vec3f: square ", "14.0", v31.square());
            put("Vec3f: norm   ", "3.7416574", v31.norm());
            Vec3f v3u = v31; v3u.unitize();
            Vec3f v3r = new Vec3f(0.2672612f, 0.5345225f, 0.8017837f);

            put2("Vec3f: unitize", edit_vector(v3r), edit_vector(v3u));

            // TQuaternion
            System.Console.WriteLine("");
            float       pi        = 3.1415927f;
            float       rad90     = pi / 2;
            float       rad45     = pi / 4;
            float       cos45     = 0.7071069f;
            float       sqrt3     = 1.7320508f;
            float       sqrt3div3 = sqrt3 / 3;
            Quaternionf q1        = new Quaternionf(cos45, sqrt3div3, sqrt3div3, sqrt3div3);
            Quaternionf q2        = new Quaternionf(q1.W(), q1.X(), q1.Y(), q1.Z());
            Vec3f       qv1       = new Vec3f(sqrt3div3, sqrt3div3, sqrt3div3);

            put2("Quaternionf: W(),X(),Y(),Z()", edit_quaternion(q1), edit_quaternion(q2));
            put2("Quaternionf: V", edit_vector(qv1), edit_vector(q1.V()));
            put2("Quaternionf: Axis", edit_vector(qv1), edit_vector(q1.Axis()));
            put("Quaternionf: Theta", rad90.ToString(), q1.Theta());
            System.Console.WriteLine("");

            float half = pi / (2 * sqrt3);
            Vec3f qv2  = new Vec3f(half, half, half);

            put2("Quaternionf: RotationHalf", edit_vector(qv2), edit_vector(q1.RotationHalf()));
            put2("Quaternionf: Rotation    ", edit_vector(qv2), edit_vector(q1.Rotation()));

            float       angle = rad90;
            float       d     = sqrt3;
            float       s     = (float)Math.Sin(angle / 2) / d;
            Quaternionf qr    = new Quaternionf((float)Math.Cos(angle / 2), s, s, s);
            Quaternionf q3    = Quaternionf.Rot(angle, new Vec3f(1f, 1f, 1f));

            put2("Quaternionf: Rot", edit_quaternion(qr), edit_quaternion(q3));

            float       c1 = (float)Math.Cos(angle / 2);
            float       s1 = (float)Math.Sin(angle / 2);
            Quaternionf qs = new Quaternionf(c1, s1, 0f, 0f);
            Quaternionf q4 = Quaternionf.Rot(angle, (sbyte)'x');

            put2("Quaternionf: Rot", edit_quaternion(qs), edit_quaternion(q4));

            Vec3f       qv3 = new Vec3f(1f, 1f, 1f);
            float       c2  = (float)Math.Cos(sqrt3 / 2);
            float       s2  = (float)Math.Sin(sqrt3 / 2);
            Vec3f       qv4 = (s2 / sqrt3) * qv3;
            Quaternionf qt  = new Quaternionf(c2, qv4[0], qv4[1], qv4[2]);
            Quaternionf q5  = Quaternionf.Rot(qv3);

            put2("Quaternionf: Rot", edit_quaternion(qt), edit_quaternion(q5));

            Quaternionf qc1 = new Quaternionf(cos45, sqrt3div3, sqrt3div3, sqrt3div3);
            Quaternionf qc2 = new Quaternionf(cos45, sqrt3div3, sqrt3div3, sqrt3div3);
            Quaternionf qc  = new Quaternionf(cos45, -sqrt3div3, -sqrt3div3, -sqrt3div3);

            qc1.Conjugate();
            put2("Quaternionf: Conjugate", edit_quaternion(qc), edit_quaternion(qc1));
            put2("Quaternionf: Conjugated", edit_quaternion(qc), edit_quaternion(qc2.Conjugated()));

            float       qf1 = (float)(cos45 * cos45 + 3 * sqrt3div3 * sqrt3div3);
            Quaternionf qe  = qc2.Conjugated() / qf1;

            put2("Quaternionf: Inv", edit_quaternion(qe), edit_quaternion(qc2.Inv()));

            // TPose
            System.Console.WriteLine("");
            Posef       p1   = new Posef(cos45, sqrt3, sqrt3, sqrt3, 1f, 2f, 3f);
            Posef       p2   = new Posef(p1.W(), p1.X(), p1.Y(), p1.Z(), p1.Px(), p1.Py(), p1.Pz());
            Vec3f       pv31 = new Vec3f(1f, 2f, 3f);
            Quaternionf pq1  = new Quaternionf(cos45, sqrt3, sqrt3, sqrt3);
            Quaternionf pq2  = new Quaternionf();
            Vec3f       pv32 = new Vec3f();
            Posef       pp1  = new Posef(pq2.w, pq2.x, pq2.y, pq2.z, pv32.x, pv32.y, pv32.z);
            Posef       pp2  = new Posef(pq2.w, pq2.x, pq2.y, pq2.z, 1f, 2f, 3f);

            put2("Posef: W(),X(),Y(),Z(),Px(),Py(),Pz()", edit_pose(p1), edit_pose(p2));
            put2("Posef: Pos()", edit_vector(pv31), edit_vector(p1.Pos()));
            put2("Posef: Ori()", edit_quaternion(pq1), edit_quaternion(p1.Ori()));
            put2("Posef: Unit ", edit_pose(pp1), edit_pose(Posef.Unit()));
            put2("Posef: Trn  ", edit_pose(pp2), edit_pose(Posef.Trn(1f, 2f, 3f)));
            put2("Posef: Trn  ", edit_pose(pp2), edit_pose(Posef.Trn(pv31)));
        }
        // This function defines the implicit surface we render.
        static float signed_distance(Vec3f p)
        {
            var displacement = -fractal_brownian_motion(p * 3.4f) * NoiseAmplitude;

            return(p.norm() - (SphereRadius + displacement));
        }