Color[] CreateColorForTestHitRecord(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            hitableList.list.Add(new SimpleSphere(new Vector3(0, 0, -1), 0.5f));  //第一个参数是球心  第2个参数是半径
            hitableList.list.Add(new SimpleSphere(new Vector3(0, -100.5f, -1), 100f));
            Color[] colors = new Color[l];

            float recip_width  = 1f / width;  // 1/400
            float recip_height = 1f / height; // 1/200

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Ray r = new Ray(original, lowLeftCorner + horizontal * i / recip_width + vertical * j / recip_height);
                    colors[i + j * width] = GetColorForTestHitRecord(r, hitableList);
                }
            }
            return(colors);
        }
        Color GetColorForTestMetal(Ray ray, HitableList hitableList, int depth)
        {
            HitRecord record = new HitRecord();

            // 当光线撞击在球上的时候  // 这里包括了法线毛绒球和两个金属球
            if (hitableList.Hit(ray, 0.0001f, float.MaxValue, ref record))
            {
                Ray   r           = new Ray(Vector3.zero, Vector3.zero);
                Color attenuation = Color.black;

                // 说一下scatter 调用中的 ref 关键字   这个表示按照引用传递  因此后面运算中的attenuation 的值是材质本身设定的衰减值  并不是black
                // material 是 Metal  和 漫反射的毛绒球(兰伯特光照)  不同的材质对scatter 有不同的实现
                if (depth < MAX_SCATTER_TIME / 10 && record.material.scatter(ray, record, ref attenuation, ref r))
                {
                    Color c = GetColorForTestMetal(r, hitableList, depth + 1); //将镜面反射的光线再次进行碰撞计算
                    return(new Color(c.r * attenuation.r, c.g * attenuation.g, c.b * attenuation.b));
                }
                else
                {
                    //假设已经反射了太多次,或者压根就没有发生反射,那么就认为黑了
                    return(Color.black);
                }
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
        Color[] CreateColorForTestAntialiasing(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            hitableList.list.Add(new SimpleSphere(new Vector3(0, 0, -1), 0.5f));
            hitableList.list.Add(new SimpleSphere(new Vector3(0, -100.5f, -1), 100f));
            Color[]      colors       = new Color[l];
            SimpleCamera camera       = new SimpleCamera(original, lowLeftCorner, horizontal, vertical);
            float        recip_width  = 1f / width;
            float        recip_height = 1f / height;

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestAntialiasing(r, hitableList);
                    }
                    color  *= SAMPLE_WEIGHT;
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
        public static HitableList CreateRandomScene()
        {
            HitableList list = new HitableList();

            list.list.Add(new Sphere(new Vector3(0f, -1000f, 0f), 1000f, new Lambertian(Color.gray)));
            for (int a = -4; a < 4; a++)
            {
                for (int b = -4; b < 4; b++)
                {
                    float   choose_mat = R();
                    Vector3 center     = new Vector3(a + 0.9f * R(), 0.2f, b + 0.9f * R());
                    if (Vector3.Distance(center, new Vector3(4, 0.2f, 4)) > 0.9f)
                    {
                        if (choose_mat < 0.8f)
                        {
                            list.list.Add(new Sphere(center, 0.2f, new Lambertian(new Color(R() * R(), R() * R(), R() * R()))));
                        }
                        else if (choose_mat < 0.95f)
                        {
                            list.list.Add(new Sphere(center, 0.2f, new Metal(new Color(0.5f + 0.5f * R(), 0.5f + 0.5f * R(), 0.5f + 0.5f * R()), 0.5f * R())));
                        }
                        else
                        {
                            list.list.Add(new Sphere(center, 0.2f, new Dielectirc(1.5f)));
                        }
                    }
                }
            }
            list.list.Add(new Sphere(new Vector3(0, 1, 0), 1, new Dielectirc(1.5f)));
            list.list.Add(new Sphere(new Vector3(-4, 1, 0), 1, new Lambertian(new Color(0.9f, 0.5f, 0.1f))));
            list.list.Add(new Sphere(new Vector3(4, 1, 0), 1, new Metal(new Color(0.7f, 0.6f, 0.5f), 0.01f)));
            return(list);
        }
        Color[] CreateColorForTestRandomBalls(int width, int height)
        {
            // 在simpleCamer中视锥体的左下角、长宽和起始扫射点设定
            // Vector3 lowLeftCorner = new Vector3(-2, -1, -3);
            // 对于camera 视锥体的大小由lookAt 和 lookFrom 决定

            Vector3 horizontal = new Vector3(4, 0, 0);
            Vector3 vertical   = new Vector3(0, 2, 0);
            Vector3 original   = new Vector3(0, 0, 0);
            //在simpleCamera 中的摄像机的光线出发点一般就是origin
            //但是Camera中的ray出发点是 lookFrom

            int l = width * height;
            //这里注释的两句话是随机场景渲染用的……
            //三个大球的位置 金属球(0, 1, 0)  漫反射(-4, 1, 0)  玻璃球(4, 1, 0) 且半径都是1
            HitableList hitableList = _M.CreateRandomScene();

            Color[] colors = new Color[l];

            // from(0 1 0) to(10 1 0) 和 from(0 1 0) to (1 1 0) 理论上效果一样?Yes
            // from(0 1 0) to (1 1 0) 和 from(2 1 0) to (3 1 0) 理论上效果一样?Yes
            // from(2.5f, 1, -6) to(2.5f, 1, 6)应该可以看到3个球? Yes
            // from(2.5f, 3, -3) to(-5, 1, 3) //视野范围3的话(3+3)其实还不够  有较大形变
            // 所以后面采用了6
            Vector3 from = new Vector3(5f, 3, -6);
            Vector3 to   = new Vector3(-5, 1, 6);


            // vup 这里并不是摄像头的位置 // vup 是用来控制摄像头围绕lookup的方向旋转的
            Camera camera = new Camera(from, to, new Vector3(0, 30, 0), 50, width / height);
            //Camera camera = new Camera(from, to, Vector3.up, 35, width / height);
            float recip_width  = 1f / width;
            float recip_height = 1f / height;

            for (int j = 0; j <= height - 1; j++)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestCamera(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
                EditorUtility.DisplayProgressBar("", "", j / (float)height);
            }
            EditorUtility.ClearProgressBar();
            return(colors);
        }
        Color[] CreateColorForTestCamera(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            //紫色球
            hitableList.list.Add(new Sphere(new Vector3(0, 0, -1), 0.5f, new Lambertian(new Color(0.8f, 0.3f, 0.3f))));

            //下方的绿色球
            hitableList.list.Add(new Sphere(new Vector3(0, -100.5f, -1), 100f, new Lambertian(new Color(0.8f, 0.8f, 0.0f))));

            // 右侧的蓝色球 调整FOV后在最上方
            hitableList.list.Add(new Sphere(new Vector3(1, 0, -1), 0.5f, new Metal(new Color(0.2f, 0.6f, 0.9f), 0f)));

            // 左侧的玻璃球 调整FOV后就是离相机最近的位置
            hitableList.list.Add(new Sphere(new Vector3(-1, 0, -1), 0.5f, new Dielectirc(1.5f)));

            Color[] colors = new Color[l];

            // 从左上角向下俯视
            // Vector3.up 就是 Vector3(0, 1, 0).

            //public Camera(Vector3 lookFrom, Vector3 lookat, Vector3 vup, float vfov, float aspect, float r = 0, float focus_dist = 1)
            // vfov 似乎在控制相机和物体的远近 值越小越近
            Camera camera = new Camera(new Vector3(-2, 2f, 1), new Vector3(0, 0, -1), Vector3.up, 25, width / height);


            float recip_width  = 1f / width;
            float recip_height = 1f / height;

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE / 10; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestCamera(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT * 10;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
        Color GetColorForTestAntialiasing(Ray ray, HitableList hitableList)
        {
            HitRecord record = new HitRecord();

            if (hitableList.Hit(ray, 0f, float.MaxValue, ref record))
            {
                return(0.5f * new Color(record.normal.x + 1, record.normal.y + 1, record.normal.z + 1, 2f));
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
        Color[] CreateColorForTestMetal(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-4, -1, -1);
            Vector3     horizontal    = new Vector3(8, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            hitableList.list.Add(new Sphere(new Vector3(0, 0, -1), 0.5f, new Lambertian(new Color(0.3f, 0.3f, 0.3f))));
            hitableList.list.Add(new Sphere(new Vector3(0, -100.5f, -1), 100f, new Lambertian(new Color(0.8f, 0.8f, 0.0f))));
            hitableList.list.Add(new Sphere(new Vector3(-1, 0, -1), 0.5f, new Metal(new Color(0.8f, 0.8f, 0.8f), 0.3f))); //Metal 的带个参数是albedo 反照率
            hitableList.list.Add(new Sphere(new Vector3(1, 0, -1), 0.5f, new Metal(new Color(0.8f, 0.8f, 0.8f), 0.0f)));  // 设置fuzz为0  表示一个干净的镜面
            Color[] colors = new Color[l];

            //之前的视觉锥体变形比较厉害  现在把摄像机离远一点
            //右手坐标系  屏幕的z轴是 -1
            SimpleCamera camera       = new SimpleCamera(original + new Vector3(0, 0, 3), lowLeftCorner, horizontal, vertical);
            float        recip_width  = 1f / width;
            float        recip_height = 1f / height;

            // Debug.LogFormat("Hitable discriminant {0} {1}", recip_width, recip_height);

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    if (i % 10 == 0 && j % 10 == 0)
                    {
                        Debug.LogFormat("r u v {0} {1}    {2} {3}", i, j, (i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                    }

                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE / 10; s++)
                    {
                        // 光线的出发点就是摄像机
                        // (i + _M.R()) * recip_width 都是小范围发散光线
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);



                        color += GetColorForTestMetal(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT * 10f;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
        Color GetColorForTestHitRecord(Ray ray, HitableList hitableList)
        {
            HitRecord record = new HitRecord();

            if (hitableList.Hit(ray, 0f, float.MaxValue, ref record))
            {
                // 没有直接返回 record.normal.xyz 是因为默认颜色有点暗
                return(0.5f * new Color(record.normal.x + 1, record.normal.y + 1, record.normal.z + 1, 2f));
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            // 控制浅蓝的背景色
            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
        Color GetColorForTestDiffusing(Ray ray, HitableList hitableList)
        {
            HitRecord record = new HitRecord();

            if (hitableList.Hit(ray, 0.0001f, float.MaxValue, ref record))
            {
                Vector3 target = record.p + record.normal + GetRandomPointInUnitSphereForTestDiffusing();
                //此处假定有50%的光被吸收,剩下的则从入射点开始取随机方向再次发射一条射线
                return(0.5f * GetColorForTestDiffusing(new Ray(record.p, target - record.p), hitableList));
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
Ejemplo n.º 11
0
        // 测试透明模型
        // 传统右手坐标系 Z值越小 离人眼越近
        // 之前调整参数 光源在 0 0 3 的位置
        // 屏幕Z轴在 -3 的位置
        Color[] CreateColorForTestDielectric(int width, int height)
        {
            // 透明材料(例如水,玻璃和钻石)是电介质。 当光线射到它们上时,它分裂为反射射线和折射(透射)射线。

            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -3);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            // 漫反射 中间的红色金属球
            hitableList.list.Add(new Sphere(new Vector3(0, 0, -1), 0.5f, new Lambertian(new Color(0.8f, 0.3f, 0.3f))));

            // 漫反射 //底部的绿色球
            hitableList.list.Add(new Sphere(new Vector3(0, -100.5f, -1), 100f, new Lambertian(new Color(0.8f, 0.8f, 0.0f))));

            // 右侧的金属球
            hitableList.list.Add(new Sphere(new Vector3(1, 0, -1), 0.5f, new Metal(new Color(0.8f, 0.6f, 0.2f), 0f)));

            // 左侧透明球
            hitableList.list.Add(new Sphere(new Vector3(-1, 0, -1), 0.5f, new Dielectirc(1.5f)));
            // 1.3 是水的折射率  玻璃折射率是1.5

            Color[] colors = new Color[l];
            // 为了减小形变  让摄像头离屏幕远一点
            SimpleCamera camera       = new SimpleCamera(original + new Vector3(0, 0, 3), lowLeftCorner, horizontal, vertical);
            float        recip_width  = 1f / width;
            float        recip_height = 1f / height;

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE / 10; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestDielectric(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT * 10f;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
Ejemplo n.º 12
0
        Color[] CreateColorForTestAntialiasing(int width, int height)
        {
            // width height 是像素点单位400  200
            // 视锥体的左下角、长宽和起始扫射点设定

            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            //这样的球在偏右的位置
            //hitableList.list.Add(new SimpleSphere(new Vector3(1, 0, -1), 0.5f));
            hitableList.list.Add(new SimpleSphere(new Vector3(0, 0, -1), 0.5f));
            hitableList.list.Add(new SimpleSphere(new Vector3(0, -100.5f, -1), 100f));
            Color[] colors = new Color[l];


            // 摄像头在0 0 0的位置
            // 屏幕在 z轴 -1 的位置
            // 传统的右手坐标系
            SimpleCamera camera       = new SimpleCamera(original + new Vector3(0, 0, 3), lowLeftCorner, horizontal, vertical);
            float        recip_width  = 1f / width;  // 1/400
            float        recip_height = 1f / height; // 1/200

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);

                    // 每个像素点都再发射100条光线去采样计算
                    for (int s = 0; s < SAMPLE / 10; s++)
                    {
                        // _M.R() 生成0~1随机数
                        // 创建的ray  出发点在球心  也就是original  //注意 !! CreateRay包含了vertical 和 horizontal 的尺寸计算
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        //下面关闭抗锯齿的情形,就和第5版一样的
                        //Ray r = camera.CreateRay(i * recip_width, j * recip_height);
                        color += GetColorForTestAntialiasing(r, hitableList);
                    }
                    color  *= SAMPLE_WEIGHT * 10;
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
Ejemplo n.º 13
0
        Color GetColorForTestAntialiasing(Ray ray, HitableList hitableList)
        {
            HitRecord record = new HitRecord();

            // 实际上调用的是 SimpleSphere 的 Hit
            if (hitableList.Hit(ray, 0f, float.MaxValue, ref record))
            {
                // 这里+1 都是为了更好的视觉效果
                return(0.5f * new Color(record.normal.x + 1, record.normal.y + 1, record.normal.z + 1, 2f));
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            // 控制浅蓝的背景色
            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
        Color[] CreateColorForTestDefocus(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            //这里注释的两句话是随机场景渲染用的……
            //HitableList hitableList = _M.CreateRandomScene();
            hitableList.list.Add(new Sphere(new Vector3(0, 0, -1), 0.5f, new Lambertian(new Color(0.2f, 0.2f, 0.8f))));
            hitableList.list.Add(new Sphere(new Vector3(0, -100.5f, -1), 100f, new Lambertian(new Color(0.8f, 0.8f, 0.0f))));
            hitableList.list.Add(new Sphere(new Vector3(1, 0, -1), 0.5f, new Metal(new Color(0.8f, 0.6f, 0.2f), 0f)));
            hitableList.list.Add(new Sphere(new Vector3(-1, 0, -1), 0.5f, new Dielectirc(1.5f)));
            Color[] colors = new Color[l];
            Vector3 from   = new Vector3(10, 2f, -2);
            Vector3 to     = new Vector3(0, 1, 0);
            Camera  camera = new Camera(from, to, Vector3.up, 20, width / height, 2, (from - to).magnitude);
            //Camera camera = new Camera(from, to, Vector3.up, 35, width / height);
            float recip_width  = 1f / width;
            float recip_height = 1f / height;

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestDefocus(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
                EditorUtility.DisplayProgressBar("", "", j / (float)height);
            }
            EditorUtility.ClearProgressBar();
            return(colors);
        }
Ejemplo n.º 15
0
        // https://www.guokr.com/question/569971/
        // 光线追踪 如果遇到漫反射面的话一般是需要产生非常多的次级射线往下递归才能达到比较好的效果(否则噪点比较明显)
        Color GetColorForTestDiffusing(Ray ray, HitableList hitableList)
        {
            HitRecord record = new HitRecord();

            // 这里对应的是 simpleSphere 的 Hit 方法
            if (hitableList.Hit(ray, 0.0001f, float.MaxValue, ref record))
            {
                Vector3 target = record.p + record.normal + GetRandomPointInUnitSphereForTestDiffusing();
                //此处假定有50%的光被吸收,剩下的则从入射点开始取随机方向再次发射一条射线
                //return 0.5f * GetColorForTestDiffusing(new Ray(record.p, target - record.p), hitableList);

                // 即便文中说的是使用随机的光线 但是即使是漫反射 也还是和物体本身的法线方向相关的  //所以这里还需要考虑到法线
                return(0.5f * GetColorForTestDiffusing(new Ray(record.p, record.normal + GetRandomPointInUnitSphereForTestDiffusing() * 0.5f), hitableList));
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }
        Color[] CreateColorForTestCamera(int width, int height)
        {
            //视锥体的左下角、长宽和起始扫射点设定
            Vector3     lowLeftCorner = new Vector3(-2, -1, -1);
            Vector3     horizontal    = new Vector3(4, 0, 0);
            Vector3     vertical      = new Vector3(0, 2, 0);
            Vector3     original      = new Vector3(0, 0, 0);
            int         l             = width * height;
            HitableList hitableList   = new HitableList();

            hitableList.list.Add(new Sphere(new Vector3(0, 0, -1), 0.5f, new Lambertian(new Color(0.8f, 0.3f, 0.3f))));
            hitableList.list.Add(new Sphere(new Vector3(0, -100.5f, -1), 100f, new Lambertian(new Color(0.8f, 0.8f, 0.0f))));
            hitableList.list.Add(new Sphere(new Vector3(1, 0, -1), 0.5f, new Metal(new Color(0.8f, 0.6f, 0.2f), 0f)));
            hitableList.list.Add(new Sphere(new Vector3(-1, 0, -1), 0.5f, new Dielectirc(1.5f)));
            Color[] colors       = new Color[l];
            Camera  camera       = new Camera(new Vector3(-2, 1f, -1), new Vector3(-1, 0, -1), Vector3.up, 75, width / height);
            float   recip_width  = 1f / width;
            float   recip_height = 1f / height;

            for (int j = height - 1; j >= 0; j--)
            {
                for (int i = 0; i < width; i++)
                {
                    Color color = new Color(0, 0, 0);
                    for (int s = 0; s < SAMPLE; s++)
                    {
                        Ray r = camera.CreateRay((i + _M.R()) * recip_width, (j + _M.R()) * recip_height);
                        color += GetColorForTestCamera(r, hitableList, 0);
                    }
                    color *= SAMPLE_WEIGHT;
                    //为了使球体看起来更亮,改变gamma值
                    color   = new Color(Mathf.Sqrt(color.r), Mathf.Sqrt(color.g), Mathf.Sqrt(color.b), 1f);
                    color.a = 1f;
                    colors[i + j * width] = color;
                }
            }
            return(colors);
        }
        Color GetColorForTestDefocus(Ray ray, HitableList hitableList, int depth)
        {
            HitRecord record = new HitRecord();

            if (hitableList.Hit(ray, 0.0001f, float.MaxValue, ref record))
            {
                Ray   r           = new Ray(Vector3.zero, Vector3.zero);
                Color attenuation = Color.black;
                if (depth < MAX_SCATTER_TIME && record.material.scatter(ray, record, ref attenuation, ref r))
                {
                    Color c = GetColorForTestDefocus(r, hitableList, depth + 1);
                    return(new Color(c.r * attenuation.r, c.g * attenuation.g, c.b * attenuation.b));
                }
                else
                {
                    //假设已经反射了太多次,或者压根就没有发生反射,那么就认为黑了
                    return(Color.black);
                }
            }
            float t = 0.5f * ray.normalDirection.y + 1f;

            return((1 - t) * new Color(1, 1, 1) + t * new Color(0.5f, 0.7f, 1));
        }