示例#1
0
 public Sphere(string name, Vector3 center, float radius, Color color, ITexture texture = null, bool isWall = false, float brightness = 1f, float reflectiveness = 0.2f)
 {
     _name           = name;
     _centerVector   = center;
     _radius         = radius;
     _color          = color;
     _brightness     = brightness;
     _rgb            = Conversions.FromColor(_color);
     _texture        = texture;
     _isWall         = isWall;
     _reflectiveness = reflectiveness;
 }
示例#2
0
        public WriteableBitmap GetBitmap(int width, int height, double dpiX, double dpiY)
        {
            var fromRGB = Conversions.FromColor(_fromColor);
            var toRGB   = Conversions.FromColor(_toColor);

            // 4 channels (blue, green, red, alpha). Order of channels is important!
            int channels = 4;

            byte[] pixels = new byte[width * height * channels];

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    var rgb   = Vector3.Lerp(fromRGB, toRGB, i / (float)width);
                    var color = Conversions.FromRGB(rgb, gammaCorrection: j < (height / 2));

                    color.Clamp();

                    var pos = (j * width * channels) + (i * channels);

                    // blue channel
                    pixels[pos + 0] = color.B;

                    // green channel
                    pixels[pos + 1] = color.G;

                    // red channel
                    pixels[pos + 2] = color.R;

                    // alpha channel
                    pixels[pos + 3] = byte.MaxValue;
                }
            }

            var bitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Bgra32, BitmapPalettes.Halftone256);

            bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * channels, 0);

            return(bitmap);
        }
示例#3
0
        public bool CalcColorDeferred(int x, int y, LightSource[] lightSources, float z, out Vector3 rgb)
        {
            rgb = Vector3.Zero;

            var  p         = new Vector2(x, y);
            var  AP        = p - _a.ScreenPosition;
            var  vec       = _barryCentricMatrixInverse * AP;
            var  u         = vec.X;
            var  v         = vec.Y;
            bool drawPoint = (u >= 0 && v >= 0 && (u + v) < 1);

            if (drawPoint)
            {
                var interpolatedPosition = _a.HomogenousPosition + u * (_b.HomogenousPosition - _a.HomogenousPosition) + v * (_c.HomogenousPosition - _a.HomogenousPosition);
                var position             = interpolatedPosition.HomogenousNormalize();

                if (position.Z == z)
                {
                    var material = Vector3.Zero;

                    if (_options.SingleColor)
                    {
                        material = new Vector3(1, 0, 0); // red
                    }
                    else
                    {
                        if (_options.Texture == null)
                        {
                            var interpolatedMaterial = _a.HomogenousColor + u * (_b.HomogenousColor - _a.HomogenousColor) + v * (_c.HomogenousColor - _a.HomogenousColor);
                            material = interpolatedMaterial.HomogenousNormalize();
                        }
                        else
                        {
                            var interpolatedTexture = _a.HomogenousTexturePosition + u * (_b.HomogenousTexturePosition - _a.HomogenousTexturePosition) + v * (_c.HomogenousTexturePosition - _a.HomogenousTexturePosition);
                            var texturePosition     = interpolatedTexture.HomogenousNormalize();
                            material = _options.Texture.CalcColor(texturePosition.X, texturePosition.Y, _options.BilinearFilter, _options.GammaCorrect);
                        }
                    }

                    var interpolatedNormal = Vector3.Normalize(_a.Normal + u * (_b.Normal - _a.Normal) + v * (_c.Normal - _a.Normal));

                    for (int i = 0; i < lightSources.Length; i++)
                    {
                        var lightSource = lightSources[i];

                        var lVec = lightSource.Center - position;

                        // Gibt dasselbe für lVec:
                        // lVec = (new Vector4(lightSource.Center, w: 1) - interpolatedPosition).HomogenousNormalize();

                        var lVecNorm = Vector3.Normalize(lVec);
                        //var nVecNorm = _currentSurfaceNormal;
                        var nVecNorm = interpolatedNormal;

                        var light = Conversions.FromColor(lightSource.Color);

                        // Diffuse Lambert
                        var dot_diffuse = Vector3.Dot(nVecNorm, lVecNorm);

                        if (_options.DiffuseLambert &&
                            dot_diffuse > 0)
                        {
                            var diffuse = Vector3.Multiply(light, material) * dot_diffuse;
                            rgb += diffuse;
                        }

                        // Specular Phong
                        var eye        = new Vector3(0, 0, 0);
                        var rayVecNorm = Vector3.Normalize(position - eye);

                        var sVec      = (lVec - ((Vector3.Dot(lVec, nVecNorm)) * nVecNorm));
                        var rVec      = lVec - (2 * sVec);
                        var dot_phong = -Vector3.Dot(Vector3.Normalize(rVec), rayVecNorm);

                        if (_options.SpecularPhong &&
                            dot_phong > 0)
                        {
                            var specular = light * (float)Math.Pow(dot_phong, _options.SpecularPhongFactor);
                            rgb += specular;
                        }
                    }

                    return(true);
                }
            }

            return(false);
        }
示例#4
0
        private Vector3 CalcColor(Ray ray, int pathTracingLimit, int reflectionLimit)
        {
            var rgb = Vector3.Zero;

            var hitPoint = FindClosestHitPoint(ray);

            if (hitPoint != null)
            {
                var sphere = hitPoint.Sphere;

                var rayVecNorm  = Vector3.Normalize(hitPoint.Ray.DirectionVec);
                var rayVec      = (hitPoint.Ray.Lambda * rayVecNorm) + (-rayVecNorm * 0.001f) /* nudging..? */;
                var hitPointVec = hitPoint.Ray.StartVec + rayVec;
                var nVecNorm    = Vector3.Normalize(hitPointVec - hitPoint.Sphere.Center);

                var material = sphere.CalcColor(hitPointVec);

                if (!PathTracing)
                {
                    if (sphere.Brightness > 0)
                    {
                        rgb += material * sphere.Brightness;
                    }

                    if (Reflection)
                    {
                        // Reflection
                        if (!sphere.IsWall && /* ignore walls */
                            reflectionLimit > 0)
                        {
                            var reflectionMaterial = Conversions.FromColor(Colors.White);

                            var refVecNorm      = Vector3.Normalize(rayVecNorm - 2 * Vector3.Dot(nVecNorm, rayVecNorm) * nVecNorm);
                            var refVec2         = refVecNorm + (Vector3.One - refVecNorm) * (float)Math.Pow((1 - Vector3.Dot(nVecNorm, refVecNorm)), 5);
                            var reflectionRay   = new Ray(hitPointVec, refVec2);
                            var reflectionColor = CalcColor(reflectionRay, 0, --reflectionLimit);
                            var reflection      = Vector3.Multiply(reflectionColor, reflectionMaterial) * 0.25f;
                            rgb += reflection;
                        }
                    }

                    for (int i = 0; i < _lightSources.Length; i++)
                    {
                        var lightSource = _lightSources[i];

                        var lVec     = lightSource.Center - hitPointVec;
                        var lVecNorm = Vector3.Normalize(lVec);

                        var light_cos = Vector3.Dot(nVecNorm, lVecNorm);

                        if (light_cos >= 0)
                        {
                            var light = Conversions.FromColor(lightSource.Color);

                            if (Shadows)
                            {
                                if (SoftShadows)
                                {
                                    light_cos *= GetShadowedRatio(hitPointVec, lightSource);
                                }
                                else
                                {
                                    // Shadows
                                    if (HasObjectInFrontOfLightSource(hitPointVec, lightSource.Center))
                                    {
                                        light_cos *= 0.01f;
                                    }
                                }
                            }

                            if (DiffuseLambert)
                            {
                                // Diffuse "Lambert"
                                var diffuse = Vector3.Multiply(light, material) * light_cos;
                                rgb += diffuse;
                            }

                            if (SpecularPhong)
                            {
                                // Ignore walls
                                if (!sphere.IsWall)
                                {
                                    // Specular "Phong"
                                    var sVec     = (lVec - ((Vector3.Dot(lVec, nVecNorm)) * nVecNorm));
                                    var rVec     = lVec - (2 * sVec);
                                    var specular = light * (float)Math.Pow((Vector3.Dot(Vector3.Normalize(rVec), rayVecNorm)), SpecularPhongFactor);
                                    rgb += specular;
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (pathTracingLimit > 0)
                    {
                        var numberOfRandomRays = 0;

                        bool isBounced = pathTracingLimit < PathTracingMaxBounces;

                        if (!isBounced)
                        {
                            numberOfRandomRays = PathTracingRays;
                        }
                        else
                        {
                            var russianRoulette = (float)_random.NextDouble();

                            if (russianRoulette > 0.2f)
                            {
                                numberOfRandomRays = 1;
                            }
                        }

                        if (numberOfRandomRays > 0)
                        {
                            // Source: https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation

                            Vector3 indirectDiffuse = Vector3.Zero;

                            Vector3 ntVec = Vector3.Zero;

                            if (Math.Abs(nVecNorm.X) > Math.Abs(nVecNorm.Y))
                            {
                                ntVec = (new Vector3(nVecNorm.Z, 0, -nVecNorm.X) / (float)Math.Sqrt(nVecNorm.X * nVecNorm.X + nVecNorm.Z * nVecNorm.Z));
                            }
                            else
                            {
                                ntVec = (new Vector3(0, -nVecNorm.Z, nVecNorm.Y) / (float)Math.Sqrt(nVecNorm.Y * nVecNorm.Y + nVecNorm.Z * nVecNorm.Z));
                            }

                            var nbVec = Vector3.Cross(nVecNorm, ntVec);

                            for (int i = 0; i < numberOfRandomRays; i++)
                            {
                                var cosTheta = (float)_random.NextDouble();
                                var phi      = (float)(_random.NextDouble() * 2 * Math.PI);

                                var   sinTheta = (float)Math.Sqrt(1 - cosTheta * cosTheta);
                                float x        = sinTheta * (float)Math.Cos(phi);
                                float z        = sinTheta * (float)Math.Sin(phi);

                                var sampleLocalVec = new Vector3(x, cosTheta, z);
                                var sampleWorldVec = new Vector3()
                                {
                                    X = sampleLocalVec.X * nbVec.X + sampleLocalVec.Y * nVecNorm.X + sampleLocalVec.Z * ntVec.X,
                                    Y = sampleLocalVec.X * nbVec.Y + sampleLocalVec.Y * nVecNorm.Y + sampleLocalVec.Z * ntVec.Y,
                                    Z = sampleLocalVec.X * nbVec.Z + sampleLocalVec.Y * nVecNorm.Z + sampleLocalVec.Z * ntVec.Z
                                };

                                var randomRay = new Ray(hitPointVec, sampleWorldVec);
                                indirectDiffuse += CalcColor(randomRay, pathTracingLimit - 1, 0) * cosTheta;
                            }

                            indirectDiffuse /= numberOfRandomRays * _pdf;

                            rgb += Vector3.Multiply(indirectDiffuse, material) * sphere.Reflectiveness;
                        }
                        else
                        {
                            rgb += material * sphere.Brightness;
                        }
                    }
                    else
                    {
                        rgb += material * sphere.Brightness;
                    }
                }
            }

            return(rgb);
        }