예제 #1
0
        public Color Shade(Ray ray, Scene scene, int depth)
        {
            if (depth == 0)
            {
                var ambient = scene.AmbientLight.Color;
                return(new Color(ambient.R, ambient.G, ambient.B));
            }

            HitInfo hitInfo = new HitInfo();

            if (scene.HitTest(ray, ref hitInfo, 0.001f, float.PositiveInfinity))
            {
                var emitted =
                    hitInfo.ModelHit.Material.Emitted(hitInfo.TexCoord.X, hitInfo.TexCoord.Y);

                if (hitInfo.ModelHit.Material.Scatter(ref ray, ref hitInfo, out Color attenuation, out Ray scattered))
                {
                    return(emitted + attenuation * Shade(scattered, scene, depth - 1));
                }

                return(emitted);
            }

            return(scene.AmbientLight.Color);
        }
예제 #2
0
        public override void Render(Scene scene, Camera camera)
        {
            scene.Preprocess();

            if (camera is LensCamera lensCamera && lensCamera.AutoFocus)
            {
                var ray     = lensCamera.GetRay(0.5f, 0.5f);
                var hitInfo = new HitInfo();
                var hit     = scene.HitTest(ray, ref hitInfo, 0.001f, float.PositiveInfinity);
                if (hit)
                {
                    lensCamera.FocusDistance = hitInfo.Distance;
                }
                else
                {
                    lensCamera.FocusDistance = 100000f;
                }
            }

            int width  = Resolution;
            int height = (int)(width / camera.AspectRatio);
            var image  = new Texture(width, height);
            AbstractSampler <Vector2> sampler = new ThreadSafeSampler <Vector2>(Sampling, Samples);

            for (int k = 0; k < Samples; k++)
            {
                try
                {
                    Parallel.For(0, width, new ParallelOptions {
                        CancellationToken = CancellationToken
                    }, i =>
                    {
                        for (int j = 0; j < height; j++)
                        {
                            var sample = sampler.GetSample(k);
                            float u    = (i + sample.X) / (width - 1);
                            float v    = (j + sample.Y) / (height - 1);
                            Ray ray    = camera.GetRay(u, v);
                            var shade  = Shade(ray, scene, MaxDepth);
                            image.Bloom(shade, i, j, (int)shade.GetBrightness(), Bloom);
                            image[i, j] += shade;
                        }
                    });
                }
                catch (Exception e)
                {
                    Log.Warn(e);
                }

                if (CancellationToken.IsCancellationRequested)
                {
                    return;
                }

                if (k % SamplesRenderStep == 0 || k == Samples - 1)
                {
                    var output = new Texture(image);
                    output.Process(c => (c / (k + 1)).Clamp());
                    if (GammaCorrection)
                    {
                        output.AutoGammaCorrect();
                    }
                    var percentage = (k + 1) * 100 / Samples;
                    OnFrameReady?.Invoke(percentage, output);
                }
            }
        }
예제 #3
0
        private Color Trace(ref Ray ray, Scene scene, int depth)
        {
            HitTestResult hittest = scene.HitTest(ref ray);

            if (hittest == null)
            {
                return(Color.Black);
            }

            var d          = hittest.Ray.Direction;
            var pos        = hittest.Distance * hittest.Ray.Direction + hittest.Ray.Position; //交点位置
            var normal     = hittest.Shape.GetNormal(pos);                                    //交点法向量
            var cosa       = normal * d;                                                      //-Cos(入射角)
            var reflectDir = d - 2 * cosa * normal;                                           //反射方向

            Color color;

            if (cosa < 0)
            {
                color = GetNaturalColor(hittest.Shape, ref pos, ref normal, ref reflectDir, scene);
            }
            else
            {
                color = Color.Black;
            }
            if (depth <= 0)
            {
                return(color);
            }
            depth--;

            //追踪反射光线
            var ray1    = new Ray(pos, reflectDir);
            var rcolor1 = Trace(ref ray1, scene, depth);

            rcolor1.Multiply(hittest.Shape.Surface.Specular(pos));

            //追踪折射光线
            var n = hittest.Shape.Surface.Refraction(pos);// 折射率

            if (n > 0)
            {
                if (cosa > 0)
                {
                    n = 1 / n;
                }

                var f = Math.Acos(-cosa);                      //入射角
                var t = Math.Asin(Math.Sqrt(1 - cosa * cosa)); //折射角

                //fresnel公式,计算反射比
                double s1     = Math.Sin(f - t);
                double s2     = Math.Sin(f + t);
                double t1     = Math.Tan(f - t);
                double t2     = Math.Tan(f + t);
                var    factor = (float)(((s1 * s1) / (s2 * s2) + (t1 * t1) / (t2 * t2)) / 2);

                if (factor < 1 && factor >= 0) //等于1时发生了全反射
                {
                    rcolor1.Multiply(factor);

                    //折射定律矢量形式:n2 * e2 - n1 * e1 = (n2 * cos(t) - n1 * cos(f)) * normal
                    var dir = ((float)(n * Math.Cos(t) - Math.Cos(f)) * normal) * (1 / n);
                    dir.Normalize();
                    var ray2 = new Ray(pos, dir);

                    var rcolor2 = Trace(ref ray2, scene, depth);
                    rcolor2.Multiply(1 - factor);
                    color.Add(ref rcolor2);
                }
            }

            color.Add(ref rcolor1);

            return(color);
        }