void render(byte[] buf, List <Sphere> spheres, int pixelWidth)
        {
            float tm = _timer.gameTime() * 2.0f;

            int stride      = (pixelWidth * 32) / 8;
            int pixelHeight = buf.Length / stride;

            int width  = pixelWidth;
            int height = pixelHeight;

            float invWidth    = 1.0f / (float)width;
            float invHeight   = 1.0f / (float)height;
            float fov         = 80.0f;
            float aspectratio = width / (float)height;
            float angle       = (float)Math.Tan(M_PI * 0.5f * fov / 180.0f);

            List <Task> tasks = new List <Task>();

            for (int i = 0; i < lineTos.Length; i++)
            {
                Task task = new Task(obj => {
                    // Trace rays
                    lineToRender toRender = lineTos[(int)obj];
                    for (int y = toRender.from; y < toRender.to; ++y)
                    {
                        for (int x = 0; x < width; ++x)
                        {
                            float xx     = (2.0f * (((float)x + 0.5f) * invWidth) - 1.0f) * angle * aspectratio;
                            float yy     = (1.0f - 2.0f * (((float)y + 0.5f) * invHeight)) * angle;
                            Vec3f raydir = new Vec3f(xx, yy, -1.0f);
                            raydir.normalize();

                            Vec3f raydir2 = new Vec3f(Mat4f.RotationYMatrix(-tm) * raydir);
                            //Vec3f raydir2 = raydir;

                            //Vec3f rayorig = new Vec3f(0.0f, 1.0f + (float)Math.Sin(tm) * 4.0f, -20.0f) + new Vec3f(Mat4f.RotationYMatrix(-tm) * new Vec3f(0.0f, 1.0f, 20.0f));
                            Vec3f rayorig = new Vec3f(0.0f, 5.0f, -25.0f) + new Vec3f(Mat4f.RotationYMatrix(-tm) * new Vec3f(0.0f, 5.0f, 25.0f));
                            //Vec3f rayorig = spheres[1].center + new Vec3f(Mat4f.RotationYMatrix(-tm) * new Vec3f(0.0f, 3.0f, 5.0f + tm));
                            //Vec3f rayorig = new Vec3f(0.0f);
                            //Vec3f rayorig = new Vec3f(0.0f, 10.0f, 0.0f);
                            Vec3f pixel = trace(rayorig, raydir2, spheres, 0);

                            printPixel(buf, x, y, new pBGRA((byte)(pixel.z * 255.0f), (byte)(pixel.y * 255.0f), (byte)(pixel.x * 255.0f), 255), pixelWidth);
                        }
                    }
                }, i);
                task.Start();
                tasks.Add(task);
            }

            foreach (Task t in tasks)
            {
                t.Wait();
            }
        }
Beispiel #2
0
        void render(byte[] buf, List <Sphere> spheres, int pixelWidth)
        {
            float tm = _timer.gameTime() * 2.0f;

            int stride      = (pixelWidth * 32) / 8;
            int pixelHeight = buf.Length / stride;

            int width  = pixelWidth;
            int height = pixelHeight;

            float invWidth    = 1.0f / (float)width;
            float invHeight   = 1.0f / (float)height;
            float fov         = 40.0f;
            float aspectratio = width / (float)height;
            float angle       = (float)Math.Tan(M_PI * 0.5f * fov / 180.0f);

            Parallel.For(0, lineTos.Length, i => {
                lineToRender toRender = lineTos[i];
                for (int y = toRender.from; y < toRender.to; ++y)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        float xx     = (2.0f * (((float)x + 0.5f) * invWidth) - 1.0f) * angle * aspectratio;
                        float yy     = (1.0f - 2.0f * (((float)y + 0.5f) * invHeight)) * angle;
                        Vec3f raydir = new Vec3f(xx, yy, -1.0f);
                        raydir.normalize();

                        Vec3f raydir2 = new Vec3f(Mat4f.RotationYMatrix(-tm) * raydir);
                        Vec3f rayorig = new Vec3f(0.0f, 5.0f, -25.0f) + new Vec3f(Mat4f.RotationYMatrix(-tm) * new Vec3f(0.0f, 5.0f, 25.0f));
                        Vec3f pixel   = trace(rayorig, raydir2, spheres, 0);

                        printPixel(buf, x, y, new pBGRA((byte)(pixel.z * 255.0f), (byte)(pixel.y * 255.0f), (byte)(pixel.x * 255.0f), 255), pixelWidth);
                    }
                }
            });
        }
        public Vec3f trace(Vec3f rayorig, Vec3f raydir, List <Sphere> spheres, int depth)
        {
            float  tnear  = INFINITY;
            Sphere sphere = null;

            //find intersection of this ray with the sphere in the scene
            int spCount = spheres.Count();

            for (int i = 0; i < spCount; ++i)
            {
                float t0 = INFINITY;
                float t1 = INFINITY;
                (bool, float, float)inter = spheres[i].intersect(rayorig, raydir);
                if (inter.Item1)
                {
                    t0 = inter.Item2;
                    t1 = inter.Item3;
                    if (t0 < 0)
                    {
                        t0 = t1;
                    }
                    if (t0 < tnear)
                    {
                        tnear  = t0;
                        sphere = spheres[i];
                    }
                }
            }

            //if there's no intersection return black or background color
            if (sphere == null)
            {
                return(new Vec3f(1.0f));
            }

            Vec3f surfaceColor = new Vec3f(0.0f);          //color of the ray/surfaceof the object intersected by the ray
            Vec3f phit         = rayorig + raydir * tnear; //point of intersection
            Vec3f nhit         = phit - sphere.center;     //normal at the intersection point

            nhit.normalize();                              //normalize normal direction

            //If the normal and the view direction are not opposite to each other
            //reverse the normal direction. That also means we are inside the sphere so set
            //the inside bool to true. Finally reverse the sign of IdotN which we want
            //positive.
            float bias   = 0.0001f; //add some bias to the point from which we will be tracing
            bool  inside = false;

            if (raydir.dot(nhit) > 0)
            {
                nhit   = -1 * nhit;
                inside = true;
            }

            if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH)
            {
                float facingratio = -raydir.dot(nhit);

                // change the mix value to tweak the effect
                float fresneleffect = mix((float)Math.Pow(1 - facingratio, 3), 1, 0.1f);

                // compute reflection direction (not need to normalize because all vectors
                // are already normalized)
                Vec3f refldir = raydir - nhit * 2 * raydir.dot(nhit);
                refldir.normalize();
                Vec3f reflection = trace(phit + nhit * bias, refldir, spheres, depth + 1);
                Vec3f refraction = new Vec3f(0.0f);

                // if the sphere is also transparent compute refraction ray (transmission)
                if (sphere.transparency != 0.0f)
                {
                    float ior     = 1.1f;
                    float eta     = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
                    float cosi    = -nhit.dot(raydir);
                    float k       = 1 - eta * eta * (1 - cosi * cosi);
                    Vec3f refrdir = raydir * eta + nhit * (eta * cosi - (float)Math.Sqrt(k));
                    refrdir.normalize();
                    refraction = trace(phit - nhit * bias, refrdir, spheres, depth + 1);
                }

                // the result is a mix of reflection and refraction (if the sphere is transparent)
                surfaceColor = (reflection * fresneleffect + refraction * (1.0f - fresneleffect) * sphere.transparency) * sphere.surfaceColor;
            }
            else
            {
                // it's a diffuse object, no need to raytrace any further
                for (int i = 0; i < spCount; ++i)
                {
                    if (spheres[i].emissionColor.x > 0)
                    {
                        // this is a light
                        Vec3f transmission   = new Vec3f(1.0f);
                        Vec3f lightDirection = spheres[i].center - phit;
                        lightDirection.normalize();

                        for (int j = 0; j < spCount; ++j)
                        {
                            if (i != j)
                            {
                                if (spheres[j].intersect(phit + nhit * bias, lightDirection).Item1)
                                {
                                    transmission = new Vec3f(0.0f);
                                    break;
                                }
                            }
                        }

                        surfaceColor += sphere.surfaceColor * transmission * Math.Max(0.0f, nhit.dot(lightDirection)) * spheres[i].emissionColor;
                    }
                }
            }

            return(surfaceColor + sphere.emissionColor);
        }