// OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            // Create a camera node.
            CameraNode = new CameraNode(new Camera(new PerspectiveProjection()))
            {
                Name = "PlayerCamera"
            };

            // Add to scene.
            // (This is usually optional. Since cameras do not have a visual representation,
            // it  makes no difference if the camera is actually part of the scene graph or
            // not. - Except when other scene nodes are attached to the camera. In this case
            // the camera needs to be in the scene.)
            var scene = _services.GetInstance <IScene>();

            if (scene != null)
            {
                scene.Children.Add(CameraNode);
            }

            ResetPose();
            ResetProjection();

            // Add GUI controls to the Options window.
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "CameraObject");

            SampleHelper.AddSlider(
                panel,
                "Camera far distance",
                "F0",
                1,
                5000,
                _farDistance,
                value =>
            {
                _farDistance = value;
                ResetProjection();
            });

            SampleHelper.AddSlider(
                panel,
                "Position smoothing",
                "F2",
                0,
                1,
                positionFilter.TimeConstant,
                value => positionFilter.TimeConstant = value);

            SampleHelper.AddSlider(
                panel,
                "Orientation smoothing",
                "F2",
                0,
                1,
                orientationFilter.TimeConstant,
                value => orientationFilter.TimeConstant = value);
        }
Example #2
0
        // Add GUI controls to the Options window.
        private void CreateGuiControls()
        {
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "OceanObject");

            SampleHelper.AddCheckBox(
                panel,
                "Enable ocean",
                _waterNode.IsEnabled,
                isChecked => _waterNode.IsEnabled = isChecked);

            SampleHelper.AddCheckBox(
                panel,
                "Enable caustics",
                _waterNode.Water.CausticsSampleCount > 0,
                isChecked => _waterNode.Water.CausticsSampleCount = isChecked ? 4 : 0);
        }
Example #3
0
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        protected override void OnLoad()
        {
            // Get services.
            _inputService    = _services.GetInstance <IInputService>();
            _graphicsService = _services.GetInstance <IGraphicsService>();
            _scene           = _services.GetInstance <IScene>();
            var content           = _services.GetInstance <ContentManager>();
            var gameObjectService = _services.GetInstance <IGameObjectService>();

            // Get camera game object.
            _cameraObject = (CameraObject)gameObjectService.Objects["Camera"];

            // Create SkyNodes.
            InitializeSky(content);

            // Create LightNodes
            InitializeLights();

            // Optionally, the sky is captured into a cube map and the cube map is added
            // to the scene instead of all the sky nodes.
            if (_cacheSky)
            {
                // We use a SceneCaptureNode to create the cube map.
                // The cube map uses RGBM encoding to store HDR values.
                var renderToTexture = new RenderToTexture
                {
                    Texture = new RenderTargetCube(
                        _graphicsService.GraphicsDevice,
#if XBOX
                        512,
#else
                        1024,
#endif
                        true,
                        SurfaceFormat.Color,
                        DepthFormat.None),
                };
                var projection = new PerspectiveProjection();
                projection.SetFieldOfView(ConstantsF.PiOver2, 1, 1, 10);
                _sceneCaptureNode = new SceneCaptureNode(renderToTexture)
                {
                    // Note: The scene is captured at the origin (0, 0, 0).
                    CameraNode = new CameraNode(new Camera(projection)),
                };

                SkyboxNode = new SkyboxNode
                {
                    Encoding = ColorEncoding.Rgbm,
                    Texture  = (TextureCube)renderToTexture.Texture,
                };
                _scene.Children.Add(SkyboxNode);
            }

            // The Ephemeris class computes the positions of the sun and the moon as seen
            // from any place on the earth.
            _ephemeris = new Ephemeris
            {
                // Seattle, Washington
                //Latitude = 47,
                //Longitude = 122,
                //Altitude = 100

                // Vienna
                //Latitude = 48,
                //Longitude = -16,
                //Altitude = 0

                // Equator
                Latitude  = 0,
                Longitude = 0,
                Altitude  = 0
            };

            // Update the positions of sky objects and the lights.
            UpdateSky();

            // Create cube map.
            if (_cacheSky)
            {
                UpdateCubeMap(TimeSpan.Zero);
            }

            // Add GUI controls to the Options window.
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "DynamicSkyObject");

            SampleHelper.AddSlider(
                panel,
                "Time",
                "F2",
                0,
                24,
                (float)Time.TimeOfDay.TotalHours,
                value =>
            {
                var time = Time;
                time     = time.Subtract(time.TimeOfDay).Add(TimeSpan.FromHours(value));
                Time     = time;
            });

            SampleHelper.AddCheckBox(
                panel,
                "Enable ambient light",
                EnableAmbientLight,
                isChecked => EnableAmbientLight = isChecked);

            SampleHelper.AddSlider(
                panel,
                "Fog sample angle",
                "F2",
                0,
                ConstantsF.PiOver2,
                FogSampleAngle,
                value => FogSampleAngle = value);

            SampleHelper.AddSlider(
                panel,
                "Fog saturation",
                "F2",
                0,
                1,
                FogSaturation,
                value => FogSaturation = value);

            //SampleHelper.AddSlider(
            //  panel,
            //  "Fog scattering symmetry R",
            //  "F2",
            //  0,
            //  1,
            //  FogScatteringSymmetry.X,
            //  value => FogScatteringSymmetry = new Vector3F(value, FogScatteringSymmetry.Y, FogScatteringSymmetry.Z));
            //SampleHelper.AddSlider(
            //  panel,
            //  "Fog scattering symmetry G",
            //  "F2",
            //  0,
            //  1,
            //  FogScatteringSymmetry.Y,
            //  value => FogScatteringSymmetry = new Vector3F(FogScatteringSymmetry.X, value, FogScatteringSymmetry.Z));
            //SampleHelper.AddSlider(
            //  panel,
            //  "Fog scattering symmetry B",
            //  "F2",
            //  0,
            //  1,
            //  FogScatteringSymmetry.Z,
            //  value => FogScatteringSymmetry = new Vector3F(FogScatteringSymmetry.X, FogScatteringSymmetry.Y, value));
        }
Example #4
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            FogNode = new FogNode(new Fog())
            {
                IsEnabled = false,
                Name      = "Fog",
            };

            AddFogNodeToScene();

            // Add GUI controls to the Options window.
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "FogObject");

            SampleHelper.AddCheckBox(
                panel,
                "Enable fog",
                FogNode.IsEnabled,
                isChecked => FogNode.IsEnabled = isChecked);

            SampleHelper.AddCheckBox(
                panel,
                "Attach to camera",
                AttachToCamera,
                isChecked => AttachToCamera = isChecked);

            SampleHelper.AddSlider(
                panel,
                "Fog ramp start",
                "F2",
                0,
                1000,
                FogNode.Fog.Start,
                value => FogNode.Fog.Start = value);

            SampleHelper.AddSlider(
                panel,
                "Fog ramp end",
                "F2",
                0,
                5000,
                FogNode.Fog.End,
                value => FogNode.Fog.End = value);

            SampleHelper.AddSlider(
                panel,
                "Density",
                "F2",
                0.0f,
                2,
                FogNode.Fog.Density,
                value => FogNode.Fog.Density = value);

            SampleHelper.AddSlider(
                panel,
                "Height falloff",
                "F2",
                -1,
                1,
                FogNode.Fog.HeightFalloff,
                value => FogNode.Fog.HeightFalloff = value);

            SampleHelper.AddSlider(
                panel,
                "Height Y",
                "F2",
                -100,
                100,
                FogNode.PoseWorld.Position.Y,
                value =>
            {
                var pose          = FogNode.PoseWorld;
                pose.Position.Y   = value;
                FogNode.PoseWorld = pose;
            });
        }
Example #5
0
        protected override void OnLoad()
        {
            var contentManager = _services.GetInstance <ContentManager>();
            var scene          = _services.GetInstance <IScene>();

            _debugRenderer = _services.GetInstance <DebugRenderer>();

            // Load materials (*.drmat files) which define the used shaders and material
            // properties (e.g. textures, colors, etc.).
            var bloodMaterial      = contentManager.Load <Material>("Decals/Decal"); // Original: "Decals/Blood"
            var crackMaterial      = contentManager.Load <Material>("Decals/Decal"); // Original: "Decals/Crack"
            var bulletHoleMaterial = contentManager.Load <Material>("Decals/Decal"); // Original: "Decals/BulletHole"

            // Decal materials (like materials of meshes) usually have several render passes
            // (such as "GBuffer", "Material"). Decal materials without a "Material" pass can
            // be used to render only normal maps without color changes:
            //crackMaterial.Remove("Material");

            // Add some DecalNodes, which define where a material is projected onto the scene.
            var bloodDecal0 = new DecalNode(bloodMaterial);

            bloodDecal0.NormalThreshold = MathHelper.ToRadians(75);
            bloodDecal0.LookAt(new Vector3F(0.7f, 0.6f, 0.7f), new Vector3F(0.7f, 0.6f, 0), new Vector3F(0.1f, 1, 0));
            bloodDecal0.Width   = 1.1f;
            bloodDecal0.Height  = 1.1f;
            bloodDecal0.Depth   = 1;
            bloodDecal0.Options = DecalOptions.ProjectOnStatic;
            scene.Children.Add(bloodDecal0);
            _decals.Add(bloodDecal0);

            var bloodDecal1 = new DecalNode(bloodMaterial);

            bloodDecal1.LookAt(new Vector3F(0.0f, 0.2f, 1.9f), new Vector3F(0.0f, 0, 1.9f), new Vector3F(1.0f, 0, -0.5f));
            bloodDecal1.Width  = 1.6f;
            bloodDecal1.Height = 1.6f;
            bloodDecal1.Depth  = 0.5f;
            scene.Children.Add(bloodDecal1);
            _decals.Add(bloodDecal1);

            var crackDecal0 = new DecalNode(crackMaterial);

            crackDecal0.NormalThreshold = MathHelper.ToRadians(75);
            crackDecal0.LookAt(new Vector3F(-0.7f, 0.7f, 0.7f), new Vector3F(-0.7f, 0.7f, 0), new Vector3F(0.1f, 1, 0));
            crackDecal0.Width   = 1.75f;
            crackDecal0.Height  = 1.75f;
            crackDecal0.Depth   = 0.6f;
            crackDecal0.Options = DecalOptions.ProjectOnStatic;
            scene.Children.Add(crackDecal0);
            _decals.Add(crackDecal0);

            var crackDecal1 = crackDecal0.Clone();
            var position    = new Vector3F(2.0f, 0.2f, 2.0f);

            crackDecal1.LookAt(position, position + new Vector3F(0, -1, 0), new Vector3F(-0.8f, 0, 1.0f));
            crackDecal1.Width  = 2.5f;
            crackDecal1.Height = 2.5f;
            crackDecal1.Depth  = 0.5f;
            scene.Children.Add(crackDecal1);
            _decals.Add(crackDecal1);

            var bulletHole0 = new DecalNode(bulletHoleMaterial);

            bulletHole0.NormalThreshold = MathHelper.ToRadians(90);
            bulletHole0.LookAt(new Vector3F(0.0f, 0.8f, 0.7f), new Vector3F(0.0f, 0.7f, 0), new Vector3F(0.1f, -1, 0));
            bulletHole0.Width     = 0.20f;
            bulletHole0.Height    = 0.20f;
            bulletHole0.Depth     = 1f;
            bulletHole0.DrawOrder = 10; // Draw over other decals.
            scene.Children.Add(bulletHole0);
            _decals.Add(bulletHole0);

            var bulletHole1 = bulletHole0.Clone();

            bulletHole1.LookAt(new Vector3F(-0.4f, 0.9f, 0.7f), new Vector3F(-0.4f, 0.9f, 0), new Vector3F(0.1f, 1, 0));
            scene.Children.Add(bulletHole1);
            _decals.Add(bulletHole1);

            var bulletHole2 = bulletHole0.Clone();

            bulletHole2.LookAt(new Vector3F(-0.2f, 0.8f, 0.7f), new Vector3F(-0.2f, 0.0f, 0), new Vector3F(0.1f, -1, 0));
            scene.Children.Add(bulletHole2);
            _decals.Add(bulletHole2);

            var bulletHole3 = bulletHole0.Clone();

            bulletHole3.LookAt(new Vector3F(3.0f, 1.0f, 2.0f), new Vector3F(3.0f, 1.0f, 1), new Vector3F(0.3f, 1, 0));
            scene.Children.Add(bulletHole3);
            _decals.Add(bulletHole3);

            var bulletHole4 = bulletHole0.Clone();

            bulletHole4.LookAt(new Vector3F(2.5f, 0.7f, 2.0f), new Vector3F(3.0f, 0.7f, 1.0f), new Vector3F(-0.1f, -1, 0));
            scene.Children.Add(bulletHole4);
            _decals.Add(bulletHole4);

            var bulletHole5 = bulletHole0.Clone();

            bulletHole5.LookAt(new Vector3F(2.7f, 1.2f, 2.0f), new Vector3F(3.0f, 1.2f, 1.0f), new Vector3F(-0.5f, -1, 0));
            scene.Children.Add(bulletHole5);
            _decals.Add(bulletHole5);

            var bulletHole6 = bulletHole0.Clone();

            bulletHole6.LookAt(new Vector3F(3.2f, 0.4f, 2.0f), new Vector3F(3.0f, 0.4f, 1), new Vector3F(-0.3f, -0.5f, 0));
            scene.Children.Add(bulletHole6);
            _decals.Add(bulletHole6);

            // Get the first dynamic mesh (the rusty cube) and add a decal as a child.
            MeshNode meshNode    = ((Scene)scene).GetSubtree().OfType <MeshNode>().First(n => !n.IsStatic);
            var      bulletHole7 = bulletHole0.Clone();

            bulletHole7.LookAt(new Vector3F(0, 0, -0.6f), new Vector3F(0, 0, 0), new Vector3F(0, 1, 0));
            bulletHole7.Depth = 0.2f;
            meshNode.Children = new SceneNodeCollection {
                bulletHole7
            };
            _decals.Add(bulletHole7);

            // Add GUI controls to the Options window.
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "EnvironmentDecalsObject");

            SampleHelper.AddCheckBox(
                panel,
                "Enable decals",
                IsEnabled,
                isChecked => IsEnabled = isChecked);
        }
        protected override void OnLoad()
        {
            // ----- Get common services, game objects, etc.
            var graphicsService        = _services.GetInstance <IGraphicsService>();
            var deferredGraphicsScreen = graphicsService.Screens.OfType <DeferredGraphicsScreen>().FirstOrDefault();

            if (deferredGraphicsScreen == null)
            {
                return;
            }

            var hdrFilter = deferredGraphicsScreen.PostProcessors.OfType <HdrFilter>().FirstOrDefault();

            var sampleFramework         = _services.GetInstance <SampleFramework>();
            var optionsPanel            = sampleFramework.AddOptions("DeferredGraphicsScreen");
            var intermediateTargetPanel = SampleHelper.AddGroupBox(optionsPanel, "Render targets");

            SampleHelper.AddCheckBox(
                intermediateTargetPanel,
                "Draw intermediate render targets",
                deferredGraphicsScreen.VisualizeIntermediateRenderTargets,
                isChecked => deferredGraphicsScreen.VisualizeIntermediateRenderTargets = isChecked,
                "1st row: G-Buffer 0 (depth), G-Buffer 1 (normals and glossiness),\n" +
                "Light Buffer 0 (diffuse), Light Buffer 1 (specular),\n" +
                "2nd row: Shadow masks");

            SampleHelper.AddDropDown(
                intermediateTargetPanel,
                "Debug Mode",
                EnumHelper.GetValues(typeof(DeferredGraphicsDebugMode)),
                (int)deferredGraphicsScreen.DebugMode,
                item => deferredGraphicsScreen.DebugMode = (DeferredGraphicsDebugMode)item,
                "Render an intermediate render target to the back buffer for debugging.");

            var lodPanel = SampleHelper.AddGroupBox(optionsPanel, "Level of detail (LOD)");

            SampleHelper.AddCheckBox(
                lodPanel,
                "Enable LOD",
                deferredGraphicsScreen.EnableLod,
                isChecked => deferredGraphicsScreen.EnableLod = isChecked);

            var particlePanel = SampleHelper.AddGroupBox(optionsPanel, "Particle rendering");

            SampleHelper.AddCheckBox(
                particlePanel,
                "Enable soft particles",
                deferredGraphicsScreen.EnableSoftParticles,
                isChecked => deferredGraphicsScreen.EnableSoftParticles = isChecked);

            SampleHelper.AddCheckBox(
                particlePanel,
                "Render particles into low-resolution offscreen buffer",
                deferredGraphicsScreen.EnableOffscreenParticles,
                isChecked => deferredGraphicsScreen.EnableOffscreenParticles = isChecked);

            // ----- Shadow mask controls
            var shadowMaskPanel = SampleHelper.AddGroupBox(optionsPanel, "Shadow Mask");

            var blurCheckBox = SampleHelper.AddCheckBox(
                shadowMaskPanel,
                "Blur shadow mask",
                deferredGraphicsScreen.ShadowMaskRenderer.Filter.Enabled,
                isChecked => deferredGraphicsScreen.ShadowMaskRenderer.Filter.Enabled = isChecked);

            var bilateralCheckBox = SampleHelper.AddCheckBox(
                shadowMaskPanel,
                "Blur is bilateral",
                ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).IsBilateral,
                isChecked => ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).IsBilateral = isChecked);

            // Disable bilateral check box if blur is not checked.
            bilateralCheckBox.IsEnabled = blurCheckBox.IsChecked;
            var blurIsCheckedProperty      = blurCheckBox.Properties.Get <bool>(ToggleButton.IsCheckedPropertyId);
            var bilateralIsEnabledProperty = bilateralCheckBox.Properties.Get <bool>(UIControl.IsEnabledPropertyId);

            blurIsCheckedProperty.Changed += bilateralIsEnabledProperty.Change;

            var anisotropicCheckBox = SampleHelper.AddCheckBox(
                shadowMaskPanel,
                "Blur is anisotropic",
                ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).IsAnisotropic,
                isChecked => ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).IsAnisotropic = isChecked);

            // Disable anisotropic check box if blur is not checked.
            anisotropicCheckBox.IsEnabled = blurCheckBox.IsChecked;
            var anisotropicIsEnabledProperty = anisotropicCheckBox.Properties.Get <bool>(UIControl.IsEnabledPropertyId);

            blurIsCheckedProperty.Changed += anisotropicIsEnabledProperty.Change;

            var depthScaleSlider = SampleHelper.AddSlider(
                shadowMaskPanel,
                "Blur depth scaling",
                "F2",
                0.0f,
                1.0f,
                ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).DepthScaling,
                value => ((Blur)deferredGraphicsScreen.ShadowMaskRenderer.Filter).DepthScaling = value);

            // Disable depth scale slider if blur is not checked or bilateral/anisotropic is not checked.
            depthScaleSlider.IsEnabled = blurCheckBox.IsChecked && (bilateralCheckBox.IsChecked || anisotropicCheckBox.IsChecked);
            EventHandler <EventArgs> setDepthScaleSliderIsEnabledHandler = (s, e) =>
            {
                depthScaleSlider.IsEnabled = blurCheckBox.IsChecked &&
                                             (bilateralCheckBox.IsChecked || anisotropicCheckBox.IsChecked);
            };

            blurCheckBox.Click        += setDepthScaleSliderIsEnabledHandler;
            bilateralCheckBox.Click   += setDepthScaleSliderIsEnabledHandler;
            anisotropicCheckBox.Click += setDepthScaleSliderIsEnabledHandler;

            var halfResCheckBox = SampleHelper.AddCheckBox(
                shadowMaskPanel,
                "Use half resolution",
                deferredGraphicsScreen.ShadowMaskRenderer.UseHalfResolution,
                isChecked => deferredGraphicsScreen.ShadowMaskRenderer.UseHalfResolution = isChecked);

            var upsampleDepthSensitivitySlider = SampleHelper.AddSlider(
                shadowMaskPanel,
                "Upsample depth sensitivity",
                "F0",
                0.0f,
                10000.0f,
                deferredGraphicsScreen.ShadowMaskRenderer.UpsampleDepthSensitivity,
                value => deferredGraphicsScreen.ShadowMaskRenderer.UpsampleDepthSensitivity = value);

            // Disable depth sensitivity slider if half-res is not checked.
            upsampleDepthSensitivitySlider.IsEnabled = halfResCheckBox.IsChecked;
            var upsampleDepthSensitivityIsEnabledProperty = upsampleDepthSensitivitySlider.Properties.Get <bool>(UIControl.IsEnabledPropertyId);
            var halfResIsCheckedProperty = halfResCheckBox.Properties.Get <bool>(ToggleButton.IsCheckedPropertyId);

            halfResIsCheckedProperty.Changed += upsampleDepthSensitivityIsEnabledProperty.Change;

            var postProcessingPanel = SampleHelper.AddGroupBox(optionsPanel, "Post processing");

            if (hdrFilter != null)
            {
                SampleHelper.AddSlider(
                    postProcessingPanel,
                    "Tone mapping middle gray",
                    "F2",
                    0,
                    1,
                    hdrFilter.MiddleGray,
                    value => hdrFilter.MiddleGray = value);

                SampleHelper.AddSlider(
                    postProcessingPanel,
                    "Min exposure",
                    "F2",
                    0,
                    10,
                    hdrFilter.MinExposure,
                    value => hdrFilter.MinExposure = value);

                SampleHelper.AddSlider(
                    postProcessingPanel,
                    "Max exposure",
                    "F2",
                    0,
                    10,
                    hdrFilter.MaxExposure,
                    value => hdrFilter.MaxExposure = value);

                SampleHelper.AddSlider(
                    postProcessingPanel,
                    "Adaption speed",
                    "F2",
                    0,
                    0.2f,
                    hdrFilter.AdaptionSpeed,
                    value => hdrFilter.AdaptionSpeed = value);

                SampleHelper.AddCheckBox(
                    postProcessingPanel,
                    "Enable blue shift",
                    hdrFilter.EnableBlueShift,
                    isChecked => hdrFilter.EnableBlueShift = isChecked);

                SampleHelper.AddSlider(
                    postProcessingPanel,
                    "Blue shift center",
                    "F4",
                    0,
                    0.005f,
                    hdrFilter.BlueShiftCenter,
                    value => hdrFilter.BlueShiftCenter = value);

                var miscPanel = SampleHelper.AddGroupBox(optionsPanel, "Misc");

                SampleHelper.AddDropDown(
                    miscPanel,
                    "Ambient occlusion type",
                    new[] { AmbientOcclusionType.None, AmbientOcclusionType.SSAO, AmbientOcclusionType.SAO, },
                    (int)deferredGraphicsScreen.LightBufferRenderer.AmbientOcclusionType,
                    item => deferredGraphicsScreen.LightBufferRenderer.AmbientOcclusionType = item);

                SampleHelper.AddCheckBox(
                    miscPanel,
                    "Draw reticle",
                    deferredGraphicsScreen.DrawReticle,
                    isChecked => deferredGraphicsScreen.DrawReticle = isChecked);
            }
        }
Example #7
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            var particleSystemService = _services.GetInstance <IParticleSystemService>();

            // The campfire consists of two particle systems (fire + smoke) and a light source.
            //
            //   _campfire (SceneNode)
            //      |
            //      +-- _fireParticles (ParticleSystemNode)
            //      |
            //      +-- _smokeParticles (ParticleSystemNode)
            //      |
            //      +-- _light (LightNode)

            // Use a basic scene node as the root node for the campfire.
            _campfire = new SceneNode
            {
                Name      = "Campfire",
                PoseLocal = new Pose(new Vector3(0, 0, -1)),
                Children  = new SceneNodeCollection()
            };

            // Add fire particles.
            var contentManager = _services.GetInstance <ContentManager>();
            var particleSystem = CreateFire(contentManager);

            particleSystemService.ParticleSystems.Add(particleSystem);
            _fireParticles = new ParticleSystemNode(particleSystem)
            {
                // The fire effect lies in the xy plane and shoots into the forward direction (= -z axis).
                // Therefore we rotate the particle system to shoot upwards.
                PoseLocal = new Pose(new Vector3(0, 0.2f, 0), Matrix.CreateRotationX(ConstantsF.PiOver2))
            };
            _campfire.Children.Add(_fireParticles);

            // Add smoke particles.
            particleSystem = CreateSmoke(contentManager);
            particleSystemService.ParticleSystems.Add(particleSystem);
            _smokeParticles = new ParticleSystemNode(particleSystem)
            {
                PoseLocal = new Pose(new Vector3(0, 0.2f, 0), Matrix.CreateRotationX(ConstantsF.PiOver2))
            };
            _campfire.Children.Add(_smokeParticles);

            // Add a point light that illuminates the environment.
            var light = new PointLight
            {
                Attenuation = 0.1f,
                Color       = new Vector3(1, 0.2f, 0),
                HdrScale    = 20,
                Range       = 4
            };

            _light = new LightNode(light)
            {
                // Optional: We can make this light cast shadows - but this will cost performance!
                //Shadow = new CubeMapShadow { PreferredSize = 64, FilterRadius = 2, JitterResolution = 2048 },
                PoseLocal = new Pose(new Vector3(0, 1f, 0))
            };
            _campfire.Children.Add(_light);

            // Add campfire to scene.
            var scene = _services.GetInstance <IScene>();

            scene.Children.Add(_campfire);

            // Particle effects can be added multiple times to the scene (= "instancing").
            // Uncomment the following lines to add a few more instance to the scene.
            //for (int i = 0; i < 10; i++)
            //{
            //  var clone = _campfire.Clone();

            //  // Set random scale, position, orientation.
            //  clone.ScaleLocal = _random.NextVector3(0.5f, 1.5f);
            //  var pose = _campfire.PoseWorld;
            //  pose.Position.X += _random.NextFloat(-10, 10);
            //  pose.Position.Z += _random.NextFloat(-10, 10);
            //  pose.Orientation = Matrix.CreateRotationY(_random.NextFloat(-ConstantsF.PiOver2, ConstantsF.PiOver2));
            //  clone.PoseLocal = pose;

            //  scene.Children.Add(clone);
            //}

            // Add GUI controls to the Options window.
            var sampleFramework = _services.GetInstance <SampleFramework>();
            var optionsPanel    = sampleFramework.AddOptions("Game Objects");
            var panel           = SampleHelper.AddGroupBox(optionsPanel, "CampfireObject");

            SampleHelper.AddCheckBox(
                panel,
                "Enable campfire",
                IsEnabled,
                isChecked => IsEnabled = isChecked);
        }