示例#1
0
        private void PrefilterCubeMap()
        {
            if (!shouldPrefilter)
            {
                return;
            }

            if (useComputeShader)
            {
                lamberFilter.HarmonicOrder = 5;
                lamberFilter.RadianceMap   = inputCubemap;
                lamberFilter.Draw();
                renderSHEffect.InputSH = lamberFilter.PrefilteredLambertianSH;
            }
            else
            {
                lamberFilterNoCompute.HarmonicOrder = 5;
                lamberFilterNoCompute.RadianceMap   = inputCubemap;
                lamberFilterNoCompute.Draw();
                renderSHEffect.InputSH = lamberFilterNoCompute.PrefilteredLambertianSH;
            }

            renderSHEffect.SetOutput(outputCubemap);
            renderSHEffect.Draw();
        }
示例#2
0
        public static Dictionary <LightProbeComponent, FastList <Color3> > GenerateCoefficients(ISceneRendererContext context)
        {
            using (var cubemapRenderer = new CubemapSceneRenderer(context, 256))
            {
                // Create target cube texture
                var cubeTexture = Texture.NewCube(context.GraphicsDevice, 256, PixelFormat.R16G16B16A16_Float);

                // Prepare shader for SH prefiltering
                var lambertFiltering = new LambertianPrefilteringSHNoCompute(cubemapRenderer.DrawContext.RenderContext)
                {
                    HarmonicOrder = LambertHamonicOrder,
                    RadianceMap   = cubeTexture,
                };

                var lightProbesCoefficients = new Dictionary <LightProbeComponent, FastList <Color3> >();

                using (cubemapRenderer.DrawContext.PushRenderTargetsAndRestore())
                {
                    // Render light probe
                    context.GraphicsContext.CommandList.BeginProfile(Color.Red, "LightProbes");

                    int lightProbeIndex = 0;
                    foreach (var entity in context.SceneSystem.SceneInstance)
                    {
                        var lightProbe = entity.Get <LightProbeComponent>();
                        if (lightProbe == null)
                        {
                            continue;
                        }

                        var lightProbePosition = lightProbe.Entity.Transform.WorldMatrix.TranslationVector;
                        context.GraphicsContext.ResourceGroupAllocator.Reset(context.GraphicsContext.CommandList);

                        context.GraphicsContext.CommandList.BeginProfile(Color.Red, $"LightProbes {lightProbeIndex}");
                        lightProbeIndex++;

                        cubemapRenderer.Draw(lightProbePosition, cubeTexture);

                        context.GraphicsContext.CommandList.BeginProfile(Color.Red, "Prefilter SphericalHarmonics");

                        // Compute SH coefficients
                        lambertFiltering.Draw(cubemapRenderer.DrawContext);

                        var coefficients           = lambertFiltering.PrefilteredLambertianSH.Coefficients;
                        var lightProbeCoefficients = new FastList <Color3>();
                        for (int i = 0; i < coefficients.Length; i++)
                        {
                            lightProbeCoefficients.Add(coefficients[i] * SphericalHarmonics.BaseCoefficients[i]);
                        }

                        lightProbesCoefficients.Add(lightProbe, lightProbeCoefficients);

                        context.GraphicsContext.CommandList.EndProfile(); // Prefilter SphericalHarmonics

                        context.GraphicsContext.CommandList.EndProfile(); // Face XXX

                        // Debug render
                    }

                    context.GraphicsContext.CommandList.EndProfile(); // LightProbes
                }

                cubeTexture.Dispose();

                return(lightProbesCoefficients);
            }
        }
示例#3
0
        public static SkyboxResult Compile(SkyboxAsset asset, SkyboxGeneratorContext context)
        {
            if (asset == null)
            {
                throw new ArgumentNullException("asset");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            var result = new SkyboxResult {
                Skybox = new Skybox()
            };

            var parameters = context.Parameters;
            var skybox     = result.Skybox;

            skybox.Parameters = parameters;

            var cubemap = asset.CubeMap;

            if (cubemap == null)
            {
                return(result);
            }

            // load the skybox texture from the asset.
            var reference     = AttachedReferenceManager.GetAttachedReference(cubemap);
            var skyboxTexture = context.Content.Load <Texture>(BuildTextureForSkyboxGenerationLocation(reference.Url), ContentManagerLoaderSettings.StreamingDisabled);

            if (skyboxTexture.ViewDimension == TextureDimension.Texture2D)
            {
                var cubemapSize = (int)Math.Pow(2, Math.Ceiling(Math.Log(skyboxTexture.Width / 4) / Math.Log(2))); // maximum resolution is around horizontal middle line which composes 4 images.
                skyboxTexture = CubemapFromTextureRenderer.GenerateCubemap(context.Services, context.RenderDrawContext, skyboxTexture, cubemapSize);
            }
            else if (skyboxTexture.ViewDimension != TextureDimension.TextureCube)
            {
                result.Error($"SkyboxGenerator: The texture type ({skyboxTexture.ViewDimension}) used as skybox is not supported. Should be a Cubemap or a 2D texture.");
                return(result);
            }

            // If we are using the skybox asset for lighting, we can compute it
            // Specular lighting only?
            if (!asset.IsSpecularOnly)
            {
                // -------------------------------------------------------------------
                // Calculate Diffuse prefiltering
                // -------------------------------------------------------------------
                var lamberFiltering = new LambertianPrefilteringSHNoCompute(context.RenderContext)
                {
                    HarmonicOrder = (int)asset.DiffuseSHOrder,
                    RadianceMap   = skyboxTexture
                };
                lamberFiltering.Draw(context.RenderDrawContext);

                var coefficients = lamberFiltering.PrefilteredLambertianSH.Coefficients;
                for (int i = 0; i < coefficients.Length; i++)
                {
                    coefficients[i] = coefficients[i] * SphericalHarmonics.BaseCoefficients[i];
                }

                skybox.DiffuseLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("SphericalHarmonicsEnvironmentColor", lamberFiltering.HarmonicOrder));
                skybox.DiffuseLightingParameters.Set(SphericalHarmonicsEnvironmentColorKeys.SphericalColors, coefficients);
            }

            // -------------------------------------------------------------------
            // Calculate Specular prefiltering
            // -------------------------------------------------------------------
            var specularRadiancePrefilterGGX = new RadiancePrefilteringGGXNoCompute(context.RenderContext);

            var textureSize = asset.SpecularCubeMapSize <= 0 ? 64 : asset.SpecularCubeMapSize;

            textureSize = (int)Math.Pow(2, Math.Round(Math.Log(textureSize, 2)));
            if (textureSize < 64)
            {
                textureSize = 64;
            }

            // TODO: Add support for HDR 32bits
            var filteringTextureFormat = skyboxTexture.Format.IsHDR() ? skyboxTexture.Format : PixelFormat.R8G8B8A8_UNorm;

            //var outputTexture = Texture.New2D(graphicsDevice, 256, 256, skyboxTexture.Format, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess, 6);
            using (var outputTexture = Texture.New2D(context.GraphicsDevice, textureSize, textureSize, true, filteringTextureFormat, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 6))
            {
                specularRadiancePrefilterGGX.RadianceMap         = skyboxTexture;
                specularRadiancePrefilterGGX.PrefilteredRadiance = outputTexture;
                specularRadiancePrefilterGGX.Draw(context.RenderDrawContext);

                var cubeTexture = Texture.NewCube(context.GraphicsDevice, textureSize, true, filteringTextureFormat);
                context.RenderDrawContext.CommandList.Copy(outputTexture, cubeTexture);

                cubeTexture.SetSerializationData(cubeTexture.GetDataAsImage(context.RenderDrawContext.CommandList));

                skybox.SpecularLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("RoughnessCubeMapEnvironmentColor"));
                skybox.SpecularLightingParameters.Set(SkyboxKeys.CubeMap, cubeTexture);
            }
            // TODO: cubeTexture is not deallocated

            return(result);
        }
示例#4
0
        public static SkyboxResult Compile(SkyboxAsset asset, SkyboxGeneratorContext context)
        {
            if (asset == null)
            {
                throw new ArgumentNullException("asset");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            var result = new SkyboxResult {
                Skybox = new Skybox()
            };

            var parameters = context.Parameters;
            var skybox     = result.Skybox;

            skybox.Parameters = parameters;

            if (asset.Model != null)
            {
                var cubemap = ((SkyboxCubeMapModel)asset.Model).CubeMap;
                if (cubemap == null)
                {
                    return(result);
                }

                // load the skybox texture from the asset.
                var reference     = AttachedReferenceManager.GetAttachedReference(cubemap);
                var skyboxTexture = context.Content.Load <Texture>(BuildTextureForSkyboxGenerationLocation(reference.Url));
                if (skyboxTexture.Dimension != TextureDimension.TextureCube)
                {
                    result.Error("SkyboxGenerator: The texture used as skybox should be a Cubemap.");
                    return(result);
                }

                var shaderSource = asset.Model.Generate(context);
                parameters.Set(SkyboxKeys.Shader, shaderSource);

                // If we are using the skybox asset for lighting, we can compute it
                // TODO: This following code should be pluggable (like asset.Model.Generate(context);) but it is currently not
                if (asset.Usage != SkyboxUsage.Background)
                {
                    // -------------------------------------------------------------------
                    // Calculate Diffuse prefiltering
                    // -------------------------------------------------------------------
                    var lamberFiltering = new LambertianPrefilteringSHNoCompute(context.RenderContext)
                    {
                        HarmonicOrder = (int)asset.DiffuseSHOrder,
                        RadianceMap   = skyboxTexture
                    };
                    lamberFiltering.Draw(context.RenderDrawContext);

                    var coefficients = lamberFiltering.PrefilteredLambertianSH.Coefficients;

                    // TODO: MOVE THE COEFFICIENTS TO THE SphericalHarmonics type in Core.Mathematics
                    var PI4     = 4 * Math.PI;
                    var PI16    = 16 * Math.PI;
                    var PI64    = 64 * Math.PI;
                    var SQRT_PI = 1.77245385090551602729;

                    var bases = new float[coefficients.Length];
                    bases[0] = (float)(1.0 / (2.0 * SQRT_PI));

                    bases[1] = (float)(-Math.Sqrt(3.0 / PI4));
                    bases[2] = (float)(Math.Sqrt(3.0 / PI4));
                    bases[3] = (float)(-Math.Sqrt(3.0 / PI4));

                    bases[4] = (float)(Math.Sqrt(15.0 / PI4));
                    bases[5] = (float)(-Math.Sqrt(15.0 / PI4));
                    bases[6] = (float)(Math.Sqrt(5.0 / PI16));
                    bases[7] = (float)(-Math.Sqrt(15.0 / PI4));
                    bases[8] = (float)(Math.Sqrt(15.0 / PI16));

                    if (asset.DiffuseSHOrder == SkyboxPreFilteringDiffuseOrder.Order5)
                    {
                        bases[9]  = -(float)Math.Sqrt(7 / PI64);
                        bases[10] = (float)Math.Sqrt(105 / PI4);
                        bases[11] = -(float)Math.Sqrt(21 / PI16);
                        bases[12] = (float)Math.Sqrt(7 / PI16);
                        bases[13] = -(float)Math.Sqrt(42 / PI64);
                        bases[14] = (float)Math.Sqrt(105 / PI16);
                        bases[15] = -(float)Math.Sqrt(70 / PI64);

                        bases[16] = 3 * (float)Math.Sqrt(35 / PI16);
                        bases[17] = -3 * (float)Math.Sqrt(70 / PI64);
                        bases[18] = 3 * (float)Math.Sqrt(5 / PI16);
                        bases[19] = -3 * (float)Math.Sqrt(10 / PI64);
                        bases[20] = (float)(1.0 / (16.0 * SQRT_PI));
                        bases[21] = -3 * (float)Math.Sqrt(10 / PI64);
                        bases[22] = 3 * (float)Math.Sqrt(5 / PI64);
                        bases[23] = -3 * (float)Math.Sqrt(70 / PI64);
                        bases[24] = 3 * (float)Math.Sqrt(35 / (4 * PI64));
                    }

                    for (int i = 0; i < coefficients.Length; i++)
                    {
                        coefficients[i] = coefficients[i] * bases[i];
                    }

                    skybox.DiffuseLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("SphericalHarmonicsEnvironmentColor", lamberFiltering.HarmonicOrder));
                    skybox.DiffuseLightingParameters.Set(SphericalHarmonicsEnvironmentColorKeys.SphericalColors, coefficients);

                    // -------------------------------------------------------------------
                    // Calculate Specular prefiltering
                    // -------------------------------------------------------------------
                    var specularRadiancePrefilterGGX = new RadiancePrefilteringGGXNoCompute(context.RenderContext);

                    var textureSize = asset.SpecularCubeMapSize <= 0 ? 64 : asset.SpecularCubeMapSize;
                    textureSize = (int)Math.Pow(2, Math.Round(Math.Log(textureSize, 2)));
                    if (textureSize < 64)
                    {
                        textureSize = 64;
                    }

                    // TODO: Add support for HDR 32bits
                    var filteringTextureFormat = skyboxTexture.Format.IsHDR() ? skyboxTexture.Format : PixelFormat.R8G8B8A8_UNorm;

                    //var outputTexture = Texture.New2D(graphicsDevice, 256, 256, skyboxTexture.Format, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess, 6);
                    using (var outputTexture = Texture.New2D(context.GraphicsDevice, textureSize, textureSize, true, filteringTextureFormat, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 6)
                           )
                    {
                        specularRadiancePrefilterGGX.RadianceMap         = skyboxTexture;
                        specularRadiancePrefilterGGX.PrefilteredRadiance = outputTexture;
                        specularRadiancePrefilterGGX.Draw(context.RenderDrawContext);

                        var cubeTexture = Texture.NewCube(context.GraphicsDevice, textureSize, true, skyboxTexture.Format);
                        context.RenderDrawContext.CommandList.Copy(outputTexture, cubeTexture);

                        cubeTexture.SetSerializationData(cubeTexture.GetDataAsImage(context.RenderDrawContext.CommandList));

                        skybox.SpecularLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("RoughnessCubeMapEnvironmentColor"));
                        skybox.SpecularLightingParameters.Set(SkyboxKeys.CubeMap, cubeTexture);
                    }
                }
                // TODO: cubeTexture is not deallocated
            }

            return(result);
        }