/// <summary>
        /// Clears the current render target (which must be the G-buffer).
        /// </summary>
        /// <param name="context">The render context.</param>
        public void Render(RenderContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              context.Validate(_effect);

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.BlendState = BlendState.Opaque;

              // Clear to maximum depth.
              _parameterDepth.SetValue(1.0f);

              // The environment is facing the camera.
              // --> Set normal = cameraBackward.
              var cameraNode = context.CameraNode;
              _parameterNormal.SetValue((cameraNode != null) ? (Vector3)cameraNode.ViewInverse.GetColumn(2).XYZ : Vector3.Backward);

              // Clear specular to arbitrary value.
              _parameterSpecularPower.SetValue(1.0f);

              _effect.CurrentTechnique.Passes[0].Apply();

              // Draw full-screen quad using clip space coordinates.
              graphicsDevice.DrawQuad(
            new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0, 0)),
            new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1)));

              savedRenderState.Restore();
        }
Example #2
0
        private void VisualizeQuery(SceneNode node, RenderContext context, int passIndex)
        {
            if (node == null)
            throw new ArgumentNullException("node");
              if (context == null)
            throw new ArgumentNullException("context");

              context.ThrowIfCameraMissing();

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var originalRenderState = new RenderStateSnapshot(graphicsDevice);

              var viewport = graphicsDevice.Viewport;
              _parameterTargetSize.SetValue(new Vector2(viewport.Width, viewport.Height));

              var aabb = node.Aabb;
              _parameterDebugMinimum.SetValue((Vector3)aabb.Minimum);
              _parameterDebugMaximum.SetValue((Vector3)aabb.Maximum);

              _effect.CurrentTechnique = _techniqueVisualize;
              _techniqueVisualize.Passes[passIndex].Apply();

              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              // Do not override blend state: Use current blend state.

              graphicsDevice.DrawFullScreenQuad();

              originalRenderState.Restore();
        }
Example #3
0
        private void RenderReach(SkyboxNode node, RenderContext context)
        {
            var graphicsDevice = context.GraphicsService.GraphicsDevice;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
              graphicsDevice.BlendState = node.EnableAlphaBlending ? BlendState.AlphaBlend : BlendState.Opaque;
              graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;

              // Change viewport to render all pixels at max z.
              var originalViewport = graphicsDevice.Viewport;
              var viewport = originalViewport;
              viewport.MinDepth = viewport.MaxDepth;
              graphicsDevice.Viewport = viewport;

              var cameraNode = context.CameraNode;
              var view = cameraNode.View;
              view.Translation = Vector3F.Zero;
              var projection = cameraNode.Camera.Projection;

              var basicEffect = (BasicEffect)_effect;
              basicEffect.View = (Matrix)view;
              basicEffect.Projection = projection;
              basicEffect.DiffuseColor = (Vector3)node.Color;
              basicEffect.Alpha = node.EnableAlphaBlending ? node.Alpha : 1;

              // Scale skybox such that it lies within view frustum:
              //   distance of a skybox corner = √3
              //   √3 * scale = far
              //   => scale = far / √3
              // (Note: If  near > far / √3  then the skybox will be clipped.)
              float scale = projection.Far * 0.577f;

              var orientation = node.PoseWorld.Orientation;

              // Positive X
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.PositiveX);
              basicEffect.World = (Matrix)new Matrix44F(orientation * scale, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              // Negative X
              // transform = scale * rotY(180°)
              var transform = new Matrix33F(-scale, 0, 0, 0, scale, 0, 0, 0, -scale);
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.NegativeX);
              basicEffect.World = (Matrix)new Matrix44F(orientation * transform, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              // Positive Y
              // transform = scale * rotX(90°) * rotY(90°)
              transform = new Matrix33F(0, 0, scale, scale, 0, 0, 0, scale, 0);
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.PositiveY);
              basicEffect.World = (Matrix)new Matrix44F(orientation * transform, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              // Negative Y
              // transform = scale * rotX(-90°) * rotY(90°)
              transform = new Matrix33F(0, 0, scale, -scale, 0, 0, 0, -scale, 0);
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.NegativeY);
              basicEffect.World = (Matrix)new Matrix44F(orientation * transform, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              // Cube maps are left-handed, where as the world is right-handed!

              // Positive Z (= negative Z in world space)
              // transform = scale * rotY(90°)
              transform = new Matrix33F(0, 0, scale, 0, scale, 0, -scale, 0, 0);
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.PositiveZ);
              basicEffect.World = (Matrix)new Matrix44F(orientation * transform, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              // Negative Z (= positive Z in world space)
              // transform = scale * rotY(-90°)
              transform = new Matrix33F(0, 0, -scale, 0, scale, 0, scale, 0, 0);
              basicEffect.Texture = GetTexture2D(graphicsDevice, node.Texture, CubeMapFace.NegativeZ);
              basicEffect.World = (Matrix)new Matrix44F(orientation * transform, Vector3F.Zero);
              basicEffect.CurrentTechnique.Passes[0].Apply();
              graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _faceVertices, 0, 2);

              graphicsDevice.Viewport = originalViewport;
              savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.ThrowIfCameraMissing();
              context.ThrowIfSceneMissing();

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;
              var originalReferenceNode = context.ReferenceNode;

              var cameraNode = context.CameraNode;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              // The scene node renderer should use the light camera instead of the player camera.
              context.CameraNode = _perspectiveCameraNode;
              context.Technique = "Omnidirectional";

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var renderTargetPool = graphicsService.RenderTargetPool;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var shadow = lightNode.Shadow as CubeMapShadow;
            if (shadow == null)
              continue;

            var light = lightNode.Light as PointLight;
            if (light == null)
              throw new GraphicsException("CubeMapShadow can only be used with a PointLight.");

            // LightNode is visible in current frame.
            lightNode.LastFrame = frame;

            if (shadow.ShadowMap == null)
            {
              shadow.ShadowMap = renderTargetPool.ObtainCube(
            new RenderTargetFormat(
              shadow.PreferredSize,
              null,
              false,
              shadow.Prefer16Bit ? SurfaceFormat.HalfSingle : SurfaceFormat.Single,
              DepthFormat.Depth24));
            }

            ((PerspectiveProjection)_perspectiveCameraNode.Camera.Projection).SetFieldOfView(
              ConstantsF.PiOver2, 1, shadow.Near, light.Range);

            // World units per texel at a planar distance of 1 world unit.
            float unitsPerTexel = _perspectiveCameraNode.Camera.Projection.Width / (shadow.ShadowMap.Size * shadow.Near);

            // Convert depth bias from "texel" to  world space.
            // Minus to move receiver closer to light.
            shadow.EffectiveDepthBias = -shadow.DepthBias * unitsPerTexel;

            // Convert normal offset from "texel" to world space.
            shadow.EffectiveNormalOffset = shadow.NormalOffset * unitsPerTexel;

            var pose = lightNode.PoseWorld;

            context.ReferenceNode = lightNode;
            context.Object = shadow;

            bool shadowMapContainsSomething = false;
            for (int side = 0; side < 6; side++)
            {
              context.Data[RenderContextKeys.ShadowTileIndex] = BoxedIntegers[side];

              graphicsDevice.SetRenderTarget(shadow.ShadowMap, CubeMapFaces[side]);
              // context.RenderTarget = shadow.ShadowMap;   // TODO: Support cube maps targets in the render context.
              context.Viewport = graphicsDevice.Viewport;

              graphicsDevice.Clear(Color.White);

              _perspectiveCameraNode.View = Matrix44F.CreateLookAt(
            pose.Position,
            pose.ToWorldPosition(CubeMapForwardVectors[side]),
            pose.ToWorldDirection(CubeMapUpVectors[side]));

              // Abort if this cube map frustum does not touch the camera frustum.
              if (!context.Scene.HaveContact(cameraNode, _perspectiveCameraNode))
            continue;

              graphicsDevice.DepthStencilState = DepthStencilState.Default;
              graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
              graphicsDevice.BlendState = BlendState.Opaque;

              shadowMapContainsSomething |= RenderCallback(context);
            }

            // Recycle shadow map if empty.
            if (!shadowMapContainsSomething)
            {
              renderTargetPool.Recycle(shadow.ShadowMap);
              shadow.ShadowMap = null;
            }
              }

              graphicsDevice.SetRenderTarget(null);
              savedRenderState.Restore();

              context.CameraNode = cameraNode;
              context.Technique = null;
              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
              context.ReferenceNode = originalReferenceNode;
              context.Object = null;
              context.Data[RenderContextKeys.ShadowTileIndex] = null;
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            var graphicsService  = context.GraphicsService;
            var graphicsDevice   = graphicsService.GraphicsDevice;
            var renderTargetPool = graphicsService.RenderTargetPool;
            int frame            = context.Frame;

            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            var originalRenderTarget  = context.RenderTarget;
            var originalViewport      = context.Viewport;
            var originalCameraNode    = context.CameraNode;
            var originalLodCameraNode = context.LodCameraNode;
            var originalReferenceNode = context.ReferenceNode;

            try
            {
                // Use foreach instead of for-loop to catch InvalidOperationExceptions in
                // case the collection is modified.
                for (int i = 0; i < numberOfNodes; i++)
                {
                    var node = nodes[i] as SceneCaptureNode;
                    if (node == null)
                    {
                        continue;
                    }

                    // Update each node only once per frame.
                    if (node.LastFrame == frame)
                    {
                        continue;
                    }

                    node.LastFrame = frame;

                    var cameraNode = node.CameraNode;
                    if (cameraNode == null)
                    {
                        continue;
                    }

                    var texture = node.RenderToTexture.Texture;
                    if (texture == null)
                    {
                        continue;
                    }

                    // RenderToTexture instances can be shared. --> Update them only once per frame.
                    if (node.RenderToTexture.LastFrame == frame)
                    {
                        continue;
                    }

                    context.CameraNode    = cameraNode;
                    context.LodCameraNode = cameraNode;
                    context.ReferenceNode = node;

                    var renderTarget2D = texture as RenderTarget2D;
                    var projection     = cameraNode.Camera.Projection;
                    if (renderTarget2D != null)
                    {
                        context.RenderTarget = renderTarget2D;
                        context.Viewport     = new Viewport(0, 0, renderTarget2D.Width, renderTarget2D.Height);

                        RenderCallback(context);

                        // Update other properties of RenderToTexture.
                        node.RenderToTexture.LastFrame     = frame;
                        node.RenderToTexture.TextureMatrix = GraphicsHelper.ProjectorBiasMatrix
                                                             * projection
                                                             * cameraNode.PoseWorld.Inverse;

                        continue;
                    }

                    var renderTargetCube = texture as RenderTargetCube;
                    if (renderTargetCube != null)
                    {
                        var format = new RenderTargetFormat(renderTargetCube)
                        {
                            Mipmap = false
                        };

                        renderTarget2D = renderTargetPool.Obtain2D(format);

                        context.RenderTarget = renderTarget2D;
                        context.Viewport     = new Viewport(0, 0, renderTarget2D.Width, renderTarget2D.Height);

                        if (_spriteBatch == null)
                        {
                            _spriteBatch = graphicsService.GetSpriteBatch();
                        }

                        var perspectiveProjection = projection as PerspectiveProjection;
                        if (perspectiveProjection == null)
                        {
                            throw new GraphicsException("The camera of the SceneCaptureNode must use a perspective projection.");
                        }

                        // ReSharper disable CompareOfFloatsByEqualityOperator
                        if (perspectiveProjection.FieldOfViewX != ConstantsF.PiOver2 ||
                            perspectiveProjection.FieldOfViewY != ConstantsF.PiOver2)
                        {
                            perspectiveProjection.SetFieldOfView(ConstantsF.PiOver2, 1, projection.Near, projection.Far);
                        }
                        // ReSharper restore CompareOfFloatsByEqualityOperator

                        var originalCameraPose = cameraNode.PoseWorld;
                        for (int side = 0; side < 6; side++)
                        {
                            // Rotate camera to face the current cube map face.
                            //var cubeMapFace = (CubeMapFace)side;
                            // AMD problem: If we generate in normal order, the last cube map face contains
                            // garbage when mipmaps are created.
                            var cubeMapFace = (CubeMapFace)(5 - side);
                            var position    = cameraNode.PoseWorld.Position;
                            cameraNode.View = Matrix44F.CreateLookAt(
                                position,
                                position + originalCameraPose.ToWorldDirection(GraphicsHelper.GetCubeMapForwardDirection(cubeMapFace)),
                                originalCameraPose.ToWorldDirection(GraphicsHelper.GetCubeMapUpDirection(cubeMapFace)));

                            RenderCallback(context);

                            // Copy RGBM texture into cube map face.
                            graphicsDevice.SetRenderTarget(renderTargetCube, cubeMapFace);
                            _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, null, null, null);
                            _spriteBatch.Draw(renderTarget2D, new Vector2(0, 0), Color.White);
                            _spriteBatch.End();
                        }
                        cameraNode.PoseWorld = originalCameraPose;

                        renderTargetPool.Recycle(renderTarget2D);

                        // Update other properties of RenderToTexture.
                        node.RenderToTexture.LastFrame     = frame;
                        node.RenderToTexture.TextureMatrix = GraphicsHelper.ProjectorBiasMatrix
                                                             * projection
                                                             * cameraNode.PoseWorld.Inverse;

                        continue;
                    }

                    throw new GraphicsException(
                              "SceneCaptureNode.RenderToTexture.Texture is invalid. The texture must be a RenderTarget2D or RenderTargetCube.");
                }
            }
            catch (InvalidOperationException exception)
            {
                throw new GraphicsException(
                          "InvalidOperationException was raised in SceneCaptureRenderer.Render(). "
                          + "This can happen if a SceneQuery instance that is currently in use is modified in the "
                          + "RenderCallback. --> Use different SceneQuery types in the method which calls "
                          + "SceneCaptureRenderer.Render() and in the RenderCallback method.",
                          exception);
            }

            graphicsDevice.SetRenderTarget(null);
            savedRenderState.Restore();

            context.RenderTarget  = originalRenderTarget;
            context.Viewport      = originalViewport;
            context.CameraNode    = originalCameraNode;
            context.LodCameraNode = originalLodCameraNode;
            context.ReferenceNode = originalReferenceNode;
        }
        private void Render(RenderContext context, Vector4F color, Texture2D colorTexture, bool preserveColor)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              context.Validate(_effect);
              context.ThrowIfCameraMissing();
              context.ThrowIfGBuffer0Missing();

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateAlways;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;

              if (preserveColor)
            graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;
              else
            graphicsDevice.BlendState = BlendState.Opaque;

              if (colorTexture != null)
              {
            if (TextureHelper.IsFloatingPointFormat(colorTexture.Format))
              graphicsDevice.SamplerStates[1] = SamplerState.PointClamp;
            else
              graphicsDevice.SamplerStates[1] = SamplerState.LinearClamp;
              }

              var projection = context.CameraNode.Camera.Projection;
              bool isPerspective = projection is PerspectiveProjection;
              float near = projection.Near * NearBias;
              float far = projection.Far * FarBias;
              var biasedProjection = isPerspective
                               ? Matrix44F.CreatePerspectiveOffCenter(
                                 projection.Left, projection.Right,
                                 projection.Bottom, projection.Top,
                                 near, far)
                               : Matrix44F.CreateOrthographicOffCenter(
                                 projection.Left, projection.Right,
                                 projection.Bottom, projection.Top,
                                 near, far);

              var viewport = graphicsDevice.Viewport;
              _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
              _parameterProjection.SetValue((Matrix)biasedProjection);
              _parameterCameraFar.SetValue(projection.Far);
              _parameterGBuffer0.SetValue(context.GBuffer0);
              _parameterColor.SetValue((Vector4)color);
              _parameterSourceTexture.SetValue(colorTexture);

              _effect.CurrentTechnique = isPerspective ? _techniquePerspective : _techniqueOrthographic;
              _effect.CurrentTechnique.Passes[(colorTexture == null) ? 0 : 1].Apply();

              graphicsDevice.DrawFullScreenQuad();

              graphicsDevice.ResetTextures();

              savedRenderState.Restore();
        }
Example #7
0
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              // Camera properties
              int viewportHeight = graphicsDevice.Viewport.Height;
              var cameraNode = context.CameraNode;
              var projection = cameraNode.Camera.Projection;
              _parameterProjection.SetValue(projection);

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as CloudLayerNode;
            if (node == null)
              continue;

            // CloudLayerNode is visible in current frame.
            node.LastFrame = frame;

            if (node.CloudMap.Texture == null)
              continue;

            var sunDirection = node.SunDirection;
            _parameterSunDirection.SetValue((Vector3)sunDirection);
            _parameterSkyCurvature.SetValue(node.SkyCurvature);
            _parameterTextureMatrix.SetValue((Matrix)new Matrix44F(node.TextureMatrix, Vector3F.Zero));

            // The sample at the pixel counts as one, the rest are for the blur.
            // Note: We must not set -1 because a for loop like
            //   for (int i = 0; i < -1, i++)
            // crashes the AMD DX9 WP8.1 graphics driver. LOL
            _parameterNumberOfSamples.SetValue(Math.Max(0, node.NumberOfSamples - 1));

            _parameterSampleDistance.SetValue(node.SampleDistance);
            _parameterScatterParameters.SetValue(new Vector3(node.ForwardScatterExponent, node.ForwardScatterScale, node.ForwardScatterOffset));
            _parameterHorizonFade.SetValue(new Vector2(node.HorizonFade, node.HorizonBias));
            _parameterSunLight.SetValue((Vector3)node.SunLight);
            _parameterAmbientLight.SetValue(new Vector4((Vector3)node.AmbientLight, node.Alpha));
            _parameterTexture.SetValue(node.CloudMap.Texture);

            // Occlusion query.
            if (graphicsDevice.GraphicsProfile != GraphicsProfile.Reach && node.SunQuerySize >= Numeric.EpsilonF)
            {
              bool skipQuery = false;
              if (node.OcclusionQuery != null)
              {
            if (node.OcclusionQuery.IsComplete)
            {
              node.TryUpdateSunOcclusion();
            }
            else
            {
              // The previous query is still not finished. Do not start a new query, this would
              // create a SharpDX warning.
              skipQuery = true;
            }
              }
              else
              {
            node.OcclusionQuery = new OcclusionQuery(graphicsDevice);
              }

              if (!skipQuery)
              {
            node.IsQueryPending = true;

            float totalPixels = viewportHeight * node.SunQuerySize;
            totalPixels *= totalPixels;
            node.QuerySize = totalPixels;

            // Use a camera which looks at the sun.
            // Get an relative up vector which is not parallel to the forward direction.
            var lookAtUp = Vector3F.UnitY;
            if (Vector3F.AreNumericallyEqual(sunDirection, lookAtUp))
              lookAtUp = Vector3F.UnitZ;

            Vector3F zAxis = -sunDirection;
            Vector3F xAxis = Vector3F.Cross(lookAtUp, zAxis).Normalized;
            Vector3F yAxis = Vector3F.Cross(zAxis, xAxis);

            var lookAtSunView = new Matrix(xAxis.X, yAxis.X, zAxis.X, 0,
                                           xAxis.Y, yAxis.Y, zAxis.Y, 0,
                                           xAxis.Z, yAxis.Z, zAxis.Z, 0,
                                           0, 0, 0, 1);
            _parameterView.SetValue(lookAtSunView);

            graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;
            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState = RasterizerState.CullNone;

            // Create small quad shortly behind the near plane.
            // Note: We use an "untranslated" view matrix, so we can ignore the camera position.
            float width = (projection.Top - projection.Bottom) * node.SunQuerySize;
            Vector3F right = sunDirection.Orthonormal1 * (width / 2);
            Vector3F up = sunDirection.Orthonormal2 * (width / 2);
            Vector3F center = sunDirection * (projection.Near * 1.0001f);
            _queryGeometry[0] = center - up - right;
            _queryGeometry[1] = center + up - right;
            _queryGeometry[2] = center - up + right;
            _queryGeometry[3] = center + up + right;

            if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
              _passOcclusionAlpha.Apply();
            else
              _passOcclusionRgb.Apply();

            node.OcclusionQuery.Begin();
            graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2,
              VertexPosition.VertexDeclaration);
            node.OcclusionQuery.End();
              }
            }
            else
            {
              node.IsQueryPending = false;
              node.SunOcclusion = 0;
            }

            Matrix viewUntranslated = (Matrix)new Matrix44F(cameraNode.PoseWorld.Orientation.Transposed, new Vector3F(0));
            _parameterView.SetValue(viewUntranslated);

            // Render clouds.
            graphicsDevice.BlendState = BlendState.AlphaBlend;
            graphicsDevice.RasterizerState = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

            if (context.IsHdrEnabled())
            {
              if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
            _passCloudAlphaLinear.Apply();
              else
            _passCloudRgbLinear.Apply();
            }
            else
            {
              if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
            _passCloudAlphaGamma.Apply();
              else
            _passCloudRgbGamma.Apply();
            }

            _submesh.Draw();
              }

              savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.BlendState = BlendState.AlphaBlend;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

              // Camera properties
              var cameraNode = context.CameraNode;
              Matrix view = (Matrix)new Matrix44F(cameraNode.PoseWorld.Orientation.Transposed, new Vector3F());
              _parameterView.SetValue(view);
              Matrix projection = cameraNode.Camera.Projection;
              _parameterProjection.SetValue(projection);

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as GradientTextureSkyNode;
            if (node == null)
              continue;

            // GradientTextureSkyNode is visible in current frame.
            node.LastFrame = frame;

            _parameterSunDirection.SetValue((Vector3)node.SunDirection);
            _parameterTime.SetValue((float)node.TimeOfDay.TotalHours / 24);
            _parameterColor.SetValue((Vector4)node.Color);
            _parameterFrontTexture.SetValue(node.FrontTexture);
            _parameterBackTexture.SetValue(node.BackTexture);

            if (node.CieSkyStrength < Numeric.EpsilonF)
            {
              if (context.IsHdrEnabled())
            _passLinear.Apply();
              else
            _passGamma.Apply();
            }
            else
            {
              var p = node.CieSkyParameters;
              _parameterAbcd.SetValue(new Vector4(p.A, p.B, p.C, p.D));
              _parameterEAndStrength.SetValue(new Vector2(p.E, node.CieSkyStrength));

              if (context.IsHdrEnabled())
            _passCieLinear.Apply();
              else
            _passCieGamma.Apply();
            }
            _submesh.Draw();
              }

              savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.BlendState        = GraphicsHelper.BlendStateAdd;

            var viewport = graphicsDevice.Viewport;

            _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
            _parameterGBuffer0.SetValue(context.GBuffer0);
            _parameterGBuffer1.SetValue(context.GBuffer1);

            var    cameraNode     = context.CameraNode;
            Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection;

            var cameraPose = cameraNode.PoseWorld;

            GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, _cameraFrustumFarCorners);

            // Convert frustum far corners from view space to world space.
            for (int i = 0; i < _cameraFrustumFarCorners.Length; i++)
            {
                _cameraFrustumFarCorners[i] = (Vector3)cameraPose.ToWorldDirection((Vector3)_cameraFrustumFarCorners[i]);
            }

            _parameterFrustumCorners.SetValue(_cameraFrustumFarCorners);

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            var isHdrEnabled = context.IsHdrEnabled();

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var light = lightNode.Light as DirectionalLight;
                if (light == null)
                {
                    continue;
                }

                // LightNode is visible in current frame.
                lightNode.LastFrame = frame;

                float hdrScale = isHdrEnabled ? light.HdrScale : 1;
                _parameterDiffuseColor.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
                _parameterSpecularColor.SetValue((Vector3)light.Color * light.SpecularIntensity * hdrScale);

                Pose    lightPose           = lightNode.PoseWorld;
                Vector3 lightDirectionWorld = lightPose.ToWorldDirection(Vector3.Forward);
                _parameterLightDirection.SetValue((Vector3)lightDirectionWorld);

                bool hasShadow = (lightNode.Shadow != null && lightNode.Shadow.ShadowMask != null);
                if (hasShadow)
                {
                    switch (lightNode.Shadow.ShadowMaskChannel)
                    {
                    case 0:  _parameterShadowMaskChannel.SetValue(new Vector4(1, 0, 0, 0)); break;

                    case 1:  _parameterShadowMaskChannel.SetValue(new Vector4(0, 1, 0, 0)); break;

                    case 2:  _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 1, 0)); break;

                    default: _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 0, 1)); break;
                    }

                    _parameterShadowMask.SetValue(lightNode.Shadow.ShadowMask);
                }

                bool hasTexture = (light.Texture != null);
                if (hasTexture)
                {
                    var textureProjection = Matrix.CreateOrthographicOffCenter(
                        -light.TextureOffset.X,
                        -light.TextureOffset.X + Math.Abs(light.TextureScale.X),
                        light.TextureOffset.Y,
                        light.TextureOffset.Y + Math.Abs(light.TextureScale.Y),
                        1,  // Not relevant
                        2); // Not relevant.
                    var scale = Matrix.CreateScale(Math.Sign(light.TextureScale.X), Math.Sign(light.TextureScale.Y), 1);

                    _parameterTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * scale * textureProjection * lightPose.Inverse));

                    _parameterTexture.SetValue(light.Texture);
                }

                if (lightNode.Clip != null)
                {
                    var data = lightNode.RenderData as LightRenderData;
                    if (data == null)
                    {
                        data = new LightRenderData();
                        lightNode.RenderData = data;
                    }

                    data.UpdateClipSubmesh(context.GraphicsService, lightNode);

                    graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail;
                    graphicsDevice.BlendState        = GraphicsHelper.BlendStateNoColorWrite;

                    _parameterWorldViewProjection.SetValue((Matrix)data.ClipMatrix * viewProjection);
                    _passClip.Apply();
                    data.ClipSubmesh.Draw();

                    graphicsDevice.DepthStencilState = lightNode.InvertClip
            ? GraphicsHelper.DepthStencilStateStencilEqual0
            : GraphicsHelper.DepthStencilStateStencilNotEqual0;
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;
                }
                else
                {
                    graphicsDevice.DepthStencilState = DepthStencilState.None;
                }

                if (hasShadow)
                {
                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passShadowedTexturedAlpha.Apply();
                        }
                        else
                        {
                            _passShadowedTexturedRgb.Apply();
                        }
                    }
                    else
                    {
                        _passShadowed.Apply();
                    }
                }
                else
                {
                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passTexturedAlpha.Apply();
                        }
                        else
                        {
                            _passTexturedRgb.Apply();
                        }
                    }
                    else
                    {
                        _passDefault.Apply();
                    }
                }

                graphicsDevice.DrawFullScreenQuad();
            }

            savedRenderState.Restore();
        }
Example #10
0
        // Perform FFTs.
        // 4 complex input images: source0.xy, source0.zw, source1.xy, source1.zw
        // 2 targets: target0 = displacement map, target1 = normal map using Color format.
        public void Process(RenderContext context, bool forward, Texture2D source0, Texture2D source1, RenderTarget2D target0, RenderTarget2D target1, float choppiness)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (source0 == null)
            {
                throw new ArgumentNullException("source0");
            }
            if (source1 == null)
            {
                throw new ArgumentNullException("source1");
            }

            if (forward)
            {
                // For forward FFT, uncomment the LastPassScale stuff!
                throw new NotImplementedException("Forward FFT not implemented.");
            }

            var graphicsService  = context.GraphicsService;
            var graphicsDevice   = graphicsService.GraphicsDevice;
            var renderTargetPool = graphicsService.RenderTargetPool;

            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.BlendState        = BlendState.Opaque;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.None;

            int size = source0.Width;

            _parameterSize.SetValue((float)size);

            _parameterChoppiness.SetValue(choppiness);

            int numberOfButterflyPasses = (int)MathHelper.Log2GreaterOrEqual((uint)source0.Width);

            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            _parameterButterflyTexture.SetValue(GetButterflyTexture(forward, numberOfButterflyPasses));

            var format    = new RenderTargetFormat(size, size, false, source0.Format, DepthFormat.None);
            var tempPing0 = renderTargetPool.Obtain2D(format);
            var tempPing1 = renderTargetPool.Obtain2D(format);
            var tempPong0 = renderTargetPool.Obtain2D(format);
            var tempPong1 = renderTargetPool.Obtain2D(format);

            //_parameterIsLastPass.SetValue(false);

            // Perform horizontal and vertical FFT pass.
            for (int i = 0; i < 2; i++)
            {
                //_parameterLastPassScale.SetValue(1);

                // Perform butterfly passes. We ping-pong between two temp targets.
                for (int pass = 0; pass < numberOfButterflyPasses; pass++)
                {
                    _parameterButterflyIndex.SetValue(0.5f / numberOfButterflyPasses + (float)pass / numberOfButterflyPasses);

                    if (i == 0 && pass == 0)
                    {
                        // First pass.
                        _renderTargetBindings[0] = new RenderTargetBinding(tempPing0);
                        _renderTargetBindings[1] = new RenderTargetBinding(tempPing1);
                        graphicsDevice.SetRenderTargets(_renderTargetBindings);
                        _parameterSourceTexture0.SetValue(source0);
                        _parameterSourceTexture1.SetValue(source1);
                    }
                    else if (i == 1 && pass == numberOfButterflyPasses - 1)
                    {
                        // Last pass.
                        // We have explicit shader passes for the last FFT pass.
                        break;

                        //_parameterIsLastPass.SetValue(true);
                        //if (forward)
                        //  _parameterLastPassScale.SetValue(1.0f / size / size);

                        //if (_renderTargetBindings[0].RenderTarget == tempPing0)
                        //{
                        //  _renderTargetBindings[0] = new RenderTargetBinding(target0);
                        //  _renderTargetBindings[1] = new RenderTargetBinding(target1);
                        //  graphicsDevice.SetRenderTargets(_renderTargetBindings);
                        //  _parameterSourceTexture0.SetValue(tempPing0);
                        //  _parameterSourceTexture1.SetValue(tempPing1);
                        //}
                        //else
                        //{
                        //  _renderTargetBindings[0] = new RenderTargetBinding(target0);
                        //  _renderTargetBindings[1] = new RenderTargetBinding(target1);
                        //  graphicsDevice.SetRenderTargets(_renderTargetBindings);
                        //  _parameterSourceTexture0.SetValue(tempPong0);
                        //  _parameterSourceTexture1.SetValue(tempPong1);
                        //}
                    }
                    else
                    {
                        // Intermediate pass.
                        if (_renderTargetBindings[0].RenderTarget == tempPing0)
                        {
                            _renderTargetBindings[0] = new RenderTargetBinding(tempPong0);
                            _renderTargetBindings[1] = new RenderTargetBinding(tempPong1);
                            graphicsDevice.SetRenderTargets(_renderTargetBindings);
                            _parameterSourceTexture0.SetValue(tempPing0);
                            _parameterSourceTexture1.SetValue(tempPing1);
                        }
                        else
                        {
                            _renderTargetBindings[0] = new RenderTargetBinding(tempPing0);
                            _renderTargetBindings[1] = new RenderTargetBinding(tempPing1);
                            graphicsDevice.SetRenderTargets(_renderTargetBindings);
                            _parameterSourceTexture0.SetValue(tempPong0);
                            _parameterSourceTexture1.SetValue(tempPong1);
                        }
                    }

                    if (i == 0)
                    {
                        _passFftHorizontal.Apply();
                    }
                    else
                    {
                        _passFftVertical.Apply();
                    }

                    graphicsDevice.DrawFullScreenQuad();
                }
            }

            // Perform final vertical FFT passes. We have to perform them separately
            // because displacement map and normal map usually have different bit depth.
            // Final pass for displacement.
            graphicsDevice.SetRenderTarget(target0);
            if (_renderTargetBindings[1].RenderTarget == tempPing1)
            {
                _parameterSourceTexture0.SetValue(tempPing0);
            }
            else
            {
                _parameterSourceTexture0.SetValue(tempPong0);
            }

            _passFftDisplacement.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Final pass for normals.
            graphicsDevice.SetRenderTarget(target1);
            if (_renderTargetBindings[1].RenderTarget == tempPing1)
            {
                _parameterSourceTexture0.SetValue(tempPing1);
            }
            else
            {
                _parameterSourceTexture0.SetValue(tempPong1);
            }

            _passFftNormal.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Clean up.
            _renderTargetBindings[0] = default(RenderTargetBinding);
            _renderTargetBindings[1] = default(RenderTargetBinding);
            _parameterButterflyTexture.SetValue((Texture2D)null);
            _parameterSourceTexture0.SetValue((Texture2D)null);
            _parameterSourceTexture1.SetValue((Texture2D)null);

            renderTargetPool.Recycle(tempPing0);
            renderTargetPool.Recycle(tempPing1);
            renderTargetPool.Recycle(tempPong0);
            renderTargetPool.Recycle(tempPong1);

            savedRenderState.Restore();

            // Reset the texture stages. If a floating point texture is set, we get exceptions
            // when a sampler with bilinear filtering is set.
#if !MONOGAME
            graphicsDevice.ResetTextures();
#endif
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;

            var cameraNode = context.CameraNode;

            _parameterViewInverse.SetValue(cameraNode.PoseWorld);
            _parameterGBuffer0.SetValue(context.GBuffer0);

            Viewport viewport = context.Viewport;

            _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

            if (_jitterMap == null)
            {
                _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);
            }

            _parameterJitterMap.SetValue(_jitterMap);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var shadow = lightNode.Shadow as StandardShadow;
                if (shadow == null)
                {
                    continue;
                }

                if (shadow.ShadowMap == null || shadow.ShadowMask == null)
                {
                    continue;
                }

                // The effect must only render in a specific channel.
                // Do not change blend state if the correct write channels is already set, e.g. if this
                // shadow is part of a CompositeShadow, the correct blend state is already set.
                if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
                {
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];
                }

                _parameterParameters1.SetValue(new Vector4(
                                                   shadow.Near,
                                                   shadow.Far,
                                                   shadow.EffectiveDepthBias,
                                                   shadow.EffectiveNormalOffset));

                // If we use a subset of the Poisson kernel, we have to normalize the scale.
                int   numberOfSamples = Math.Min(shadow.NumberOfSamples, PoissonKernel.Length);
                float filterRadius    = shadow.FilterRadius;
                if (numberOfSamples > 0)
                {
                    filterRadius /= PoissonKernel[numberOfSamples - 1].Length();
                }

                _parameterParameters2.SetValue(new Vector3(
                                                   shadow.ShadowMap.Width,
                                                   filterRadius,
                                                   // The StandardShadow.JitterResolution is the number of texels per world unit.
                                                   // In the shader the parameter JitterResolution contains the division by the jitter map size.
                                                   shadow.JitterResolution / _jitterMap.Width));

                _parameterLightPosition.SetValue((Vector3)cameraNode.PoseWorld.ToLocalPosition(lightNode.PoseWorld.Position));

                Matrix cameraViewToShadowView = cameraNode.PoseWorld * shadow.View;
                _parameterShadowView.SetValue(cameraViewToShadowView);
                _parameterShadowMatrix.SetValue(cameraViewToShadowView * shadow.Projection);
                _parameterShadowMap.SetValue(shadow.ShadowMap);

                var      rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                Vector2F texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                var pass = GetPass(numberOfSamples);

                if (numberOfSamples > 0)
                {
                    if (_lastNumberOfSamples != numberOfSamples)
                    {
                        // Create an array with the first n samples and the rest set to 0.
                        _lastNumberOfSamples = numberOfSamples;
                        for (int j = 0; j < numberOfSamples; j++)
                        {
                            _samples[j].X = PoissonKernel[j].X;
                            _samples[j].Y = PoissonKernel[j].Y;
                            _samples[j].Z = 1.0f / numberOfSamples;

                            // Note [HelmutG]: I have tried weights decreasing with distance but that did not
                            // look better.
                        }

                        // Set the rest to zero.
                        for (int j = numberOfSamples; j < _samples.Length; j++)
                        {
                            _samples[j] = Vector3.Zero;
                        }

                        _parameterSamples.SetValue(_samples);
                    }
                    else if (i == 0)
                    {
                        // Apply offsets in the first loop.
                        _parameterSamples.SetValue(_samples);
                    }
                }

                pass.Apply();

                graphicsDevice.DrawQuad(rectangle);
            }

            _parameterGBuffer0.SetValue((Texture2D)null);
            _parameterJitterMap.SetValue((Texture2D)null);
            _parameterShadowMap.SetValue((Texture2D)null);
            savedRenderState.Restore();
        }
Example #12
0
        /// <inheritdoc/>
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_effect);

            var originalRenderTarget = context.RenderTarget;
            var originalViewport     = context.Viewport;

            var graphicsService = context.GraphicsService;
            var graphicsDevice  = graphicsService.GraphicsDevice;
            //var renderTargetPool = graphicsService.RenderTargetPool;

            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.BlendState        = BlendState.Opaque;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.None;

            int frame = context.Frame;

            for (int nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++)
            {
                var node = nodes[nodeIndex] as WaterNode;
                if (node == null)
                {
                    continue;
                }

                var waves = node.Waves as OceanWaves;
                if (waves == null)
                {
                    continue;
                }

                // We update the waves only once per frame.
                if (waves.LastFrame == frame)
                {
                    continue;
                }

                waves.LastFrame = frame;

                float time = (float)context.Time.TotalSeconds;

                // Initialize h0 spectrum. Perform CPU FFT.
                waves.Update(graphicsDevice, time);

                int n = waves.TextureSize;

                // Allocate textures in the first frame and when the TextureSize was changed.
                if (waves.DisplacementSpectrum == null || waves.DisplacementSpectrum.Width != n)
                {
                    waves.DisplacementSpectrum.SafeDispose();
                    waves.NormalSpectrum.SafeDispose();
                    waves.DisplacementMap.SafeDispose();
                    waves.NormalMap.SafeDispose();

                    waves.DisplacementSpectrum = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
                    waves.NormalSpectrum       = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
                    waves.DisplacementMap      = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
                    waves.NormalMap            = new RenderTarget2D(
                        _graphicsService.GraphicsDevice,
                        n,
                        n,
                        true,
                        SurfaceFormat.Color,
                        DepthFormat.None);
                }

                // Create spectrum (h, D, N) for current time from h0.
                _renderTargetBindings[0] = new RenderTargetBinding(waves.DisplacementSpectrum);
                _renderTargetBindings[1] = new RenderTargetBinding(waves.NormalSpectrum);
                graphicsDevice.SetRenderTargets(_renderTargetBindings);
                _parameterSize.SetValue((float)n);
                _parameterSpectrumParameters.SetValue(new Vector4(
                                                          waves.TileSize,
                                                          waves.Gravity,
                                                          time,
                                                          waves.HeightScale));
                _parameterSourceTexture.SetValue(waves.H0Spectrum);
                _passSpectrum.Apply();
                graphicsDevice.DrawFullScreenQuad();

                // Do inverse FFT.
                _fft.Process(
                    context,
                    false,
                    waves.DisplacementSpectrum,
                    waves.NormalSpectrum,
                    (RenderTarget2D)waves.DisplacementMap,
                    (RenderTarget2D)waves.NormalMap,
                    waves.Choppiness);

                #region ----- Old Debugging Code -----

                // Create textures from CPU FFT data for debug visualization.
                //n = waves.CpuSize;
                //var s0Data = new Vector4[n * n];
                //var s1Data = new Vector4[n * n];
                //var s0 = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
                //var s1 = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
                //for (int y = 0; y < n; y++)
                //{
                //  for (int x = 0; x < n; x++)
                //  {
                //s0Data[y * n + x] = new Vector4(
                //  -waves._D[x, y].X * waves.Choppiness,
                //  waves._h[x, y].X * 1,
                //  -waves._D[x, y].Y * waves.Choppiness,
                //  1);

                //s1Data[y * n + x] = new Vector4(
                //  waves._N[x, y].X,
                //  waves._N[x, y].Y,
                //  0,
                //  0);
                //  }
                //}
                //s0.SetData(s0Data);
                //s1.SetData(s1Data);
                //WaterSample._t0 = s0;
                //WaterSample._t1 = waves.DisplacementMap;
                #endregion
            }

            savedRenderState.Restore();
            graphicsDevice.SetRenderTarget(null);
            context.RenderTarget = originalRenderTarget;
            context.Viewport     = originalViewport;

            _renderTargetBindings[0] = default(RenderTargetBinding);
            _renderTargetBindings[1] = default(RenderTargetBinding);

            // Reset the texture stages. If a floating point texture is set, we get exceptions
            // when a sampler with bilinear filtering is set.
#if !MONOGAME
            graphicsDevice.ResetTextures();
#endif
        }
Example #13
0
        /// <summary>
        /// Draws the texts.
        /// </summary>
        /// <param name="context">The render context.</param>
        /// <remarks>
        /// If <see cref="SpriteBatch"/> or <see cref="SpriteFont"/> are <see langword="null"/>, then
        /// <see cref="Render"/> does nothing.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="context"/> is <see langword="null"/>.
        /// </exception>
        public void Render(RenderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (SpriteBatch == null || SpriteFont == null)
            {
                return;
            }

            context.Validate(SpriteBatch);

            if (_texts2D.Count == 0 && _texts3D.Count == 0)
            {
                return;
            }

            if (_texts3D.Count > 0)
            {
                context.ThrowIfCameraMissing();
            }

            var savedRenderState = new RenderStateSnapshot(SpriteBatch.GraphicsDevice);

            if (EnableDepthTest)
            {
                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
            }
            else
            {
                SpriteBatch.Begin();
            }

            // ----- Draw world space text.
            if (_texts3D.Count > 0)
            {
                CameraNode cameraNode     = context.CameraNode;
                Matrix     viewProjection = cameraNode.Camera.Projection * cameraNode.View;
                Viewport   viewport       = SpriteBatch.GraphicsDevice.Viewport;

                foreach (var textInfo in _texts3D)
                {
                    // Transform position from world space to the viewport.
                    Vector3 pos = viewport.ProjectToViewport(textInfo.Position, viewProjection);
                    if (pos.Z < 0 || pos.Z > 1)
                    {
                        continue;
                    }

                    // Snap to pixels. Also add a small bias in one direction because when we draw text at
                    // certain positions (e.g. view space origin) and the presentation target width is an
                    // odd number, the pos will be exactly at pixel centers and due to numerical errors it
                    // would jitter between pixels if the camera moves slightly.
                    pos.X = (float)Math.Round(pos.X + 0.01f);
                    pos.Y = (float)Math.Round(pos.Y + 0.01f);

                    var textAsString = textInfo.Text as string;
                    if (!string.IsNullOrEmpty(textAsString))
                    {
                        var textOrigin = GetOrigin(textAsString, textInfo.RelativeOrigin);
                        SpriteBatch.DrawString(SpriteFont, textAsString, new Vector2(pos.X, pos.Y), textInfo.Color, 0, textOrigin, 1.0f, SpriteEffects.None, pos.Z);
                    }
                    else
                    {
                        var textAsStringBuilder = textInfo.Text as StringBuilder;
                        if (textAsStringBuilder != null && textAsStringBuilder.Length > 0)
                        {
                            var textOrigin = GetOrigin(textAsStringBuilder, textInfo.RelativeOrigin);
                            SpriteBatch.DrawString(SpriteFont, textAsStringBuilder, new Vector2(pos.X, pos.Y), textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, pos.Z);
                        }
                    }
                }
            }

            // ----- Draw screen space text.
            foreach (var textInfo in _texts2D)
            {
                var textAsString = textInfo.Text as string;
                if (!string.IsNullOrEmpty(textAsString))
                {
                    var textOrigin = GetOrigin(textAsString, textInfo.RelativeOrigin);
                    SpriteBatch.DrawString(SpriteFont, textAsString, (Vector2)textInfo.Position, textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, 0);
                }
                else
                {
                    var textAsStringBuilder = textInfo.Text as StringBuilder;
                    if (textAsStringBuilder != null && textAsStringBuilder.Length > 0)
                    {
                        var textOrigin = GetOrigin(textAsStringBuilder, textInfo.RelativeOrigin);
                        SpriteBatch.DrawString(SpriteFont, textAsStringBuilder, (Vector2)textInfo.Position, textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, 0);
                    }
                }
            }

            SpriteBatch.End();

            savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.BlendState        = BlendState.AlphaBlend;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

            // Camera properties
            var    cameraNode = context.CameraNode;
            Matrix view       = (Matrix) new Matrix44F(cameraNode.PoseWorld.Orientation.Transposed, new Vector3F());

            _parameterView.SetValue(view);
            Matrix projection = cameraNode.Camera.Projection;

            _parameterProjection.SetValue(projection);

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as GradientTextureSkyNode;
                if (node == null)
                {
                    continue;
                }

                // GradientTextureSkyNode is visible in current frame.
                node.LastFrame = frame;

                _parameterSunDirection.SetValue((Vector3)node.SunDirection);
                _parameterTime.SetValue((float)node.TimeOfDay.TotalHours / 24);
                _parameterColor.SetValue((Vector4)node.Color);
                _parameterFrontTexture.SetValue(node.FrontTexture);
                _parameterBackTexture.SetValue(node.BackTexture);

                if (node.CieSkyStrength < Numeric.EpsilonF)
                {
                    if (context.IsHdrEnabled())
                    {
                        _passLinear.Apply();
                    }
                    else
                    {
                        _passGamma.Apply();
                    }
                }
                else
                {
                    var p = node.CieSkyParameters;
                    _parameterAbcd.SetValue(new Vector4(p.A, p.B, p.C, p.D));
                    _parameterEAndStrength.SetValue(new Vector2(p.E, node.CieSkyStrength));

                    if (context.IsHdrEnabled())
                    {
                        _passCieLinear.Apply();
                    }
                    else
                    {
                        _passCieGamma.Apply();
                    }
                }
                _submesh.Draw();
            }

            savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var shadow = lightNode.Shadow as CompositeShadow;
                if (shadow == null)
                {
                    continue;
                }

                if (shadow.ShadowMask == null)
                {
                    continue;
                }

                // Write into a single channel and use min() blending.
                graphicsDevice.BlendState = BlendStates[shadow.ShadowMaskChannel];

                for (int j = 0; j < shadow.Shadows.Count; j++)
                {
                    // Temporarily set shadow mask and shadow mask channel of child shadows.
                    var childShadow = shadow.Shadows[j];
                    childShadow.ShadowMask        = shadow.ShadowMask;
                    childShadow.ShadowMaskChannel = shadow.ShadowMaskChannel;

                    // Temporarily exchange LightNode.Shadow and render the child shadow.
                    lightNode.Shadow = childShadow;

                    for (int k = 0; k < _shadowMaskRenderers.Count; k++)
                    {
                        var renderer = _shadowMaskRenderers[k];
                        if (renderer.CanRender(lightNode, context))
                        {
                            renderer.Render(lightNode, context);
                            break;
                        }
                    }

                    // Remove shadow mask references. Strictly speaking, the mask is correct
                    // for the composite shadow. It is not correct for the child shadow. The child
                    // shadow only contributes to the mask. Therefore, childShadowMask should not be
                    // set.
                    childShadow.ShadowMask        = null;
                    childShadow.ShadowMaskChannel = 0;
                }

                lightNode.Shadow = shadow;
            }

            savedRenderState.Restore();
        }
Example #16
0
        public void Render(IList<SceneNode> occluders, LightNode lightNode, SceneNodeRenderer renderer, RenderContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              context.ThrowIfCameraMissing();

              // ----- Sort occluders by type: IOcclusionProxy vs. SceneNode
              SortOccluders(occluders, renderer, context);
              Statistics.Occluders = _occlusionProxies.Count + _sceneNodes.Count;

              // ----- Update all IOcclusionProxy in background.
              if (_occlusionProxies.Count > 0)
              {
            if (EnableMultithreading)
              _updateTask = Parallel.Start(_updateOcclusionProxies);
            else
              UpdateOcclusionProxies();
              }

              // ----- Backup render state.
              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var originalRenderState = new RenderStateSnapshot(graphicsDevice);

              // ----- Camera properties
              var cameraNode = context.CameraNode;
              Matrix cameraView = (Matrix)cameraNode.View;
              var cameraProjection = cameraNode.Camera.Projection;
              Matrix cameraViewProjection = cameraView * cameraProjection;

              if (lightNode == null)
              {
            _lightHzbAvailable = false;
              }
              else
              {
            // ----- Render light HZB.
            _lightHzbAvailable = true;

            var shadow = lightNode.Shadow as CascadedShadow;
            if (shadow == null)
              throw new ArgumentException("LightNode expected to have a CascadedShadow.", "lightNode");

            // Set up orthographic camera similar to CascadedShadowMapRenderer.
            context.CameraNode = _orthographicCameraNode;

            // Part of camera frustum covered by shadow map.
            var maxShadowDistance = shadow.Distances[shadow.NumberOfCascades - 1];
            _splitVolume.SetFieldOfView(cameraProjection.FieldOfViewY, cameraProjection.AspectRatio, cameraProjection.Near, Math.Min(cameraProjection.Far, maxShadowDistance));

            // Find the bounding sphere of the camera frustum.
            Vector3F center;
            float radius;
            GetBoundingSphere(_splitVolume, out center, out radius);

            Matrix33F orientation = lightNode.PoseWorld.Orientation;
            Vector3F lightBackward = orientation.GetColumn(2);
            var orthographicProjection = (OrthographicProjection)_orthographicCameraNode.Camera.Projection;

            // Create a tight orthographic frustum around the cascade's bounding sphere.
            orthographicProjection.SetOffCenter(-radius, radius, -radius, radius, 0, 2 * radius);
            center = cameraNode.PoseWorld.ToWorldPosition(center);
            Vector3F cameraPosition = center + radius * lightBackward;
            Pose frustumPose = new Pose(cameraPosition, orientation);

            // For rendering the shadow map, move near plane back by MinLightDistance
            // to catch occluders in front of the cascade.
            orthographicProjection.Near = -shadow.MinLightDistance;
            _orthographicCameraNode.PoseWorld = frustumPose;

            Pose lightView = frustumPose.Inverse;
            Matrix lightViewProjection = (Matrix)lightView * orthographicProjection;

            _parameterCameraViewProj.SetValue(lightViewProjection);
            _parameterCameraNear.SetValue(orthographicProjection.Near);
            _parameterCameraFar.SetValue(orthographicProjection.Far);

            RenderOccluders(renderer, context);
            CreateDepthHierarchy(_lightHzb, context);

            // Set effect parameters for use in Query().
            _lightAabb = _orthographicCameraNode.Aabb;
            _parameterLightViewProj.SetValue(lightViewProjection);
            _parameterLightToCamera.SetValue(Matrix.Invert(lightViewProjection) * cameraViewProjection);

            context.CameraNode = cameraNode;
              }

              // ----- Render camera HZB.
              // Set camera parameters. (These effect parameters are also needed in Query()!)
              _cameraAabb = cameraNode.Aabb;
              _parameterCameraViewProj.SetValue(cameraViewProjection);
              _parameterCameraNear.SetValue(cameraProjection.Near);
              _parameterCameraFar.SetValue(cameraProjection.Far);

              var lodCameraNode = context.LodCameraNode;
              if (lodCameraNode != null)
              {
            // Enable distance culling.
            _parameterCameraPosition.SetValue((Vector3)lodCameraNode.PoseWorld.Position);
            float yScale = Math.Abs(lodCameraNode.Camera.Projection.ToMatrix44F().M11);
            _parameterNormalizationFactor.SetValue(1.0f / yScale * cameraNode.LodBias * context.LodBias);
              }
              else
              {
            // Disable distance culling.
            _parameterCameraPosition.SetValue(new Vector3());
            _parameterNormalizationFactor.SetValue(0);
              }

              RenderOccluders(renderer, context);
              CreateDepthHierarchy(_cameraHzb, context);

              _sceneNodes.Clear();
              _occlusionProxies.Clear();

              // Restore render state.
              graphicsDevice.SetRenderTarget(null);
              originalRenderState.Restore();

              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
        }
        /// <inheritdoc/>
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.BlendState = BlendState.AlphaBlend;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

              // Camera properties
              var cameraNode = context.CameraNode;
              Matrix view = (Matrix)new Matrix44F(cameraNode.PoseWorld.Orientation.Transposed, new Vector3F());
              _parameterView.SetValue(view);
              Matrix projection = cameraNode.Camera.Projection;
              _parameterProjection.SetValue(projection);

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as ScatteringSkyNode;
            if (node == null)
              continue;

            // ScatteringSkyNode is visible in current frame.
            node.LastFrame = frame;

            _parameterSunDirection.SetValue((Vector3)node.SunDirection);
            _parameterSunIntensity.SetValue((Vector3)(node.SunIntensity * node.SunColor));
            _parameterRadii.SetValue(new Vector4(
              node.AtmosphereHeight + node.PlanetRadius,    // Atmosphere radius
              node.PlanetRadius,                            // Ground radius
              node.ObserverAltitude + node.PlanetRadius,    // Observer radius
              node.ScaleHeight));                           // Absolute Scale height
            _parameterNumberOfSamples.SetValue(node.NumberOfSamples);
            _parameterBetaRayleigh.SetValue((Vector3)node.BetaRayleigh);
            _parameterBetaMie.SetValue((Vector3)node.BetaMie);
            _parameterGMie.SetValue(node.GMie);
            _parameterTransmittance.SetValue(node.Transmittance);

            if (node.BaseHorizonColor.IsNumericallyZero && node.BaseZenithColor.IsNumericallyZero)
            {
              // No base color.
              if (context.IsHdrEnabled())
            _passLinear.Apply();
              else
            _passGamma.Apply();
            }
            else
            {
              // Add base color.
              _parameterBaseHorizonColor.SetValue((Vector4)new Vector4F(node.BaseHorizonColor, node.BaseColorShift));
              _parameterBaseZenithColor.SetValue((Vector3)node.BaseZenithColor);

              if (context.IsHdrEnabled())
            _passLinearWithBaseColor.Apply();
              else
            _passGammaWithBaseColor.Apply();
            }

            _submesh.Draw();
              }

              savedRenderState.Restore();
        }
Example #18
0
        private void ProcessJobs(RenderContext context, RenderOrder order)
        {
            Effect        currentEffect          = null;
            EffectEx      currentEffectEx        = null;
            EffectBinding currentMaterialBinding = null;

            // Set render states for drawing decals.
            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;

            if (!ClipAtNearPlane)
            {
                // Cache some info for near plane intersection tests.

                var cameraNode = context.CameraNode;
                var cameraPose = cameraNode.PoseWorld;
                var projection = cameraNode.Camera.Projection;

                // Get min and max of near plane AABB in view space.
                var min = new Vector3F(projection.Left, projection.Bottom, -projection.Near);
                var max = new Vector3F(projection.Right, projection.Top, -projection.Near);

                // Convert min and max to world space.
                min = cameraPose.ToWorldPosition(min);
                max = cameraPose.ToWorldPosition(max);

                // Get world space aabb
                _cameraNearPlaneAabbWorld = new Aabb(Vector3F.Min(min, max), Vector3F.Max(min, max));
            }

            // The BlendState is set below.
            bool isGBufferPass = string.Equals(context.RenderPass, "GBuffer", StringComparison.OrdinalIgnoreCase); // InvariantCultureIgnoreCase would be better but is not available in WindowsStore.
            var  blendState    = isGBufferPass ? GBufferBlendState : BlendState.AlphaBlend;

            int index    = 0;
            var jobs     = _jobs.Array;
            int jobCount = _jobs.Count;

            while (index < jobCount)
            {
                // Update BlendState. (Needs to be done for each batch because decals can
                // change the blend mode in the material. For example, alpha-tested decals
                // can disable alpha blending.)
                graphicsDevice.BlendState = blendState;

                uint materialKey             = jobs[index].MaterialKey;
                var  materialInstanceBinding = jobs[index].MaterialInstanceBinding;
                var  materialBinding         = materialInstanceBinding.MaterialBinding;
                var  effectEx = materialBinding.EffectEx;

                Debug.Assert(effectEx != null, "EffectEx must not be null.");

                context.MaterialBinding         = materialBinding;
                context.MaterialInstanceBinding = materialInstanceBinding;

                if (currentEffectEx != effectEx)
                {
                    // ----- Next effect.
                    currentEffectEx = effectEx;
                    currentEffect   = effectEx.Resource;

                    // Reset ID. (Only used during state sorting.)
                    ResetEffectId(effectEx);

                    // Update and apply global bindings.
                    foreach (var binding in currentEffectEx.ParameterBindings)
                    {
                        if (binding.Description.Hint == EffectParameterHint.Global)
                        {
                            binding.Update(context);
                            binding.Apply(context);
                        }
                    }
                }

                if (currentMaterialBinding != materialBinding)
                {
                    // ----- Next material.
                    currentMaterialBinding = materialBinding;

                    // Reset ID. (Only used during state sorting.)
                    ResetMaterialId(materialBinding);

                    // Update and apply material bindings.
                    foreach (var binding in currentMaterialBinding.ParameterBindings)
                    {
                        binding.Update(context);
                        binding.Apply(context);

                        // In "GBuffer" pass the specular power is written to the alpha channel.
                        // The specular power needs to be set as the BlendFactor. (See GBufferBlendState.)
                        if (isGBufferPass && binding.Description.Semantic == DefaultEffectParameterSemantics.SpecularPower)
                        {
                            var specularPowerBinding = binding as EffectParameterBinding <float>;
                            if (specularPowerBinding != null)
                            {
                                // Note: Specular power is currently encoded using log2 - see Deferred.fxh.
                                // (Blending encoded values is mathematically not correct, but there are no
                                // rules for blending specular powers anyway.)
                                float specularPower        = specularPowerBinding.Value;
                                int   encodedSpecularPower = (byte)((float)Math.Log(specularPower + 0.0001f, 2) / 17.6f * 255.0f);
                                graphicsDevice.BlendFactor = new Color(255, 255, 255, encodedSpecularPower);
                            }
                        }
                    }
                }

                // Note: EffectTechniqueBinding only returns the EffectTechnique, but does
                // not set it as the current technique.
                var techniqueBinding = materialInstanceBinding.TechniqueBinding;
                var technique        = techniqueBinding.GetTechnique(currentEffect, context);

                // See if there is an associated technique that supports hardware instancing.
                //var instancingTechnique = (EffectTechnique)null;
                //var techniqueDescription = currentEffectEx.TechniqueDescriptions[technique];
                //if (techniqueDescription != null)
                //  instancingTechnique = techniqueDescription.InstancingTechnique;

                //if (EnableInstancing && instancingTechnique != null)
                //{
                //  // ----- Instancing
                //  // Render all decals that share the same effect/material and batch instances
                //  // into a single draw call.
                //  int count = 1;
                //  while (index + count < jobCount && jobs[index + count].MaterialKey == materialKey)
                //    count++;

                //  if (count >= InstancingThreshold)
                //  {
                //    // Draw decals using instancing.
                //    currentEffect.CurrentTechnique = instancingTechnique;
                //    var passBinding = techniqueBinding.GetPassBinding(instancingTechnique, context);
                //    DrawInstanced(ref passBinding, context, index, count);
                //    index += count;
                //  }
                //  else
                //  {
                //    // Draw decals without instancing.
                //    currentEffect.CurrentTechnique = technique;
                //    var passBinding = techniqueBinding.GetPassBinding(technique, context);
                //    Draw(ref passBinding, context, index, count, order);
                //    index += count;
                //  }
                //}
                //else
                {
                    // ----- No instancing

                    // Render all decals that share the same effect/material.
                    int count = 1;
                    while (index + count < jobCount && jobs[index + count].MaterialKey == materialKey)
                    {
                        count++;
                    }

                    currentEffect.CurrentTechnique = technique;
                    var passBinding = techniqueBinding.GetPassBinding(technique, context);
                    Draw(ref passBinding, context, index, count, order);
                    index += count;
                }
            }

            context.MaterialBinding         = null;
            context.MaterialInstanceBinding = null;

            savedRenderState.Restore();
        }
Example #19
0
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              // Camera properties
              var cameraNode = context.CameraNode;
              Matrix view = (Matrix)cameraNode.View;
              Matrix projection = cameraNode.Camera.Projection;
              Matrix viewProjection = view * projection;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              // Blend additively over any cosmos textures.
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
              graphicsDevice.BlendState = BlendState.Additive;

              _effectParameterViewportSize.SetValue(new Vector2(context.Viewport.Width, context.Viewport.Height));

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as StarfieldNode;
            if (node == null)
              continue;

            // SkyboxNode is visible in current frame.
            node.LastFrame = frame;

            if (node.Stars != null && node.Stars.Count > 0)
            {
              Matrix world = (Matrix)new Matrix44F(node.PoseWorld.Orientation, Vector3F.Zero);
              _effectParameterWorldViewProjection.SetValue(world * viewProjection);

              // In [ZFX] the star luminance of the precomputed star data is scaled with
              // float const viewFactor = tan(fov);
              // float const resolutionFactor = resolution / 1920.0f;
              // float const luminanceScale = 1.0f / (viewFactor * viewFactor) * (resolutionFactor * resolutionFactor);
              // We ignore this here, but we could add this factor to the Intensity parameter.
              _effectParameterIntensity.SetValue((Vector3)node.Color);

              if (context.IsHdrEnabled())
            _effectPassLinear.Apply();
              else
            _effectPassGamma.Apply();

              var mesh = GetStarfieldMesh(node, context);
              mesh.Draw();
            }
              }

              savedRenderState.Restore();
        }
Example #20
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_spriteBatch);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            // Camera properties
            var    cameraNode     = context.CameraNode;
            Matrix viewProjection = cameraNode.Camera.Projection * cameraNode.View;
            var    viewport       = graphicsDevice.Viewport;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            SpriteSortMode sortMode;

            switch (order)
            {
            case RenderOrder.Default:
                sortMode = SpriteSortMode.Texture;
                break;

            case RenderOrder.FrontToBack:
                sortMode = SpriteSortMode.FrontToBack;
                break;

            case RenderOrder.BackToFront:
                sortMode = SpriteSortMode.BackToFront;
                break;

            case RenderOrder.UserDefined:
            default:
                sortMode = SpriteSortMode.Deferred;
                break;
            }

            _spriteBatch.Begin(sortMode, graphicsDevice.BlendState, null, graphicsDevice.DepthStencilState, null);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as SpriteNode;
                if (node == null)
                {
                    continue;
                }

                // SpriteNode is visible in current frame.
                node.LastFrame = frame;

                // Position, size, and origin in pixels.
                Vector3 position = new Vector3();
                Vector2 size     = new Vector2();
                Vector2 origin   = new Vector2();

                var bitmapSprite = node.Sprite as ImageSprite;
                if (bitmapSprite != null)
                {
                    var packedTexture = bitmapSprite.Texture;
                    if (packedTexture != null)
                    {
                        // Project into viewport and snap to pixels.
                        position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                        position.X = (int)(position.X + 0.5f);
                        position.Y = (int)(position.Y + 0.5f);

                        // Get source rectangle (pixel bounds).
                        var sourceRectangle = packedTexture.GetBounds(node.AnimationTime);
                        size = new Vector2(sourceRectangle.Width, sourceRectangle.Height);

                        // Premultiply color.
                        Vector3 color3F = node.Color;
                        float   alpha   = node.Alpha;
                        Color   color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                        // Get absolute origin (relative to pixel bounds).
                        origin = (Vector2)node.Origin * size;

                        // Draw using SpriteBatch.
                        _spriteBatch.Draw(
                            packedTexture.TextureAtlas, new Vector2(position.X, position.Y), sourceRectangle,
                            color, node.Rotation, origin, (Vector2)node.Scale, SpriteEffects.None, position.Z);
                    }
                }
                else
                {
                    var textSprite = node.Sprite as TextSprite;
                    if (textSprite != null)
                    {
                        var font = textSprite.Font ?? _spriteFont;
                        if (font != null)
                        {
                            // Text can be a string or StringBuilder.
                            var text = textSprite.Text as string;
                            if (text != null)
                            {
                                if (text.Length > 0)
                                {
                                    // Project into viewport and snap to pixels.
                                    position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                                    position.X = (int)(position.X + 0.5f);
                                    position.Y = (int)(position.Y + 0.5f);

                                    // Premultiply color.
                                    Vector3 color3F = node.Color;
                                    float   alpha   = node.Alpha;
                                    Color   color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                                    // Get absolute origin (relative to pixel bounds).
                                    size   = font.MeasureString(text);
                                    origin = (Vector2)node.Origin * size;

                                    // Draw using SpriteBatch.
                                    _spriteBatch.DrawString(
                                        font, text, new Vector2(position.X, position.Y),
                                        color, node.Rotation, origin, (Vector2)node.Scale,
                                        SpriteEffects.None, position.Z);
                                }
                            }
                            else
                            {
                                var stringBuilder = textSprite.Text as StringBuilder;
                                if (stringBuilder != null && stringBuilder.Length > 0)
                                {
                                    // Project into viewport and snap to pixels.
                                    position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                                    position.X = (int)(position.X + 0.5f);
                                    position.Y = (int)(position.Y + 0.5f);

                                    // Premultiply color.
                                    Vector3 color3F = node.Color;
                                    float   alpha   = node.Alpha;
                                    Color   color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                                    // Get absolute origin (relative to pixel bounds).
                                    size   = font.MeasureString(stringBuilder);
                                    origin = (Vector2)node.Origin * size;

                                    // Draw using SpriteBatch.
                                    _spriteBatch.DrawString(
                                        font, stringBuilder, new Vector2(position.X, position.Y),
                                        color, node.Rotation, origin, (Vector2)node.Scale,
                                        SpriteEffects.None, position.Z);
                                }
                            }
                        }
                    }
                }

                // Store bounds an depth for hit tests.
                node.LastBounds = new Rectangle(
                    (int)(position.X - origin.X),
                    (int)(position.Y - origin.Y),
                    (int)(size.X * node.Scale.X),
                    (int)(size.Y * node.Scale.Y));

                node.LastDepth = position.Z;
            }

            _spriteBatch.End();
            savedRenderState.Restore();
        }
Example #21
0
        /// <summary>
        /// Draws the textures.
        /// </summary>
        /// <param name="context">The render context.</param>
        /// <remarks>
        /// If <see cref="SpriteBatch"/> is <see langword="null"/>, then <see cref="Render"/> does 
        /// nothing.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="context"/> is <see langword="null"/>.
        /// </exception>
        public void Render(RenderContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              if (SpriteBatch == null)
            return;

              var count = _textures.Count;
              if (count == 0)
            return;

              context.Validate(SpriteBatch);

              var savedRenderState = new RenderStateSnapshot(SpriteBatch.GraphicsDevice);

              SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullNone);

              for (int i = 0; i < count; i++)
              {
            var textureInfo = _textures[i];

            if (textureInfo.Texture.IsDisposed)
              continue;

            if (TextureHelper.IsFloatingPointFormat(textureInfo.Texture.Format))
            {
              // Floating-point textures must not use linear hardware filtering!
              SpriteBatch.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
              SpriteBatch.Draw(textureInfo.Texture, textureInfo.Rectangle, Color.White);
              SpriteBatch.GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
            }
            else
            {
              SpriteBatch.Draw(textureInfo.Texture, textureInfo.Rectangle, Color.White);
            }
              }

              SpriteBatch.End();

              savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            // Camera properties
            var    cameraNode     = context.CameraNode;
            Matrix view           = (Matrix)cameraNode.View;
            Matrix projection     = cameraNode.Camera.Projection;
            Matrix viewProjection = view * projection;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            // Blend additively over any cosmos textures.
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.BlendState        = BlendState.Additive;

            _effectParameterViewportSize.SetValue(new Vector2(context.Viewport.Width, context.Viewport.Height));

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as StarfieldNode;
                if (node == null)
                {
                    continue;
                }

                // SkyboxNode is visible in current frame.
                node.LastFrame = frame;

                if (node.Stars != null && node.Stars.Count > 0)
                {
                    Matrix world = (Matrix) new Matrix44F(node.PoseWorld.Orientation, Vector3F.Zero);
                    _effectParameterWorldViewProjection.SetValue(world * viewProjection);

                    // In [ZFX] the star luminance of the precomputed star data is scaled with
                    // float const viewFactor = tan(fov);
                    // float const resolutionFactor = resolution / 1920.0f;
                    // float const luminanceScale = 1.0f / (viewFactor * viewFactor) * (resolutionFactor * resolutionFactor);
                    // We ignore this here, but we could add this factor to the Intensity parameter.
                    _effectParameterIntensity.SetValue((Vector3)node.Color);

                    if (context.IsHdrEnabled())
                    {
                        _effectPassLinear.Apply();
                    }
                    else
                    {
                        _effectPassGamma.Apply();
                    }

                    var mesh = GetStarfieldMesh(node, context);
                    mesh.Draw();
                }
            }

            savedRenderState.Restore();
        }
        private void DrawText(int index, int endIndex, RenderContext context)
        {
            var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderStates = new RenderStateSnapshot(graphicsDevice);

              // The sprite batch and text effect are only created when needed.
              if (_spriteBatch == null)
              {
            _spriteBatch = context.GraphicsService.GetSpriteBatch();
            _textEffect = new BasicEffect(graphicsDevice)
            {
              TextureEnabled = true,
              VertexColorEnabled = true,
            };
              }

              _textEffect.View = (Matrix)context.CameraNode.View;
              _textEffect.Projection = context.CameraNode.Camera.Projection;

              var jobs = _jobs.Array;
              while (index < endIndex)
              {
            var node = jobs[index++].Node as BillboardNode;
            if (node == null)
              continue;

            var billboard = node.Billboard as TextBillboard;
            if (billboard == null)
              continue;

            var font = billboard.Font ?? _defaultFont;
            if (font == null)
              continue;

            var text = billboard.Text as string;
            var stringBuilder = billboard.Text as StringBuilder;
            if (string.IsNullOrEmpty(text) && (stringBuilder == null || stringBuilder.Length == 0))
              continue;

            Vector3F position = node.PoseWorld.Position;
            var orientation = billboard.Orientation;

            #region ----- Billboarding -----

            // (Code copied from BillboardBatchReach.)

            // Normal
            Vector3F normal;
            if (orientation.Normal == BillboardNormal.ViewPlaneAligned)
            {
              normal = _defaultNormal;
            }
            else if (orientation.Normal == BillboardNormal.ViewpointOriented)
            {
              Vector3F n = _cameraPose.Position - position;
              normal = n.TryNormalize() ? n : _defaultNormal;
            }
            else
            {
              normal = node.Normal;
            }

            // Axis = up vector
            Vector3F axis = node.Axis;
            if (orientation.IsAxisInViewSpace)
              axis = _cameraPose.ToWorldDirection(axis);

            if (1 - Vector3F.Dot(normal, axis) < Numeric.EpsilonF)
            {
              // Normal and axis are parallel.
              // --> Bend normal by adding a fraction of the camera down vector.
              Vector3F cameraDown = -_cameraPose.Orientation.GetColumn(1);
              normal += cameraDown * 0.001f;
              normal.Normalize();
            }

            // Compute right.
            //Vector3F right = Vector3F.Cross(axis, normal);
            // Inlined:
            Vector3F right;
            right.X = axis.Y * normal.Z - axis.Z * normal.Y;
            right.Y = axis.Z * normal.X - axis.X * normal.Z;
            right.Z = axis.X * normal.Y - axis.Y * normal.X;
            if (!right.TryNormalize())
              right = normal.Orthonormal1;   // Normal and axis are parallel --> Choose random perpendicular vector.

            if (orientation.IsAxisFixed)
            {
              // Make sure normal is perpendicular to right and up.
              //normal = Vector3F.Cross(right, axis);
              // Inlined:
              normal.X = right.Y * axis.Z - right.Z * axis.Y;
              normal.Y = right.Z * axis.X - right.X * axis.Z;
              normal.Z = right.X * axis.Y - right.Y * axis.X;

              // No need to normalize because right and up are normalized and perpendicular.
            }
            else
            {
              // Make sure axis is perpendicular to normal and right.
              //axis = Vector3F.Cross(normal, right);
              // Inlined:
              axis.X = normal.Y * right.Z - normal.Z * right.Y;
              axis.Y = normal.Z * right.X - normal.X * right.Z;
              axis.Z = normal.X * right.Y - normal.Y * right.X;

              // No need to normalize because normal and right are normalized and perpendicular.
            }
            #endregion

            _textEffect.World = new Matrix(right.X, right.Y, right.Z, 0,
                                       -axis.X, -axis.Y, -axis.Z, 0,
                                       normal.X, normal.Y, normal.Z, 0,
                                       position.X, position.Y, position.Z, 1);

            Vector3F color3F = node.Color * billboard.Color;
            float alpha = node.Alpha * billboard.Alpha;
            Color color = new Color(color3F.X * alpha,
                                color3F.Y * alpha,
                                color3F.Z * alpha,
                                alpha);

            Vector2 size = (text != null) ? font.MeasureString(text) : font.MeasureString(stringBuilder);
            Vector2 origin = size / 2;
            float scale = node.ScaleWorld.Y; // Assume uniform scale.

            _spriteBatch.Begin(SpriteSortMode.Immediate, null, null, graphicsDevice.DepthStencilState, RasterizerState.CullNone, _textEffect);
            if (text != null)
              _spriteBatch.DrawString(font, text, Vector2.Zero, color, 0, origin, scale, SpriteEffects.None, 0);
            else
              _spriteBatch.DrawString(font, stringBuilder, Vector2.Zero, color, 0, origin, scale, SpriteEffects.None, 0);

            _spriteBatch.End();
              }

              savedRenderStates.Restore();
        }
Example #24
0
        private void DrawText(int index, int endIndex, RenderContext context)
        {
            var graphicsDevice    = context.GraphicsService.GraphicsDevice;
            var savedRenderStates = new RenderStateSnapshot(graphicsDevice);

            // The sprite batch and text effect are only created when needed.
            if (_spriteBatch == null)
            {
                _spriteBatch = context.GraphicsService.GetSpriteBatch();
                _textEffect  = new BasicEffect(graphicsDevice)
                {
                    TextureEnabled     = true,
                    VertexColorEnabled = true,
                };
            }

            _textEffect.View       = (Matrix)context.CameraNode.View;
            _textEffect.Projection = context.CameraNode.Camera.Projection;

            var jobs = _jobs.Array;

            while (index < endIndex)
            {
                var node = jobs[index++].Node as BillboardNode;
                if (node == null)
                {
                    continue;
                }

                var billboard = node.Billboard as TextBillboard;
                if (billboard == null)
                {
                    continue;
                }

                var font = billboard.Font ?? _defaultFont;
                if (font == null)
                {
                    continue;
                }

                var text          = billboard.Text as string;
                var stringBuilder = billboard.Text as StringBuilder;
                if (string.IsNullOrEmpty(text) && (stringBuilder == null || stringBuilder.Length == 0))
                {
                    continue;
                }

                Vector3 position    = node.PoseWorld.Position;
                var     orientation = billboard.Orientation;



                // (Code copied from BillboardBatchReach.)

                // Normal
                Vector3 normal;
                if (orientation.Normal == BillboardNormal.ViewPlaneAligned)
                {
                    normal = _defaultNormal;
                }
                else if (orientation.Normal == BillboardNormal.ViewpointOriented)
                {
                    Vector3 n = _cameraPose.Position - position;
                    normal = n.TryNormalize() ? n : _defaultNormal;
                }
                else
                {
                    normal = node.Normal;
                }

                // Axis = up vector
                Vector3 axis = node.Axis;
                if (orientation.IsAxisInViewSpace)
                {
                    axis = _cameraPose.ToWorldDirection(axis);
                }

                if (1 - Vector3.Dot(normal, axis) < Numeric.EpsilonF)
                {
                    // Normal and axis are parallel.
                    // --> Bend normal by adding a fraction of the camera down vector.
                    Vector3 cameraDown = -_cameraPose.Orientation.GetColumn(1);
                    normal += cameraDown * 0.001f;
                    normal.Normalize();
                }

                // Compute right.
                //Vector3 right = Vector3.Cross(axis, normal);
                // Inlined:
                Vector3 right;
                right.X = axis.Y * normal.Z - axis.Z * normal.Y;
                right.Y = axis.Z * normal.X - axis.X * normal.Z;
                right.Z = axis.X * normal.Y - axis.Y * normal.X;
                if (!right.TryNormalize())
                {
                    right = normal.Orthonormal1; // Normal and axis are parallel --> Choose random perpendicular vector.
                }
                if (orientation.IsAxisFixed)
                {
                    // Make sure normal is perpendicular to right and up.
                    //normal = Vector3.Cross(right, axis);
                    // Inlined:
                    normal.X = right.Y * axis.Z - right.Z * axis.Y;
                    normal.Y = right.Z * axis.X - right.X * axis.Z;
                    normal.Z = right.X * axis.Y - right.Y * axis.X;

                    // No need to normalize because right and up are normalized and perpendicular.
                }
                else
                {
                    // Make sure axis is perpendicular to normal and right.
                    //axis = Vector3.Cross(normal, right);
                    // Inlined:
                    axis.X = normal.Y * right.Z - normal.Z * right.Y;
                    axis.Y = normal.Z * right.X - normal.X * right.Z;
                    axis.Z = normal.X * right.Y - normal.Y * right.X;

                    // No need to normalize because normal and right are normalized and perpendicular.
                }


                _textEffect.World = new Matrix(right.X, right.Y, right.Z, 0,
                                               -axis.X, -axis.Y, -axis.Z, 0,
                                               normal.X, normal.Y, normal.Z, 0,
                                               position.X, position.Y, position.Z, 1);

                Vector3 color3F = node.Color * billboard.Color;
                float   alpha   = node.Alpha * billboard.Alpha;
                Color   color   = new Color(color3F.X * alpha,
                                            color3F.Y * alpha,
                                            color3F.Z * alpha,
                                            alpha);

                Vector2 size   = (text != null) ? font.MeasureString(text) : font.MeasureString(stringBuilder);
                Vector2 origin = size / 2;
                float   scale  = node.ScaleWorld.Y; // Assume uniform scale.

                _spriteBatch.Begin(SpriteSortMode.Immediate, null, null, graphicsDevice.DepthStencilState, RasterizerState.CullNone, _textEffect);
                if (text != null)
                {
                    _spriteBatch.DrawString(font, text, Vector2.Zero, color, 0, origin, scale, SpriteEffects.None, 0);
                }
                else
                {
                    _spriteBatch.DrawString(font, stringBuilder, Vector2.Zero, color, 0, origin, scale, SpriteEffects.None, 0);
                }

                _spriteBatch.End();
            }

            savedRenderStates.Restore();
        }
Example #25
0
        /// <summary>
        /// Draws the texts.
        /// </summary>
        /// <param name="context">The render context.</param>
        /// <remarks>
        /// If <see cref="SpriteBatch"/> or <see cref="SpriteFont"/> are <see langword="null"/>, then 
        /// <see cref="Render"/> does nothing.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="context"/> is <see langword="null"/>.
        /// </exception>
        public void Render(RenderContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              if (SpriteBatch == null || SpriteFont == null)
            return;

              context.Validate(SpriteBatch);

              if (_texts2D.Count == 0 && _texts3D.Count == 0)
            return;

              if (_texts3D.Count > 0)
            context.ThrowIfCameraMissing();

              var savedRenderState = new RenderStateSnapshot(SpriteBatch.GraphicsDevice);

              if (EnableDepthTest)
              {
            SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
              }
              else
              {
            SpriteBatch.Begin();
              }

              // ----- Draw world space text.
              if (_texts3D.Count > 0)
              {
            CameraNode cameraNode = context.CameraNode;
            Matrix44F viewProjection = cameraNode.Camera.Projection * cameraNode.View;
            Viewport viewport = SpriteBatch.GraphicsDevice.Viewport;

            foreach (var textInfo in _texts3D)
            {
              // Transform position from world space to the viewport.
              Vector3F pos = viewport.ProjectToViewport(textInfo.Position, viewProjection);
              if (pos.Z < 0 || pos.Z > 1)
            continue;

              // Snap to pixels. Also add a small bias in one direction because when we draw text at
              // certain positions (e.g. view space origin) and the presentation target width is an
              // odd number, the pos will be exactly at pixel centers and due to numerical errors it
              // would jitter between pixels if the camera moves slightly.
              pos.X = (float)Math.Round(pos.X + 0.01f);
              pos.Y = (float)Math.Round(pos.Y + 0.01f);

              var textAsString = textInfo.Text as string;
              if (!string.IsNullOrEmpty(textAsString))
              {
            var textOrigin = GetOrigin(textAsString, textInfo.RelativeOrigin);
            SpriteBatch.DrawString(SpriteFont, textAsString, new Vector2(pos.X, pos.Y), textInfo.Color, 0, textOrigin, 1.0f, SpriteEffects.None, pos.Z);
              }
              else
              {
            var textAsStringBuilder = textInfo.Text as StringBuilder;
            if (textAsStringBuilder != null && textAsStringBuilder.Length > 0)
            {
              var textOrigin = GetOrigin(textAsStringBuilder, textInfo.RelativeOrigin);
              SpriteBatch.DrawString(SpriteFont, textAsStringBuilder, new Vector2(pos.X, pos.Y), textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, pos.Z);
            }
              }
            }
              }

              // ----- Draw screen space text.
              foreach (var textInfo in _texts2D)
              {
            var textAsString = textInfo.Text as string;
            if (!string.IsNullOrEmpty(textAsString))
            {
              var textOrigin = GetOrigin(textAsString, textInfo.RelativeOrigin);
              SpriteBatch.DrawString(SpriteFont, textAsString, (Vector2)textInfo.Position, textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, 0);
            }
            else
            {
              var textAsStringBuilder = textInfo.Text as StringBuilder;
              if (textAsStringBuilder != null && textAsStringBuilder.Length > 0)
              {
            var textOrigin = GetOrigin(textAsStringBuilder, textInfo.RelativeOrigin);
            SpriteBatch.DrawString(SpriteFont, textAsStringBuilder, (Vector2)textInfo.Position, textInfo.Color, 0, textOrigin, 1, SpriteEffects.None, 0);
              }
            }
              }

              SpriteBatch.End();

              savedRenderState.Restore();
        }
Example #26
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.BlendState        = BlendState.AlphaBlend;

            // Camera properties
            var    cameraNode = context.CameraNode;
            Pose   cameraPose = cameraNode.PoseWorld;
            Matrix view       = (Matrix) new Matrix44F(cameraPose.Orientation.Transposed, new Vector3F(0));
            Matrix projection = cameraNode.Camera.Projection;

            _effectParameterViewProjection.SetValue(view * projection);

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as SkyObjectNode;
                if (node == null)
                {
                    continue;
                }

                // SkyObjectNode is visible in current frame.
                node.LastFrame = frame;

                // Get billboard axes from scene node pose.
                Matrix33F orientation = node.PoseWorld.Orientation;
                Vector3F  right       = orientation.GetColumn(0);
                Vector3F  up          = orientation.GetColumn(1);
                Vector3F  normal      = orientation.GetColumn(2);
                Vector3F  forward     = -normal;

                _effectParameterNormal.SetValue((Vector3)(normal));

                // ----- Render object texture.
                var texture = node.Texture;
                if (texture != null)
                {
                    _effectParameterUp.SetValue((Vector3)(up));
                    _effectParameterRight.SetValue((Vector3)(right));
                    _effectParameterSunLight.SetValue((Vector3)node.SunLight);
                    _effectParameterAmbientLight.SetValue(new Vector4((Vector3)node.AmbientLight, node.Alpha));
                    _effectParameterObjectTexture.SetValue(texture.TextureAtlas);
                    _effectParameterLightWrapSmoothness.SetValue(new Vector2(node.LightWrap, node.LightSmoothness));
                    _effectParameterSunDirection.SetValue((Vector3)node.SunDirection);

                    float halfWidthX = (float)Math.Tan(node.AngularDiameter.X / 2);
                    float halfWidthY = (float)Math.Tan(node.AngularDiameter.Y / 2);

                    // Texture coordinates of packed texture.
                    Vector2F texCoordLeftTop     = texture.GetTextureCoordinates(new Vector2F(0, 0), 0);
                    Vector2F texCoordRightBottom = texture.GetTextureCoordinates(new Vector2F(1, 1), 0);
                    float    texCoordLeft        = texCoordLeftTop.X;
                    float    texCoordTop         = texCoordLeftTop.Y;
                    float    texCoordRight       = texCoordRightBottom.X;
                    float    texCoordBottom      = texCoordRightBottom.Y;

                    _effectParameterTextureParameters.SetValue(new Vector4(
                                                                   (texCoordLeft + texCoordRight) / 2,
                                                                   (texCoordTop + texCoordBottom) / 2,
                                                                   1 / ((texCoordRight - texCoordLeft) / 2), // 1 / half extent
                                                                   1 / ((texCoordBottom - texCoordTop) / 2)));

                    _vertices[0].Position          = (Vector3)(forward - right * halfWidthX - up * halfWidthY);
                    _vertices[0].TextureCoordinate = new Vector2(texCoordLeft, texCoordBottom);
                    _vertices[1].Position          = (Vector3)(forward - right * halfWidthX + up * halfWidthY);
                    _vertices[1].TextureCoordinate = new Vector2(texCoordLeft, texCoordTop);
                    _vertices[2].Position          = (Vector3)(forward + right * halfWidthX - up * halfWidthY);
                    _vertices[2].TextureCoordinate = new Vector2(texCoordRight, texCoordBottom);
                    _vertices[3].Position          = (Vector3)(forward + right * halfWidthX + up * halfWidthY);
                    _vertices[3].TextureCoordinate = new Vector2(texCoordRight, texCoordTop);

                    if (context.IsHdrEnabled())
                    {
                        _effectPassObjectLinear.Apply();
                    }
                    else
                    {
                        _effectPassObjectGamma.Apply();
                    }

                    graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
                }

                // ----- Render glows.
                if (node.GlowColor0.LengthSquared > 0 || node.GlowColor1.LengthSquared > 0)
                {
                    _effectParameterGlow0.SetValue(new Vector4((Vector3)node.GlowColor0, node.GlowExponent0));
                    _effectParameterGlow1.SetValue(new Vector4((Vector3)node.GlowColor1, node.GlowExponent1));

                    float halfWidth0 = (float)Math.Tan(Math.Acos(Math.Pow(node.GlowCutoffThreshold / node.GlowColor0.LargestComponent, 1 / node.GlowExponent0)));
                    if (!Numeric.IsPositiveFinite(halfWidth0))
                    {
                        halfWidth0 = 0;
                    }
                    float halfWidth1 = (float)Math.Tan(Math.Acos(Math.Pow(node.GlowCutoffThreshold / node.GlowColor1.LargestComponent, 1 / node.GlowExponent1)));
                    if (!Numeric.IsPositiveFinite(halfWidth1))
                    {
                        halfWidth1 = 0;
                    }
                    float halfWidth = Math.Max(halfWidth0, halfWidth1);

                    _vertices[0].Position          = (Vector3)(forward - right * halfWidth - up * halfWidth);
                    _vertices[0].TextureCoordinate = (Vector2) new Vector2F(0, 1);
                    _vertices[1].Position          = (Vector3)(forward - right * halfWidth + up * halfWidth);
                    _vertices[1].TextureCoordinate = (Vector2) new Vector2F(0, 0);
                    _vertices[2].Position          = (Vector3)(forward + right * halfWidth - up * halfWidth);
                    _vertices[2].TextureCoordinate = (Vector2) new Vector2F(1, 1);
                    _vertices[3].Position          = (Vector3)(forward + right * halfWidth + up * halfWidth);
                    _vertices[3].TextureCoordinate = (Vector2) new Vector2F(1, 0);

                    if (context.IsHdrEnabled())
                    {
                        _effectPassGlowLinear.Apply();
                    }
                    else
                    {
                        _effectPassGlowGamma.Apply();
                    }

                    graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
                }
            }

            savedRenderState.Restore();
        }
Example #27
0
        private void RenderHiDef(SkyboxNode node, RenderContext context)
        {
            var graphicsDevice = context.GraphicsService.GraphicsDevice;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
              graphicsDevice.BlendState = node.EnableAlphaBlending ? BlendState.AlphaBlend : BlendState.Opaque;

              bool sourceIsFloatingPoint = TextureHelper.IsFloatingPointFormat(node.Texture.Format);

              // Set sampler state. (Floating-point textures cannot use linear filtering. (XNA would throw an exception.))
              if (sourceIsFloatingPoint)
            graphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
              else
            graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;

              var cameraNode = context.CameraNode;
              Matrix44F view = cameraNode.View;
              Matrix44F projection = cameraNode.Camera.Projection;

              // Cube maps are left handed --> Sample with inverted z. (Otherwise, the
              // cube map and objects or texts in it are mirrored.)
              var mirrorZ = Matrix44F.CreateScale(1, 1, -1);
              Matrix33F orientation = node.PoseWorld.Orientation;
              _parameterWorldViewProjection.SetValue((Matrix)(projection * view * new Matrix44F(orientation, Vector3F.Zero) * mirrorZ));

              Vector4 color = node.EnableAlphaBlending
                      ? new Vector4((Vector3)node.Color * node.Alpha, node.Alpha) // Premultiplied
                      : new Vector4((Vector3)node.Color, 1);                      // Opaque
              _parameterColor.SetValue(color);
              _textureParameter.SetValue(node.Texture);

              if (node.Encoding is RgbEncoding)
              {
            _parameterTextureSize.SetValue(node.Texture.Size);
            if (context.IsHdrEnabled())
              _passRgbToRgb.Apply();
            else
              _passRgbToSRgb.Apply();
              }
              else if (node.Encoding is SRgbEncoding)
              {
            if (!sourceIsFloatingPoint)
            {
              if (context.IsHdrEnabled())
            _passSRgbToRgb.Apply();
              else
            _passSRgbToSRgb.Apply();
            }
            else
            {
              throw new GraphicsException("sRGB encoded skybox cube maps must not use a floating point format.");
            }
              }
              else if (node.Encoding is RgbmEncoding)
              {
            float max = GraphicsHelper.ToGamma(((RgbmEncoding)node.Encoding).Max);
            _parameterRgbmMaxValue.SetValue(max);

            if (context.IsHdrEnabled())
              _passRgbmToRgb.Apply();
            else
              _passRgbmToSRgb.Apply();
              }
              else
              {
            throw new NotSupportedException("The SkyBoxRenderer supports only RgbEncoding, SRgbEncoding and RgbmEncoding.");
              }

              _submesh.Draw();
              savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;

            // Set camera properties.
            var    cameraNode  = context.CameraNode;
            var    cameraPose  = cameraNode.PoseWorld;
            Matrix viewInverse = cameraPose;

            _parameterViewInverse.SetValue(viewInverse);
            _parameterGBuffer0.SetValue(context.GBuffer0);

            Viewport viewport = context.Viewport;

            _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

            // Set jitter map.
            if (_jitterMap == null)
            {
                _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);
            }

            _parameterJitterMap.SetValue(_jitterMap);

            float cameraFar = context.CameraNode.Camera.Projection.Far;

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var shadow = lightNode.Shadow as CascadedShadow;
                if (shadow == null)
                {
                    continue;
                }

                if (shadow.ShadowMap == null || shadow.ShadowMask == null)
                {
                    continue;
                }

                // The effect must only render in a specific channel.
                // Do not change blend state if the correct write channels is already set, e.g. if this
                // shadow is part of a CompositeShadow, the correct blend state is already set.
                if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
                {
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];
                }

                _parameterParameters1.SetValue(new Vector4(
                                                   shadow.FadeOutRange,
                                                   shadow.Distances[shadow.NumberOfCascades - 1],
                                                   shadow.VisualizeCascades ? 1 : 0,
                                                   shadow.ShadowFog));

                float filterRadius = shadow.FilterRadius;

                // If we use a subset of the Poisson kernel, we have to normalize the scale.
                int numberOfSamples = Math.Min(shadow.NumberOfSamples, StandardShadowMaskRenderer.PoissonKernel.Length);

                // Not all shader passes support cascade visualization. Use a similar pass instead.
                if (shadow.VisualizeCascades)
                {
                    if (numberOfSamples < 0)
                    {
                        numberOfSamples = 4;
                    }
                    else if (numberOfSamples == 0)
                    {
                        numberOfSamples = 1;
                        filterRadius    = 0;
                    }
                }

                // The best dithered CSM supports max 22 samples.
                if (shadow.CascadeSelection == ShadowCascadeSelection.BestDithered && numberOfSamples > 22)
                {
                    numberOfSamples = 22;
                }

                if (numberOfSamples > 0)
                {
                    filterRadius /= StandardShadowMaskRenderer.PoissonKernel[numberOfSamples - 1].Length();
                }

                _parameterParameters2.SetValue(new Vector4(
                                                   shadow.ShadowMap.Width,
                                                   shadow.ShadowMap.Height,
                                                   filterRadius,
                                                   // The StandardShadow.JitterResolution is the number of texels per world unit.
                                                   // In the shader the parameter JitterResolution contains the division by the jitter map size.
                                                   shadow.JitterResolution / _jitterMap.Width));

                // Split distances.
                if (_parameterDistances != null)
                {
                    // Set not used entries to large values.
                    Vector4 distances = shadow.Distances;
                    for (int j = shadow.NumberOfCascades; j < 4; j++)
                    {
                        distances[j] = 10 * cameraFar;
                    }

                    _parameterDistances.SetValue((Vector4)distances);
                }

                Debug.Assert(shadow.ViewProjections.Length == 4);
                for (int j = 0; j < _matrices.Length; j++)
                {
                    _matrices[j] = viewInverse * shadow.ViewProjections[j];
                }

                _parameterShadowMatrices.SetValue(_matrices);

                _parameterDepthBias.SetValue((Vector4)shadow.EffectiveDepthBias);
                _parameterNormalOffset.SetValue((Vector4)shadow.EffectiveNormalOffset);

                Vector3 lightBackwardWorld = lightNode.PoseWorld.Orientation.GetColumn(2);
                _parameterLightDirection.SetValue((Vector3)cameraPose.ToLocalDirection(lightBackwardWorld));
                _parameterNumberOfCascades.SetValue(shadow.NumberOfCascades);
                _parameterShadowMap.SetValue(shadow.ShadowMap);

                var      rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                Vector2F texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                var pass = GetPass(numberOfSamples, shadow.CascadeSelection, shadow.VisualizeCascades);

                if (numberOfSamples > 0)
                {
                    if (_lastNumberOfSamples != numberOfSamples)
                    {
                        // Create an array with the first n samples and the rest set to 0.
                        _lastNumberOfSamples = numberOfSamples;
                        for (int j = 0; j < numberOfSamples; j++)
                        {
                            _samples[j].Y = StandardShadowMaskRenderer.PoissonKernel[j].Y;
                            _samples[j].X = StandardShadowMaskRenderer.PoissonKernel[j].X;
                            _samples[j].Z = 1.0f / numberOfSamples;
                        }

                        // Set the rest to zero.
                        for (int j = numberOfSamples; j < _samples.Length; j++)
                        {
                            _samples[j] = Vector3.Zero;
                        }

                        _parameterSamples.SetValue(_samples);
                    }
                    else if (i == 0)
                    {
                        // Apply offsets in the first loop.
                        _parameterSamples.SetValue(_samples);
                    }
                }

                pass.Apply();

                graphicsDevice.DrawQuad(rectangle);
            }

            _parameterGBuffer0.SetValue((Texture2D)null);
            _parameterJitterMap.SetValue((Texture2D)null);
            _parameterShadowMap.SetValue((Texture2D)null);
            savedRenderState.Restore();
        }
Example #29
0
        private void VisualizeBuffer(int level, RenderContext context, int passIndex)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var originalRenderState = new RenderStateSnapshot(graphicsDevice);

              var viewport = graphicsDevice.Viewport;
              _parameterTargetSize.SetValue(new Vector2(viewport.Width, viewport.Height));
              _parameterDebugLevel.SetValue((float)level);
              _effect.CurrentTechnique = _techniqueVisualize;
              _techniqueVisualize.Passes[passIndex].Apply();

              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              // Do not override blend state: Use current blend state.

              graphicsDevice.DrawFullScreenQuad();

              originalRenderState.Restore();
        }
Example #30
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.BlendState        = GraphicsHelper.BlendStateAdd;

            var viewport = graphicsDevice.Viewport;

            _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
            _parameterGBuffer0.SetValue(context.GBuffer0);
            _parameterGBuffer1.SetValue(context.GBuffer1);

            var    cameraNode     = context.CameraNode;
            Pose   cameraPose     = cameraNode.PoseWorld;
            Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            context.CameraNode.LastFrame = frame;

            bool isHdrEnabled = context.IsHdrEnabled();

            // Copy nodes to list and sort them by persistent IDs. This is necessary to avoid popping when
            // light probes overlap.
            _jobs.Clear();
            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var light = lightNode.Light as ImageBasedLight;
                if (light == null || light.Texture == null)
                {
                    continue;
                }

                // Build sort-ID - high values for lights which should be rendered last.
                ulong sortId = 0;

                // Render infinite lights first and others later.
                if (!(light.Shape is InfiniteShape))
                {
                    sortId += ((ulong)1 << 32); // Set high value above 32-bit range.
                }
                // Sort by priority. Lights with higher priority should be rendered last
                // (= over the other lights).
                // Shift priority (signed int) to positive range and add it.
                sortId += (ulong)((long)lightNode.Priority + int.MaxValue + 1);

                // Shift sortId and add light.Id in least significant bits.
                sortId = (sortId << 16) | (ushort)light.Id;

                // Add to list for sorting.
                _jobs.Add(new Job
                {
                    SortId    = sortId,
                    LightNode = lightNode,
                });
            }

            // Sort by ascending sort-ID value.
            _jobs.Sort(Comparer.Instance);

            numberOfNodes = _jobs.Count;
            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = _jobs[i].LightNode;
                var light     = (ImageBasedLight)lightNode.Light;

                // LightNode is visible in current frame.
                lightNode.LastFrame = frame;

                // ReSharper disable CompareOfFloatsByEqualityOperator
                bool enableDiffuse = !(Numeric.IsNaN(light.DiffuseIntensity) || (light.DiffuseIntensity == 0.0f && light.BlendMode == 0.0f));
                // ReSharper restore CompareOfFloatsByEqualityOperator

                bool enableSpecular = !Numeric.IsNaN(light.SpecularIntensity);
                if (!enableDiffuse && !enableSpecular)
                {
                    continue;
                }

                float hdrScale = isHdrEnabled ? light.HdrScale : 1;

                // We use 1x1 mipmap level for diffuse.
                // (2x2 is still okay, 4x4 already looks a bit like a specular reflection.)
                float diffuseIntensity = enableDiffuse ? light.DiffuseIntensity : 0.0f;
                _parameterParameters0.SetValue(new Vector4(
                                                   (Vector3)light.Color * diffuseIntensity * hdrScale, // DiffuseColor
                                                   Math.Max(0, light.Texture.LevelCount - 1)));        // Diffuse mip level.

                // Shader supports only RGBM.
                float rgbmMax;
                if (light.Encoding is RgbmEncoding)
                {
                    rgbmMax = GraphicsHelper.ToGamma(((RgbmEncoding)light.Encoding).Max);
                }
                else if (light.Encoding is SRgbEncoding)
                {
                    // Decoding RGBM with MaxValue 1 is equal to encoding sRGB, i.e. only
                    // gamma-to-linear is performed (assuming that the cube map alpha channel is 1).
                    rgbmMax = 1;
                }
                else
                {
                    throw new NotSupportedException(
                              "ImageBasedLight must use sRGB or RGBM encoding. Other encodings are not yet supported.");
                }

                _parameterParameters1.SetValue(new Vector4(
                                                   (Vector3)light.Color * light.SpecularIntensity * hdrScale, // SpecularColor
                                                   rgbmMax));

                // Bounding box can be a box shape or an infinite shape.
                var boundingBoxShape = lightNode.Shape as BoxShape;

                // Get extent of bounding box. For infinite shapes we simply set a large value.
                var boundingBoxExtent = boundingBoxShape != null
                              ? boundingBoxShape.Extent * lightNode.ScaleWorld
                              : new Vector3F(1e20f);

                // Falloff can only be used for box shapes but not for infinite shapes.
                float falloffRange = (boundingBoxShape != null) ? light.FalloffRange : 0;

                // AABB for localization in local space.
                // Use invalid min and max (min > max) to disable localization.
                Aabb projectionAabb = new Aabb(new Vector3F(1), new Vector3F(-1));
                if (light.EnableLocalizedReflection)
                {
                    if (light.LocalizedReflectionBox.HasValue)
                    {
                        // User defined AABB.
                        projectionAabb          = light.LocalizedReflectionBox.Value;
                        projectionAabb.Minimum *= lightNode.ScaleWorld;
                        projectionAabb.Maximum *= lightNode.ScaleWorld;
                    }
                    else if (boundingBoxShape != null)
                    {
                        // AABB is equal to the bounding box.
                        projectionAabb = new Aabb(-boundingBoxExtent / 2, boundingBoxExtent / 2);
                    }
                }

                _parameterParameters2.SetValue(new Vector4(
                                                   boundingBoxExtent.X / 2,
                                                   boundingBoxExtent.Y / 2,
                                                   boundingBoxExtent.Z / 2,
                                                   falloffRange));

                _parameterParameters3.SetValue(new Vector4(
                                                   projectionAabb.Minimum.X,
                                                   projectionAabb.Minimum.Y,
                                                   projectionAabb.Minimum.Z,
                                                   light.Texture.Size));

                _parameterParameters4.SetValue(new Vector4(
                                                   projectionAabb.Maximum.X,
                                                   projectionAabb.Maximum.Y,
                                                   projectionAabb.Maximum.Z,
                                                   light.BlendMode));

                // Precomputed value for specular reflection lookup.
                const float sqrt3 = 1.7320508075688772935274463415059f;
                _parameterPrecomputedTerm.SetValue((float)Math.Log(light.Texture.Size * sqrt3, 2.0));

                _parameterEnvironmentMap.SetValue(light.Texture);

                // Compute screen space rectangle and FrustumFarCorners.
                var rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                var texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                var texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);

                // Convert frustum far corners from view space to world space.
                for (int j = 0; j < _frustumFarCorners.Length; j++)
                {
                    _frustumFarCorners[j] = (Vector3)cameraPose.ToWorldDirection((Vector3F)_frustumFarCorners[j]);
                }

                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                EffectPass passLight = null;
                if (enableDiffuse && enableSpecular)
                {
                    passLight = _passDiffuseAndSpecularLight;
                }
                else if (enableDiffuse)
                {
                    // TODO: Can we disable writes to LightBuffer1?
                    passLight = _passDiffuseLight;
                }
                else
                {
                    // TODO: Can we disable writes to LightBuffer0?
                    passLight = _passSpecularLight;
                }

                // Simply render fullscreen quad if we do not have a clip shape or a bounding box.
                if (lightNode.Clip == null && boundingBoxShape == null)
                {
                    graphicsDevice.BlendState = BlendState.AlphaBlend;

                    // Transform matrix transforms from world space with camera as origin to
                    // local space. The lightNode.Scale is already in the other parameters and not
                    // used in Transform.
                    var pose = lightNode.PoseWorld;
                    pose.Position -= cameraPose.Position;
                    _parameterTransform.SetValue(pose.Inverse);

                    passLight.Apply();
                    graphicsDevice.DrawFullScreenQuad();
                    continue;
                }

                // ----- Render clip mesh.
                graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail;
                graphicsDevice.BlendState        = GraphicsHelper.BlendStateNoColorWrite;
                if (lightNode.Clip != null)
                {
                    // Using user-defined clip shape.
                    var data = lightNode.RenderData as LightRenderData;
                    if (data == null)
                    {
                        data = new LightRenderData();
                        lightNode.RenderData = data;
                    }

                    data.UpdateClipSubmesh(context.GraphicsService, lightNode);
                    _parameterTransform.SetValue((Matrix)data.ClipMatrix * viewProjection);
                    _passClip.Apply();
                    data.ClipSubmesh.Draw();

                    graphicsDevice.DepthStencilState = lightNode.InvertClip
            ? GraphicsHelper.DepthStencilStateStencilEqual0
            : GraphicsHelper.DepthStencilStateStencilNotEqual0;
                }
                else
                {
                    Debug.Assert(boundingBoxShape != null);

                    // Use box submesh.
                    if (_boxSubmesh == null)
                    {
                        _boxSubmesh = MeshHelper.GetBox(context.GraphicsService);
                    }

                    Matrix44F world = lightNode.PoseWorld
                                      * Matrix44F.CreateScale(lightNode.ScaleLocal * boundingBoxShape.Extent);
                    _parameterTransform.SetValue((Matrix)world * viewProjection);

                    _passClip.Apply();
                    _boxSubmesh.Draw();

                    graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateStencilNotEqual0;
                }

                graphicsDevice.BlendState = BlendState.AlphaBlend;

                {
                    // Transform matrix transforms from world space with camera as origin to
                    // local space. The lightNode.Scale is already in the other parameters and not
                    // used in Transform.
                    var pose = lightNode.PoseWorld;
                    pose.Position -= cameraPose.Position;
                    _parameterTransform.SetValue(pose.Inverse);
                }

                // ----- Render full screen quad.
                passLight.Apply();
                graphicsDevice.DrawQuad(rectangle);
            }

            savedRenderState.Restore();
            _jobs.Clear();
        }
Example #31
0
        public void Query(IList<SceneNode> nodes, RenderContext context)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              context.ThrowIfCameraMissing();

              int numberOfNodes = nodes.Count;  // Note: nodes may contain null entries!
              if (numberOfNodes == 0)
              {
            Statistics.ObjectsTotal = 0;
            Statistics.ObjectsCulled = 0;
            Statistics.ShadowCastersTotal = 0;
            Statistics.ShadowCastersCulled = 0;
            return;
              }

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var originalRenderState = new RenderStateSnapshot(graphicsDevice);

              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.BlendState = BlendState.Opaque;

              // Note: The camera parameters are set in Render().

              // ----- Query data.
              // The vertices store the AABB and the pixel address to which the results is
              // written. In MonoGame, we can simply submit the data as a point list. However,
              // XNA does not support point lists. As a workaround we can submit the data as a
              // line strip:
              // - The line strip needs to be continuous: Line strips go left-to-right at even
              //   lines and right-to-left at odd lines.
              // - According to DirectX 9 line rasterization rules, the last pixel of a line
              //   is excluded. An additional vertex needs to be appended to ensure that the
              //   last pixel is rendered.
              if (_queryData == null || _queryData.Length < numberOfNodes + 1)
              {
            // We need at least numberOfNodes + 1 vertices. We use NextPowerOf2() which
            // returns a value > numberOfNodes.
            _queryData = new OcclusionVertex[MathHelper.NextPowerOf2((uint)numberOfNodes)];
              }

              Debug.Assert(_shadowCasters.Count == 0, "List of shadow casters has not been cleared.");

              int index = 0;
              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i];
            if (node == null)
              continue;

            // Ignore empty shapes.
            if (node.Shape is EmptyShape)
            {
              nodes[i] = null;  // Cull scene node!
              continue;
            }

            if (node.CastsShadows)
              _shadowCasters.Add(node);

            // Pixel address
            _queryData[index].Pixel = ToPixelAddress(index);

            // AABB
            var aabb = node.Aabb;
            _queryData[index].Minimum = aabb.Minimum;
            _queryData[index].Maximum = aabb.Maximum;

            // Position, Scale and MaxDistance are used for distance culling.
            _queryData[index].Position = node.PoseWorld.Position;
            _queryData[index].Scale = node.ScaleWorld;
            _queryData[index].MaxDistance = node.MaxDistance;

            index++;
              }

              // Append additional vertex. (For XNA line strips.)
              {
            // Copy last vertex and increment pixel address.
            _queryData[index] = _queryData[index - 1];
            _queryData[index].Pixel = ToPixelAddress(index);
              }

              int actualNumberOfNodes = index;

              // Allocate render target storing the results.
              int numberOfQueries = _lightHzbAvailable ? actualNumberOfNodes + _shadowCasters.Count : actualNumberOfNodes;
              int desiredBufferHeight = (numberOfQueries - 1) / ResultsBufferWidth + 1;
              Debug.Assert(ResultsBufferWidth * desiredBufferHeight >= actualNumberOfNodes, "Sanity check.");
              if (_resultsBuffer == null || _resultsBuffer.Height < desiredBufferHeight)
              {
            if (_resultsBuffer != null)
              _resultsBuffer.Dispose();

            _resultsBuffer = new RenderTarget2D(graphicsDevice, ResultsBufferWidth, desiredBufferHeight, false, SurfaceFormat.Single, DepthFormat.None);
            _results = new float[ResultsBufferWidth * desiredBufferHeight];
              }

              // Set new render target before binding the _cameraHzb.
              graphicsDevice.SetRenderTarget(_resultsBuffer);

              float width = _hzbLevels[0].Width;
              float height = _hzbLevels[0].Height;
              Vector2 sourceSize = new Vector2(width, height);
              Vector2 targetSize = new Vector2(_resultsBuffer.Width, _resultsBuffer.Height);
              Vector2 texelSize = new Vector2(1.0f / _cameraHzb.Width, 1.0f / _cameraHzb.Height);
              Vector2 halfTexelSize = 0.5f * texelSize;

              _parameterClampAabbMinimum.SetValue((Vector3)_cameraAabb.Minimum);
              _parameterClampAabbMaximum.SetValue((Vector3)_cameraAabb.Maximum);
              _parameterHzbSize.SetValue(sourceSize);
              _parameterTargetSize.SetValue(targetSize);
              _parameterAtlasSize.SetValue(new Vector2(_cameraHzb.Width, _cameraHzb.Height));
              _parameterTexelOffset.SetValue(texelSize);
              _parameterHalfTexelOffset.SetValue(halfTexelSize);
              _parameterMaxLevel.SetValue((float)_hzbLevels.Length - 1);
              _parameterHzbTexture.SetValue(_cameraHzb);
              _parameterLightHzbTexture.SetValue(_lightHzb);

              _effect.CurrentTechnique = _techniqueQuery;
              _techniqueQuery.Passes[0].Apply();

            #if MONOGAME
              var primitiveType = PrimitiveType.PointList;
            #else
              var primitiveType = PrimitiveType.LineStrip;
            #endif

              graphicsDevice.DrawUserPrimitives(primitiveType, _queryData, 0, actualNumberOfNodes);

              // Query shadow casters.
              int numberOfShadowCasters = _shadowCasters.Count;
              if (_lightHzbAvailable)
              {
            int offset = actualNumberOfNodes;
            for (int i = 0; i < numberOfShadowCasters; i++)
            {
              var node = _shadowCasters[i];

              // Pixel address
              _queryData[i].Pixel = ToPixelAddress(offset + i);

              // AABB
              var aabb = node.Aabb;
              _queryData[i].Minimum = aabb.Minimum;
              _queryData[i].Maximum = aabb.Maximum;

              // Position, Scale and MaxDistance are used for distance culling.
              _queryData[i].Position = node.PoseWorld.Position;
              _queryData[i].Scale = node.ScaleWorld;
              _queryData[i].MaxDistance = node.MaxDistance;
            }

            // Append additional vertex. (For XNA line strips.)
            {
              // Copy last vertex and increment pixel address.
              _queryData[numberOfShadowCasters] = _queryData[numberOfShadowCasters - 1];
              _queryData[numberOfShadowCasters].Pixel = ToPixelAddress(offset + numberOfShadowCasters);
            }

            _parameterClampAabbMinimum.SetValue((Vector3)_lightAabb.Minimum);
            _parameterClampAabbMaximum.SetValue((Vector3)_lightAabb.Maximum);

            int passIndex = ProgressiveShadowCasterCulling ? 2 : 1;
            _techniqueQuery.Passes[passIndex].Apply();

            graphicsDevice.DrawUserPrimitives(primitiveType, _queryData, 0, numberOfShadowCasters);
              }

              // Read back results.
              graphicsDevice.SetRenderTarget(null);
              _resultsBuffer.GetData(_results);

              index = 0;
              int objectsCulled = 0;
              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i];
            if (node == null)
              continue;

            int resultIndex = ToResultsBufferIndex(index);

            float viewNormalizedDistance = _results[resultIndex];
            if (viewNormalizedDistance >= 0)
            {
              // Store view-normalized distance in SortTag.
              node.SortTag = viewNormalizedDistance;
            }
            else
            {
              // Scene node culled.
              nodes[i] = null;
              objectsCulled++;
            }

            index++;
              }

              int shadowCastersCulled = 0;
              if (_lightHzbAvailable)
              {
            int offset = actualNumberOfNodes;
            for (int i = 0; i < numberOfShadowCasters; i++)
            {
              var node = _shadowCasters[i];
              int resultIndex = ToResultsBufferIndex(offset + i);

              // ReSharper disable once CompareOfFloatsByEqualityOperator
              float viewNormalizedDistance = _results[resultIndex];
              if (_results[resultIndex] >= 0)
              {
            // Shadow caster is visible.
            node.ClearFlag(SceneNodeFlags.IsShadowCasterCulled);
            node.SortTag = viewNormalizedDistance;
              }
              else
              {
            // Shadow caster is culled.
            node.SetFlag(SceneNodeFlags.IsShadowCasterCulled);
            shadowCastersCulled++;
              }
            }
              }

              Statistics.ObjectsTotal = actualNumberOfNodes;
              Statistics.ObjectsCulled = objectsCulled;
              Statistics.ShadowCastersTotal = _shadowCasters.Count;
              Statistics.ShadowCastersCulled = shadowCastersCulled;

              _shadowCasters.Clear();

              originalRenderState.Restore();

              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
        }
Example #32
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;
            graphicsDevice.BlendState        = GraphicsHelper.BlendStateAdd;

            var viewport = graphicsDevice.Viewport;

            _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
            _parameterGBuffer0.SetValue(context.GBuffer0);
            _parameterGBuffer1.SetValue(context.GBuffer1);

            var    cameraNode     = context.CameraNode;
            var    cameraPose     = cameraNode.PoseWorld;
            Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            var isHdrEnabled = context.IsHdrEnabled();

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var light = lightNode.Light as Spotlight;
                if (light == null)
                {
                    continue;
                }

                // LightNode is visible in current frame.
                lightNode.LastFrame = frame;

                float hdrScale = isHdrEnabled ? light.HdrScale : 1;
                _parameterDiffuseColor.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
                _parameterSpecularColor.SetValue((Vector3)light.Color * light.SpecularIntensity * hdrScale);

                var lightPose = lightNode.PoseWorld;
                _parameterPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));

                var lightDirectionWorld = lightPose.ToWorldDirection(Vector3.Forward);
                _parameterLightDirection.SetValue((Vector3)lightDirectionWorld);

                _parameterRange.SetValue(light.Range);
                _parameterAttenuation.SetValue(light.Attenuation);
                _parameterCutoffAngle.SetValue(light.CutoffAngle);
                _parameterFalloffAngle.SetValue(Math.Min(light.FalloffAngle, light.CutoffAngle));

                bool hasShadow = (lightNode.Shadow != null && lightNode.Shadow.ShadowMask != null);
                if (hasShadow)
                {
                    switch (lightNode.Shadow.ShadowMaskChannel)
                    {
                    case 0: _parameterShadowMaskChannel.SetValue(new Vector4(1, 0, 0, 0)); break;

                    case 1: _parameterShadowMaskChannel.SetValue(new Vector4(0, 1, 0, 0)); break;

                    case 2: _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 1, 0)); break;

                    default: _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 0, 1)); break;
                    }

                    _parameterShadowMask.SetValue(lightNode.Shadow.ShadowMask);
                }

                bool hasTexture = (light.Texture != null);
                if (hasTexture)
                {
                    var projection = Matrix.CreatePerspectiveFieldOfView(light.CutoffAngle * 2, 1, 0.1f, 100);
                    _parameterTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * projection * (lightPose.Inverse * new Pose(cameraPose.Position))));
                    _parameterTexture.SetValue(light.Texture);
                }

                var rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                var texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                var texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);

                // Convert frustum far corners from view space to world space.
                for (int j = 0; j < _frustumFarCorners.Length; j++)
                {
                    _frustumFarCorners[j] = (Vector3)cameraPose.ToWorldDirection((Vector3)_frustumFarCorners[j]);
                }
                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                if (lightNode.Clip != null)
                {
                    var data = lightNode.RenderData as LightRenderData;
                    if (data == null)
                    {
                        data = new LightRenderData();
                        lightNode.RenderData = data;
                    }

                    data.UpdateClipSubmesh(context.GraphicsService, lightNode);

                    graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail;
                    graphicsDevice.BlendState        = GraphicsHelper.BlendStateNoColorWrite;

                    _parameterWorldViewProjection.SetValue((Matrix)data.ClipMatrix * viewProjection);
                    _passClip.Apply();
                    data.ClipSubmesh.Draw();

                    graphicsDevice.DepthStencilState = lightNode.InvertClip
            ? GraphicsHelper.DepthStencilStateStencilEqual0
            : GraphicsHelper.DepthStencilStateStencilNotEqual0;
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;
                }
                else
                {
                    graphicsDevice.DepthStencilState = DepthStencilState.None;
                }

                if (hasShadow)
                {
                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passShadowedTexturedAlpha.Apply();
                        }
                        else
                        {
                            _passShadowedTexturedRgb.Apply();
                        }
                    }
                    else
                    {
                        _passShadowed.Apply();
                    }
                }
                else
                {
                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passTexturedAlpha.Apply();
                        }
                        else
                        {
                            _passTexturedRgb.Apply();
                        }
                    }
                    else
                    {
                        _passDefault.Apply();
                    }
                }

                graphicsDevice.DrawQuad(rectangle);
            }

            savedRenderState.Restore();
        }
Example #33
0
        /// <summary>
        /// Draws the points.
        /// </summary>
        /// <param name="context">The render context.</param>
        /// <remarks>
        /// If <see cref="Effect"/> is <see langword="null"/>, then <see cref="Render"/> does nothing.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="context"/> is <see langword="null"/>.
        /// </exception>
        public void Render(RenderContext context)
        {
            if (context == null)
            throw new ArgumentNullException("context");

              if (Effect == null)
            return;

              int numberOfPoints = _points.Count;
              if (numberOfPoints <= 0)
            return;

              context.Validate(Effect);
              context.ThrowIfCameraMissing();

              // Render state.
              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.RasterizerState = RasterizerState.CullNone;

              // Reset the texture stages. If a floating point texture is set, we get exceptions
              // when a sampler with bilinear filtering is set.
              graphicsDevice.ResetTextures();

              // Effect parameters.
              Effect.Alpha = 1;
              Effect.DiffuseColor = new Vector3(1, 1, 1);
              Effect.LightingEnabled = false;
              Effect.TextureEnabled = false;
              Effect.VertexColorEnabled = true;
              Effect.World = Matrix.Identity;
              Effect.View = Matrix.Identity;
              Effect.Projection = Matrix.Identity;
              Effect.CurrentTechnique.Passes[0].Apply();

              // Get WorldViewProjection matrix.
              Matrix view = (Matrix)context.CameraNode.View;
              Matrix projection = context.CameraNode.Camera.Projection;
              Matrix wvp = Matrix.Multiply(view, projection);

              // The x and y point size relative to the viewport.
              Viewport viewport = graphicsDevice.Viewport;
              float sizeX = PointSize / viewport.Width;
              float sizeY = sizeX * viewport.Width / viewport.Height;

              // Resize buffer if necessary.
              ResizeBuffer(graphicsDevice, numberOfPoints);

              // Submit points. The loop is only needed if we have more points than can
              // be submitted with one draw call.
              var startPointIndex = 0;
              while (startPointIndex < numberOfPoints)
              {
            // Number of points in this batch.
            int pointsPerBatch = Math.Min(numberOfPoints - startPointIndex, _buffer.Length / 6);

            // Create vertices for points. All positions are directly in clip space!
            for (int i = 0; i < pointsPerBatch; i++)
            {
              var point = _points[startPointIndex + i];

              // Transform point position to clip space.
              Vector3 positionWorld = (Vector3)point.Position;
              Vector3 positionClip;
              Vector3.Transform(ref positionWorld, ref wvp, out positionClip);
              float w = (float)((double)positionWorld.X * wvp.M14 + (double)positionWorld.Y * wvp.M24 + (double)positionWorld.Z * wvp.M34 + wvp.M44);

              // Homogeneous divide.
              positionClip /= w;

              // 2 triangles create a point quad. Clip space goes from -1 to 1, therefore
              // we do not need to divide sizeX and sizeY by 2.
              Vector3 bottomLeft = positionClip + new Vector3(-sizeX, +sizeY, 0);
              Vector3 bottomRight = positionClip + new Vector3(+sizeX, +sizeY, 0);
              Vector3 topLeft = positionClip + new Vector3(-sizeX, -sizeY, 0);
              Vector3 topRight = positionClip + new Vector3(+sizeX, -sizeY, 0);
              _buffer[i * 6 + 0].Position = bottomLeft;
              _buffer[i * 6 + 0].Color = point.Color;
              _buffer[i * 6 + 1].Position = bottomRight;
              _buffer[i * 6 + 1].Color = point.Color;
              _buffer[i * 6 + 2].Position = topLeft;
              _buffer[i * 6 + 2].Color = point.Color;
              _buffer[i * 6 + 3].Position = bottomRight;
              _buffer[i * 6 + 3].Color = point.Color;
              _buffer[i * 6 + 4].Position = topRight;
              _buffer[i * 6 + 4].Color = point.Color;
              _buffer[i * 6 + 5].Position = topLeft;
              _buffer[i * 6 + 5].Color = point.Color;
            }

            // Draw triangles.
            graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, _buffer, 0, pointsPerBatch * 2);

            startPointIndex += pointsPerBatch;
              }

              savedRenderState.Restore();
        }
Example #34
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            // Camera properties
            int viewportHeight = graphicsDevice.Viewport.Height;
            var cameraNode     = context.CameraNode;
            var projection     = cameraNode.Camera.Projection;

            _parameterProjection.SetValue(projection);

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as CloudLayerNode;
                if (node == null)
                {
                    continue;
                }

                // CloudLayerNode is visible in current frame.
                node.LastFrame = frame;

                if (node.CloudMap.Texture == null)
                {
                    continue;
                }

                var sunDirection = node.SunDirection;
                _parameterSunDirection.SetValue((Vector3)sunDirection);
                _parameterSkyCurvature.SetValue(node.SkyCurvature);
                _parameterTextureMatrix.SetValue((Matrix) new Matrix(node.TextureMatrix, Vector3.Zero));

                // The sample at the pixel counts as one, the rest are for the blur.
                // Note: We must not set -1 because a for loop like
                //   for (int i = 0; i < -1, i++)
                // crashes the AMD DX9 WP8.1 graphics driver. LOL
                _parameterNumberOfSamples.SetValue(Math.Max(0, node.NumberOfSamples - 1));

                _parameterSampleDistance.SetValue(node.SampleDistance);
                _parameterScatterParameters.SetValue(new Vector3(node.ForwardScatterExponent, node.ForwardScatterScale, node.ForwardScatterOffset));
                _parameterHorizonFade.SetValue(new Vector2(node.HorizonFade, node.HorizonBias));
                _parameterSunLight.SetValue((Vector3)node.SunLight);
                _parameterAmbientLight.SetValue(new Vector4((Vector3)node.AmbientLight, node.Alpha));
                _parameterTexture.SetValue(node.CloudMap.Texture);

                // Occlusion query.
                if (graphicsDevice.GraphicsProfile != GraphicsProfile.Reach && node.SunQuerySize >= Numeric.EpsilonF)
                {
                    bool skipQuery = false;
                    if (node.OcclusionQuery != null)
                    {
                        if (node.OcclusionQuery.IsComplete)
                        {
                            node.TryUpdateSunOcclusion();
                        }
                        else
                        {
                            // The previous query is still not finished. Do not start a new query, this would
                            // create a SharpDX warning.
                            skipQuery = true;
                        }
                    }
                    else
                    {
                        node.OcclusionQuery = new OcclusionQuery(graphicsDevice);
                    }

                    if (!skipQuery)
                    {
                        node.IsQueryPending = true;

                        float totalPixels = viewportHeight * node.SunQuerySize;
                        totalPixels   *= totalPixels;
                        node.QuerySize = totalPixels;

                        // Use a camera which looks at the sun.
                        // Get an relative up vector which is not parallel to the forward direction.
                        var lookAtUp = Vector3.UnitY;
                        if (Vector3.AreNumericallyEqual(sunDirection, lookAtUp))
                        {
                            lookAtUp = Vector3.UnitZ;
                        }

                        Vector3 zAxis = -sunDirection;
                        Vector3 xAxis = Vector3.Cross(lookAtUp, zAxis).Normalized;
                        Vector3 yAxis = Vector3.Cross(zAxis, xAxis);

                        var lookAtSunView = new Matrix(xAxis.X, yAxis.X, zAxis.X, 0,
                                                       xAxis.Y, yAxis.Y, zAxis.Y, 0,
                                                       xAxis.Z, yAxis.Z, zAxis.Z, 0,
                                                       0, 0, 0, 1);
                        _parameterView.SetValue(lookAtSunView);

                        graphicsDevice.BlendState        = GraphicsHelper.BlendStateNoColorWrite;
                        graphicsDevice.DepthStencilState = DepthStencilState.None;
                        graphicsDevice.RasterizerState   = RasterizerState.CullNone;

                        // Create small quad shortly behind the near plane.
                        // Note: We use an "untranslated" view matrix, so we can ignore the camera position.
                        float   width  = (projection.Top - projection.Bottom) * node.SunQuerySize;
                        Vector3 right  = sunDirection.Orthonormal1 * (width / 2);
                        Vector3 up     = sunDirection.Orthonormal2 * (width / 2);
                        Vector3 center = sunDirection * (projection.Near * 1.0001f);
                        _queryGeometry[0] = center - up - right;
                        _queryGeometry[1] = center + up - right;
                        _queryGeometry[2] = center - up + right;
                        _queryGeometry[3] = center + up + right;

                        if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passOcclusionAlpha.Apply();
                        }
                        else
                        {
                            _passOcclusionRgb.Apply();
                        }

                        node.OcclusionQuery.Begin();
                        graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _queryGeometry, 0, 2,
                                                          VertexPosition.VertexDeclaration);
                        node.OcclusionQuery.End();
                    }
                }
                else
                {
                    node.IsQueryPending = false;
                    node.SunOcclusion   = 0;
                }

                Matrix viewUntranslated = (Matrix) new Matrix(cameraNode.PoseWorld.Orientation.Transposed, new Vector3(0));
                _parameterView.SetValue(viewUntranslated);

                // Render clouds.
                graphicsDevice.BlendState        = BlendState.AlphaBlend;
                graphicsDevice.RasterizerState   = RasterizerState.CullNone;
                graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

                if (context.IsHdrEnabled())
                {
                    if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
                    {
                        _passCloudAlphaLinear.Apply();
                    }
                    else
                    {
                        _passCloudRgbLinear.Apply();
                    }
                }
                else
                {
                    if (node.CloudMap.Texture.Format == SurfaceFormat.Alpha8)
                    {
                        _passCloudAlphaGamma.Apply();
                    }
                    else
                    {
                        _passCloudRgbGamma.Apply();
                    }
                }

                _submesh.Draw();
            }

            savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              // Note: The camera node is not used by the StandardShadowMapRenderer.
              // Still throw an exception if null for consistency. (All other shadow map
              // renderers need a camera node.)
              context.ThrowIfCameraMissing();
              context.ThrowIfSceneMissing();

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;
              var originalReferenceNode = context.ReferenceNode;

              var cameraNode = context.CameraNode;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              context.Technique = "Default";

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var shadow = lightNode.Shadow as StandardShadow;
            if (shadow == null)
              continue;

            // LightNode is visible in current frame.
            lightNode.LastFrame = frame;

            // Get a new shadow map if necessary.
            if (shadow.ShadowMap == null)
            {
              shadow.ShadowMap = graphicsService.RenderTargetPool.Obtain2D(
            new RenderTargetFormat(
              shadow.PreferredSize,
              shadow.PreferredSize,
              false,
              shadow.Prefer16Bit ? SurfaceFormat.HalfSingle : SurfaceFormat.Single,
              DepthFormat.Depth24));
            }

            // Create a suitable shadow camera.
            CameraNode lightCameraNode;
            if (lightNode.Light is ProjectorLight)
            {
              var light = (ProjectorLight)lightNode.Light;
              if (light.Projection is PerspectiveProjection)
              {
            var lp = (PerspectiveProjection)light.Projection;
            var cp = (PerspectiveProjection)_perspectiveCameraNode.Camera.Projection;
            cp.SetOffCenter(lp.Left, lp.Right, lp.Bottom, lp.Top, lp.Near, lp.Far);

            lightCameraNode = _perspectiveCameraNode;
              }
              else //if (light.Projection is OrthographicProjection)
              {
            var lp = (OrthographicProjection)light.Projection;
            var cp = (OrthographicProjection)_orthographicCameraNode.Camera.Projection;
            cp.SetOffCenter(lp.Left, lp.Right, lp.Bottom, lp.Top, lp.Near, lp.Far);

            lightCameraNode = _orthographicCameraNode;
              }
            }
            else if (lightNode.Light is Spotlight)
            {
              var light = (Spotlight)lightNode.Light;
              var cp = (PerspectiveProjection)_perspectiveCameraNode.Camera.Projection;
              cp.SetFieldOfView(2 * light.CutoffAngle, 1, shadow.DefaultNear, light.Range);

              lightCameraNode = _perspectiveCameraNode;
            }
            else
            {
              throw new GraphicsException("StandardShadow can only be used with a Spotlight or a ProjectorLight.");
            }

            lightCameraNode.PoseWorld = lightNode.PoseWorld;

            // Store data for use in StandardShadowMaskRenderer.
            shadow.Near = lightCameraNode.Camera.Projection.Near;
            shadow.Far = lightCameraNode.Camera.Projection.Far;
            shadow.View = lightCameraNode.PoseWorld.Inverse;
            shadow.Projection = lightCameraNode.Camera.Projection;

            // World units per texel at a planar distance of 1 world unit.
            float unitsPerTexel = lightCameraNode.Camera.Projection.Width / (shadow.ShadowMap.Height * shadow.Near);

            // Convert depth bias from "texel" to world space.
            // Minus to move receiver depth closer to light.
            shadow.EffectiveDepthBias = -shadow.DepthBias * unitsPerTexel;

            // Convert normal offset from "texel" to world space.
            shadow.EffectiveNormalOffset = shadow.NormalOffset * unitsPerTexel;

            graphicsDevice.SetRenderTarget(shadow.ShadowMap);
            context.RenderTarget = shadow.ShadowMap;
            context.Viewport = graphicsDevice.Viewport;

            graphicsDevice.Clear(Color.White);

            // The scene node renderer should use the light camera instead of the player camera.
            context.CameraNode = lightCameraNode;
            context.ReferenceNode = lightNode;
            context.Object = shadow;

            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState = BlendState.Opaque;

            bool shadowMapContainsSomething = RenderCallback(context);
            if (!shadowMapContainsSomething)
            {
              // Shadow map is empty. Recycle it.
              graphicsService.RenderTargetPool.Recycle(shadow.ShadowMap);
              shadow.ShadowMap = null;
            }
              }

              graphicsDevice.SetRenderTarget(null);
              savedRenderState.Restore();

              context.CameraNode = cameraNode;
              context.Technique = null;
              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
              context.ReferenceNode = originalReferenceNode;
              context.Object = null;
        }
Example #36
0
        /// <inheritdoc/>
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              context.Validate(_effect);

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              //var renderTargetPool = graphicsService.RenderTargetPool;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.BlendState = BlendState.Opaque;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.None;

              int frame = context.Frame;

              for (int nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++)
              {
            var node = nodes[nodeIndex] as WaterNode;
            if (node == null)
              continue;

            var waves = node.Waves as OceanWaves;
            if (waves == null)
              continue;

            // We update the waves only once per frame.
            if (waves.LastFrame == frame)
              continue;

            waves.LastFrame = frame;

            float time = (float)context.Time.TotalSeconds;

            // Initialize h0 spectrum. Perform CPU FFT.
            waves.Update(graphicsDevice, time);

            int n = waves.TextureSize;

            // Allocate textures in the first frame and when the TextureSize was changed.
            if (waves.DisplacementSpectrum == null || waves.DisplacementSpectrum.Width != n)
            {
              waves.DisplacementSpectrum.SafeDispose();
              waves.NormalSpectrum.SafeDispose();
              waves.DisplacementMap.SafeDispose();
              waves.NormalMap.SafeDispose();

              waves.DisplacementSpectrum = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
              waves.NormalSpectrum = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
              waves.DisplacementMap = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
              waves.NormalMap = new RenderTarget2D(
            _graphicsService.GraphicsDevice,
            n,
            n,
            true,
            SurfaceFormat.Color,
            DepthFormat.None);
            }

            // Create spectrum (h, D, N) for current time from h0.
            _renderTargetBindings[0] = new RenderTargetBinding(waves.DisplacementSpectrum);
            _renderTargetBindings[1] = new RenderTargetBinding(waves.NormalSpectrum);
            graphicsDevice.SetRenderTargets(_renderTargetBindings);
            _parameterSize.SetValue((float)n);
            _parameterSpectrumParameters.SetValue(new Vector4(
              waves.TileSize,
              waves.Gravity,
              time,
              waves.HeightScale));
            _parameterSourceTexture.SetValue(waves.H0Spectrum);
            _passSpectrum.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Do inverse FFT.
            _fft.Process(
              context,
              false,
              waves.DisplacementSpectrum,
              waves.NormalSpectrum,
              (RenderTarget2D)waves.DisplacementMap,
              (RenderTarget2D)waves.NormalMap,
              waves.Choppiness);

            #region ----- Old Debugging Code -----

            // Create textures from CPU FFT data for debug visualization.
            //n = waves.CpuSize;
            //var s0Data = new Vector4[n * n];
            //var s1Data = new Vector4[n * n];
            //var s0 = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
            //var s1 = new RenderTarget2D(_graphicsService.GraphicsDevice, n, n, false, SurfaceFormat.Vector4, DepthFormat.None);
            //for (int y = 0; y < n; y++)
            //{
            //  for (int x = 0; x < n; x++)
            //  {
            //s0Data[y * n + x] = new Vector4(
            //  -waves._D[x, y].X * waves.Choppiness,
            //  waves._h[x, y].X * 1,
            //  -waves._D[x, y].Y * waves.Choppiness,
            //  1);

            //s1Data[y * n + x] = new Vector4(
            //  waves._N[x, y].X,
            //  waves._N[x, y].Y,
            //  0,
            //  0);
            //  }
            //}
            //s0.SetData(s0Data);
            //s1.SetData(s1Data);
            //WaterSample._t0 = s0;
            //WaterSample._t1 = waves.DisplacementMap;
            #endregion
              }

              savedRenderState.Restore();
              graphicsDevice.SetRenderTarget(null);
              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;

              _renderTargetBindings[0] = default(RenderTargetBinding);
              _renderTargetBindings[1] = default(RenderTargetBinding);

              // Reset the texture stages. If a floating point texture is set, we get exceptions
              // when a sampler with bilinear filtering is set.
            #if !MONOGAME
              graphicsDevice.ResetTextures();
            #endif
        }
Example #37
0
        internal void ProcessInternal(RenderContext context)
        {
            Debug.Assert(Enabled, "PostProcessor.ProcessInternal should only be called when the post-processor is enabled.");

              var graphicsDevice = GraphicsService.GraphicsDevice;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              // Set render states. The blend state must be set by the user!
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.None;

              // Preform post-processing.
              OnProcess(context);

              savedRenderState.Restore();

              // Reset the texture stages. If a floating point texture is set, we get exceptions
            // when a sampler with bilinear filtering is set.
            #if !MONOGAME
              graphicsDevice.ResetTextures();
            #endif
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;

              var viewport = graphicsDevice.Viewport;
              _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
              _parameterGBuffer0.SetValue(context.GBuffer0);
              _parameterGBuffer1.SetValue(context.GBuffer1);

              var cameraNode = context.CameraNode;
              Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              var isHdrEnabled = context.IsHdrEnabled();

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var light = lightNode.Light as AmbientLight;
            if (light == null)
              continue;

            // LightNode is visible in current frame.
            lightNode.LastFrame = frame;

            float hdrScale = isHdrEnabled ? light.HdrScale : 1;
            _parameterLightColor.SetValue((Vector3)light.Color * light.Intensity * hdrScale);
            _parameterHemisphericAttenuation.SetValue(light.HemisphericAttenuation);

            Vector3F upWorld = lightNode.PoseWorld.ToWorldDirection(Vector3F.Up);
            _parameterUp.SetValue((Vector3)upWorld);

            if (lightNode.Clip != null)
            {
              var data = lightNode.RenderData as LightRenderData;
              if (data == null)
              {
            data = new LightRenderData();
            lightNode.RenderData = data;
              }

              data.UpdateClipSubmesh(context.GraphicsService, lightNode);

              graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;

              _parameterWorldViewProjection.SetValue((Matrix)data.ClipMatrix * viewProjection);
              _passClip.Apply();
              data.ClipSubmesh.Draw();

              graphicsDevice.DepthStencilState = lightNode.InvertClip
            ? GraphicsHelper.DepthStencilStateStencilEqual0
            : GraphicsHelper.DepthStencilStateStencilNotEqual0;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;
            }
            else
            {
              graphicsDevice.DepthStencilState = DepthStencilState.None;
            }

            _passLight.Apply();
            graphicsDevice.DrawFullScreenQuad();
              }

              savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;

              var viewport = graphicsDevice.Viewport;
              _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));
              _parameterGBuffer0.SetValue(context.GBuffer0);
              _parameterGBuffer1.SetValue(context.GBuffer1);

              var cameraNode = context.CameraNode;
              var cameraPose = cameraNode.PoseWorld;
              Matrix viewProjection = (Matrix)cameraNode.View * cameraNode.Camera.Projection;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              var isHdrEnabled = context.IsHdrEnabled();
              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var light = lightNode.Light as ProjectorLight;
            if (light == null)
              continue;

            // LightNode is visible in current frame.
            lightNode.LastFrame = frame;

            float hdrScale = isHdrEnabled ? light.HdrScale : 1;
            _parameterDiffuseColor.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
            _parameterSpecularColor.SetValue((Vector3)light.Color * light.SpecularIntensity * hdrScale);
            _parameterTexture.SetValue(light.Texture);

            var lightPose = lightNode.PoseWorld;
            _parameterPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));

            _parameterRange.SetValue(light.Projection.Far);
            _parameterAttenuation.SetValue(light.Attenuation);
            _parameterTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * light.Projection * (lightPose.Inverse * new Pose(cameraPose.Position))));

            var rectangle = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
            var texCoordTopLeft = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
            var texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
            GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);

            // Convert frustum far corners from view space to world space.
            for (int j = 0; j < _frustumFarCorners.Length; j++)
              _frustumFarCorners[j] = (Vector3)cameraPose.ToWorldDirection((Vector3F)_frustumFarCorners[j]);

            _parameterFrustumCorners.SetValue(_frustumFarCorners);

            bool hasShadow = (lightNode.Shadow != null && lightNode.Shadow.ShadowMask != null);
            if (hasShadow)
            {
              switch (lightNode.Shadow.ShadowMaskChannel)
              {
            case 0: _parameterShadowMaskChannel.SetValue(new Vector4(1, 0, 0, 0)); break;
            case 1: _parameterShadowMaskChannel.SetValue(new Vector4(0, 1, 0, 0)); break;
            case 2: _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 1, 0)); break;
            default: _parameterShadowMaskChannel.SetValue(new Vector4(0, 0, 0, 1)); break;
              }

              _parameterShadowMask.SetValue(lightNode.Shadow.ShadowMask);
            }

            if (lightNode.Clip != null)
            {
              var data = lightNode.RenderData as LightRenderData;
              if (data == null)
              {
            data = new LightRenderData();
            lightNode.RenderData = data;
              }

              data.UpdateClipSubmesh(context.GraphicsService, lightNode);

              graphicsDevice.DepthStencilState = GraphicsHelper.DepthStencilStateOnePassStencilFail;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateNoColorWrite;

              _parameterWorldViewProjection.SetValue((Matrix)data.ClipMatrix * viewProjection);
              _passClip.Apply();
              data.ClipSubmesh.Draw();

              graphicsDevice.DepthStencilState = lightNode.InvertClip
            ? GraphicsHelper.DepthStencilStateStencilEqual0
            : GraphicsHelper.DepthStencilStateStencilNotEqual0;
              graphicsDevice.BlendState = GraphicsHelper.BlendStateAdd;
            }
            else
            {
              graphicsDevice.DepthStencilState = DepthStencilState.None;
            }

            if (hasShadow)
            {
              if (light.Texture.Format == SurfaceFormat.Alpha8)
            _passShadowedAlpha.Apply();
              else
            _passShadowedRgb.Apply();
            }
            else
            {
              if (light.Texture.Format == SurfaceFormat.Alpha8)
            _passDefaultAlpha.Apply();
              else
            _passDefaultRgb.Apply();
            }

            graphicsDevice.DrawQuad(rectangle);
              }

              savedRenderState.Restore();
        }
Example #40
0
        // Perform FFTs.
        // 4 complex input images: source0.xy, source0.zw, source1.xy, source1.zw
        // 2 targets: target0 = displacement map, target1 = normal map using Color format.
        public void Process(RenderContext context, bool forward, Texture2D source0, Texture2D source1, RenderTarget2D target0, RenderTarget2D target1, float choppiness)
        {
            if (context == null)
            throw new ArgumentNullException("context");
              if (source0 == null)
            throw new ArgumentNullException("source0");
              if (source1 == null)
            throw new ArgumentNullException("source1");

              if (forward)
              {
            // For forward FFT, uncomment the LastPassScale stuff!
            throw new NotImplementedException("Forward FFT not implemented.");
              }

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var renderTargetPool = graphicsService.RenderTargetPool;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              graphicsDevice.BlendState = BlendState.Opaque;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;
              graphicsDevice.DepthStencilState = DepthStencilState.None;

              int size = source0.Width;
              _parameterSize.SetValue((float)size);

              _parameterChoppiness.SetValue(choppiness);

              int numberOfButterflyPasses = (int)MathHelper.Log2GreaterOrEqual((uint)source0.Width);
              // ReSharper disable once ConditionIsAlwaysTrueOrFalse
              _parameterButterflyTexture.SetValue(GetButterflyTexture(forward, numberOfButterflyPasses));

              var format = new RenderTargetFormat(size, size, false, source0.Format, DepthFormat.None);
              var tempPing0 = renderTargetPool.Obtain2D(format);
              var tempPing1 = renderTargetPool.Obtain2D(format);
              var tempPong0 = renderTargetPool.Obtain2D(format);
              var tempPong1 = renderTargetPool.Obtain2D(format);

              //_parameterIsLastPass.SetValue(false);

              // Perform horizontal and vertical FFT pass.
              for (int i = 0; i < 2; i++)
              {
            //_parameterLastPassScale.SetValue(1);

            // Perform butterfly passes. We ping-pong between two temp targets.
            for (int pass = 0; pass < numberOfButterflyPasses; pass++)
            {
              _parameterButterflyIndex.SetValue(0.5f / numberOfButterflyPasses + (float)pass / numberOfButterflyPasses);

              if (i == 0 && pass == 0)
              {
            // First pass.
            _renderTargetBindings[0] = new RenderTargetBinding(tempPing0);
            _renderTargetBindings[1] = new RenderTargetBinding(tempPing1);
            graphicsDevice.SetRenderTargets(_renderTargetBindings);
            _parameterSourceTexture0.SetValue(source0);
            _parameterSourceTexture1.SetValue(source1);
              }
              else if (i == 1 && pass == numberOfButterflyPasses - 1)
              {
            // Last pass.
            // We have explicit shader passes for the last FFT pass.
            break;

            //_parameterIsLastPass.SetValue(true);
            //if (forward)
            //  _parameterLastPassScale.SetValue(1.0f / size / size);

            //if (_renderTargetBindings[0].RenderTarget == tempPing0)
            //{
            //  _renderTargetBindings[0] = new RenderTargetBinding(target0);
            //  _renderTargetBindings[1] = new RenderTargetBinding(target1);
            //  graphicsDevice.SetRenderTargets(_renderTargetBindings);
            //  _parameterSourceTexture0.SetValue(tempPing0);
            //  _parameterSourceTexture1.SetValue(tempPing1);
            //}
            //else
            //{
            //  _renderTargetBindings[0] = new RenderTargetBinding(target0);
            //  _renderTargetBindings[1] = new RenderTargetBinding(target1);
            //  graphicsDevice.SetRenderTargets(_renderTargetBindings);
            //  _parameterSourceTexture0.SetValue(tempPong0);
            //  _parameterSourceTexture1.SetValue(tempPong1);
            //}
              }
              else
              {
            // Intermediate pass.
            if (_renderTargetBindings[0].RenderTarget == tempPing0)
            {
              _renderTargetBindings[0] = new RenderTargetBinding(tempPong0);
              _renderTargetBindings[1] = new RenderTargetBinding(tempPong1);
              graphicsDevice.SetRenderTargets(_renderTargetBindings);
              _parameterSourceTexture0.SetValue(tempPing0);
              _parameterSourceTexture1.SetValue(tempPing1);
            }
            else
            {
              _renderTargetBindings[0] = new RenderTargetBinding(tempPing0);
              _renderTargetBindings[1] = new RenderTargetBinding(tempPing1);
              graphicsDevice.SetRenderTargets(_renderTargetBindings);
              _parameterSourceTexture0.SetValue(tempPong0);
              _parameterSourceTexture1.SetValue(tempPong1);
            }
              }

              if (i == 0)
            _passFftHorizontal.Apply();
              else
            _passFftVertical.Apply();

              graphicsDevice.DrawFullScreenQuad();
            }
              }

              // Perform final vertical FFT passes. We have to perform them separately
              // because displacement map and normal map usually have different bit depth.
              // Final pass for displacement.
              graphicsDevice.SetRenderTarget(target0);
              if (_renderTargetBindings[1].RenderTarget == tempPing1)
            _parameterSourceTexture0.SetValue(tempPing0);
              else
            _parameterSourceTexture0.SetValue(tempPong0);

              _passFftDisplacement.Apply();
              graphicsDevice.DrawFullScreenQuad();

              // Final pass for normals.
              graphicsDevice.SetRenderTarget(target1);
              if (_renderTargetBindings[1].RenderTarget == tempPing1)
            _parameterSourceTexture0.SetValue(tempPing1);
              else
            _parameterSourceTexture0.SetValue(tempPong1);

              _passFftNormal.Apply();
              graphicsDevice.DrawFullScreenQuad();

              // Clean up.
              _renderTargetBindings[0] = default(RenderTargetBinding);
              _renderTargetBindings[1] = default(RenderTargetBinding);
              _parameterButterflyTexture.SetValue((Texture2D)null);
              _parameterSourceTexture0.SetValue((Texture2D)null);
              _parameterSourceTexture1.SetValue((Texture2D)null);

              renderTargetPool.Recycle(tempPing0);
              renderTargetPool.Recycle(tempPing1);
              renderTargetPool.Recycle(tempPong0);
              renderTargetPool.Recycle(tempPong1);

              savedRenderState.Restore();

              // Reset the texture stages. If a floating point texture is set, we get exceptions
              // when a sampler with bilinear filtering is set.
            #if !MONOGAME
              graphicsDevice.ResetTextures();
            #endif
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var shadow = lightNode.Shadow as CompositeShadow;
            if (shadow == null)
              continue;

            if (shadow.ShadowMask == null)
              continue;

            // Write into a single channel and use min() blending.
            graphicsDevice.BlendState = BlendStates[shadow.ShadowMaskChannel];

            for (int j = 0; j < shadow.Shadows.Count; j++)
            {
              // Temporarily set shadow mask and shadow mask channel of child shadows.
              var childShadow = shadow.Shadows[j];
              childShadow.ShadowMask = shadow.ShadowMask;
              childShadow.ShadowMaskChannel = shadow.ShadowMaskChannel;

              // Temporarily exchange LightNode.Shadow and render the child shadow.
              lightNode.Shadow = childShadow;

              for (int k = 0; k < _shadowMaskRenderers.Count; k++)
              {
            var renderer = _shadowMaskRenderers[k];
            if (renderer.CanRender(lightNode, context))
            {
              renderer.Render(lightNode, context);
              break;
            }
              }

              // Remove shadow mask references. Strictly speaking, the mask is correct
              // for the composite shadow. It is not correct for the child shadow. The child
              // shadow only contributes to the mask. Therefore, childShadowMask should not be
              // set.
              childShadow.ShadowMask = null;
              childShadow.ShadowMaskChannel = 0;
            }

            lightNode.Shadow = shadow;
              }

              savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.ThrowIfCameraMissing();
              context.ThrowIfSceneMissing();

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;
              var originalReferenceNode = context.ReferenceNode;

              // Camera properties
              var cameraNode = context.CameraNode;
              var cameraPose = cameraNode.PoseWorld;
              var projection = cameraNode.Camera.Projection;
              if (!(projection is PerspectiveProjection))
            throw new NotImplementedException(
              "Cascaded shadow maps not yet implemented for scenes with orthographic camera.");

              float fieldOfViewY = projection.FieldOfViewY;
              float aspectRatio = projection.AspectRatio;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              // The scene node renderer should use the light camera instead of the player camera.
              context.CameraNode = _orthographicCameraNode;
              context.Technique = "Directional";

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var shadow = lightNode.Shadow as CascadedShadow;
            if (shadow == null)
              continue;

            // LightNode is visible in current frame.
            lightNode.LastFrame = frame;

            var format = new RenderTargetFormat(
              shadow.PreferredSize * shadow.NumberOfCascades,
              shadow.PreferredSize,
              false,
              shadow.Prefer16Bit ? SurfaceFormat.HalfSingle : SurfaceFormat.Single,
              DepthFormat.Depth24);

            bool allLocked = shadow.IsCascadeLocked[0] && shadow.IsCascadeLocked[1] && shadow.IsCascadeLocked[2] && shadow.IsCascadeLocked[3];

            if (shadow.ShadowMap == null)
            {
              shadow.ShadowMap = graphicsService.RenderTargetPool.Obtain2D(format);
              allLocked = false;   // Need to render shadow map.
            }

            // If we can reuse the whole shadow map texture, abort early.
            if (allLocked)
              continue;

            _csmSplitDistances[0] = projection.Near;
            _csmSplitDistances[1] = shadow.Distances.X;
            _csmSplitDistances[2] = shadow.Distances.Y;
            _csmSplitDistances[3] = shadow.Distances.Z;
            _csmSplitDistances[4] = shadow.Distances.W;

            // (Re-)Initialize the array for cached matrices in the CascadedShadow.
            if (shadow.ViewProjections == null || shadow.ViewProjections.Length < shadow.NumberOfCascades)
              shadow.ViewProjections = new Matrix[shadow.NumberOfCascades];

            // Initialize the projection matrices to an empty matrix.
            // The unused matrices should not contain valid projections because
            // CsmComputeSplitOptimized in CascadedShadowMask.fxh should not choose
            // the wrong cascade.
            for (int j = 0; j < shadow.ViewProjections.Length; j++)
            {
              if (!shadow.IsCascadeLocked[j])    // Do not delete cached info for cached cascade.
            shadow.ViewProjections[j] = new Matrix();
            }

            // If some cascades are cached, we have to create a new shadow map and copy
            // the old cascades into the new shadow map.
            if (shadow.IsCascadeLocked[0] || shadow.IsCascadeLocked[1] || shadow.IsCascadeLocked[2] || shadow.IsCascadeLocked[3])
            {
              var oldShadowMap = shadow.ShadowMap;
              shadow.ShadowMap = graphicsService.RenderTargetPool.Obtain2D(new RenderTargetFormat(oldShadowMap));

              graphicsDevice.SetRenderTarget(shadow.ShadowMap);
              graphicsDevice.Clear(Color.White);

              var spriteBatch = graphicsService.GetSpriteBatch();
              spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
              for (int cascade = 0; cascade < shadow.NumberOfCascades; cascade++)
              {
            if (shadow.IsCascadeLocked[cascade])
            {
              var viewport = GetViewport(shadow, cascade);
              var rectangle = new Rectangle(viewport.X, viewport.Y, viewport.Width, viewport.Height);
              spriteBatch.Draw(oldShadowMap, rectangle, rectangle, Color.White);
            }
              }
              spriteBatch.End();

              graphicsService.RenderTargetPool.Recycle(oldShadowMap);
            }
            else
            {
              graphicsDevice.SetRenderTarget(shadow.ShadowMap);
              graphicsDevice.Clear(Color.White);
            }

            context.RenderTarget = shadow.ShadowMap;
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState = BlendState.Opaque;

            context.ReferenceNode = lightNode;
            context.Object = shadow;
            context.ShadowNear = 0;           // Obsolete: Only kept for backward compatibility.

            bool shadowMapContainsSomething = false;
            for (int split = 0; split < shadow.NumberOfCascades; split++)
            {
              if (shadow.IsCascadeLocked[split])
            continue;

              context.Data[RenderContextKeys.ShadowTileIndex] = CubeMapShadowMapRenderer.BoxedIntegers[split];

              // near/far of this split.
              float near = _csmSplitDistances[split];
              float far = Math.Max(_csmSplitDistances[split + 1], near + Numeric.EpsilonF);

              // Create a view volume for this split.
              _splitVolume.SetFieldOfView(fieldOfViewY, aspectRatio, near, far);

              // Find the bounding sphere of the split camera frustum.
              Vector3F center;
              float radius;
              GetBoundingSphere(_splitVolume, out center, out radius);

              // Extend radius to get enough border for filtering.
              int shadowMapSize = shadow.ShadowMap.Height;

              // We could extend by (ShadowMapSize + BorderTexels) / ShadowMapSize;
              // Add at least 1 texel. (This way, shadow mask shader can clamp uv to
              // texture rect in without considering half texel border to avoid sampling outside..)
              radius *= (float)(shadowMapSize + 1) / shadowMapSize;

              // Convert center to light space.
              Pose lightPose = lightNode.PoseWorld;
              center = cameraPose.ToWorldPosition(center);
              center = lightPose.ToLocalPosition(center);

              // Snap center to texel positions to avoid shadow swimming.
              SnapPositionToTexels(ref center, 2 * radius, shadowMapSize);

              // Convert center back to world space.
              center = lightPose.ToWorldPosition(center);

              Matrix33F orientation = lightPose.Orientation;
              Vector3F backward = orientation.GetColumn(2);
              var orthographicProjection = (OrthographicProjection)_orthographicCameraNode.Camera.Projection;

              // Create a tight orthographic frustum around the cascade's bounding sphere.
              orthographicProjection.SetOffCenter(-radius, radius, -radius, radius, 0, 2 * radius);
              Vector3F cameraPosition = center + radius * backward;
              Pose frustumPose = new Pose(cameraPosition, orientation);
              Pose view = frustumPose.Inverse;
              shadow.ViewProjections[split] = (Matrix)view * orthographicProjection;

              // Convert depth bias from "texel" to light space [0, 1] depth.
              // Minus sign to move receiver depth closer to light. Divide by depth to normalize.
              float unitsPerTexel = orthographicProjection.Width / shadow.ShadowMap.Height;
              shadow.EffectiveDepthBias[split] = -shadow.DepthBias[split] * unitsPerTexel / orthographicProjection.Depth;

              // Convert normal offset from "texel" to world space.
              shadow.EffectiveNormalOffset[split] = shadow.NormalOffset[split] * unitsPerTexel;

              // For rendering the shadow map, move near plane back by MinLightDistance
              // to catch occluders in front of the cascade.
              orthographicProjection.Near = -shadow.MinLightDistance;
              _orthographicCameraNode.PoseWorld = frustumPose;

              // Set a viewport to render a tile in the texture atlas.
              graphicsDevice.Viewport = GetViewport(shadow, split);
              context.Viewport = graphicsDevice.Viewport;

              shadowMapContainsSomething |= RenderCallback(context);
            }

            // Recycle shadow map if empty.
            if (!shadowMapContainsSomething)
            {
              graphicsService.RenderTargetPool.Recycle(shadow.ShadowMap);
              shadow.ShadowMap = null;
            }
              }

              graphicsDevice.SetRenderTarget(null);
              savedRenderState.Restore();

              context.CameraNode = cameraNode;
              context.ShadowNear = float.NaN;
              context.Technique = null;
              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
              context.ReferenceNode = originalReferenceNode;
              context.Object = null;
              context.Data[RenderContextKeys.ShadowTileIndex] = null;
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;

              // Set camera properties.
              var cameraNode = context.CameraNode;
              var cameraPose = cameraNode.PoseWorld;
              Matrix viewInverse = cameraPose;
              _parameterViewInverse.SetValue(viewInverse);
              _parameterGBuffer0.SetValue(context.GBuffer0);

              Viewport viewport = context.Viewport;
              _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

              // Set jitter map.
              if (_jitterMap == null)
            _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);

              _parameterJitterMap.SetValue(_jitterMap);

              float cameraFar = context.CameraNode.Camera.Projection.Far;

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var shadow = lightNode.Shadow as CascadedShadow;
            if (shadow == null)
              continue;

            if (shadow.ShadowMap == null || shadow.ShadowMask == null)
              continue;

            // The effect must only render in a specific channel.
            // Do not change blend state if the correct write channels is already set, e.g. if this
            // shadow is part of a CompositeShadow, the correct blend state is already set.
            if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
              graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];

            _parameterParameters1.SetValue(new Vector4(
              shadow.FadeOutRange,
              shadow.Distances[shadow.NumberOfCascades - 1],
              shadow.VisualizeCascades ? 1 : 0,
              shadow.ShadowFog));

            float filterRadius = shadow.FilterRadius;

            // If we use a subset of the Poisson kernel, we have to normalize the scale.
            int numberOfSamples = Math.Min(shadow.NumberOfSamples, StandardShadowMaskRenderer.PoissonKernel.Length);

            // Not all shader passes support cascade visualization. Use a similar pass instead.
            if (shadow.VisualizeCascades)
            {
              if (numberOfSamples < 0)
              {
            numberOfSamples = 4;
              }
              else if (numberOfSamples == 0)
              {
            numberOfSamples = 1;
            filterRadius = 0;
              }
            }

            // The best dithered CSM supports max 22 samples.
            if (shadow.CascadeSelection == ShadowCascadeSelection.BestDithered && numberOfSamples > 22)
              numberOfSamples = 22;

            if (numberOfSamples > 0)
              filterRadius /= StandardShadowMaskRenderer.PoissonKernel[numberOfSamples - 1].Length();

            _parameterParameters2.SetValue(new Vector4(
              shadow.ShadowMap.Width,
              shadow.ShadowMap.Height,
              filterRadius,
              // The StandardShadow.JitterResolution is the number of texels per world unit.
              // In the shader the parameter JitterResolution contains the division by the jitter map size.
              shadow.JitterResolution / _jitterMap.Width));

            // Split distances.
            if (_parameterDistances != null)
            {
              // Set not used entries to large values.
              Vector4F distances = shadow.Distances;
              for (int j = shadow.NumberOfCascades; j < 4; j++)
            distances[j] = 10 * cameraFar;

              _parameterDistances.SetValue((Vector4)distances);
            }

            Debug.Assert(shadow.ViewProjections.Length == 4);
            for (int j = 0; j < _matrices.Length; j++)
              _matrices[j] = viewInverse * shadow.ViewProjections[j];

            _parameterShadowMatrices.SetValue(_matrices);

            _parameterDepthBias.SetValue((Vector4)shadow.EffectiveDepthBias);
            _parameterNormalOffset.SetValue((Vector4)shadow.EffectiveNormalOffset);

            Vector3F lightBackwardWorld = lightNode.PoseWorld.Orientation.GetColumn(2);
            _parameterLightDirection.SetValue((Vector3)cameraPose.ToLocalDirection(lightBackwardWorld));
            _parameterNumberOfCascades.SetValue(shadow.NumberOfCascades);
            _parameterShadowMap.SetValue(shadow.ShadowMap);

            var rectangle = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
            Vector2F texCoordTopLeft = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
            Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
            GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
            _parameterFrustumCorners.SetValue(_frustumFarCorners);

            var pass = GetPass(numberOfSamples, shadow.CascadeSelection, shadow.VisualizeCascades);

            if (numberOfSamples > 0)
            {
              if (_lastNumberOfSamples != numberOfSamples)
              {
            // Create an array with the first n samples and the rest set to 0.
            _lastNumberOfSamples = numberOfSamples;
            for (int j = 0; j < numberOfSamples; j++)
            {
              _samples[j].Y = StandardShadowMaskRenderer.PoissonKernel[j].Y;
              _samples[j].X = StandardShadowMaskRenderer.PoissonKernel[j].X;
              _samples[j].Z = 1.0f / numberOfSamples;
            }

            // Set the rest to zero.
            for (int j = numberOfSamples; j < _samples.Length; j++)
              _samples[j] = Vector3.Zero;

            _parameterSamples.SetValue(_samples);
              }
              else if (i == 0)
              {
            // Apply offsets in the first loop.
            _parameterSamples.SetValue(_samples);
              }
            }

            pass.Apply();

            graphicsDevice.DrawQuad(rectangle);
              }

              _parameterGBuffer0.SetValue((Texture2D)null);
              _parameterJitterMap.SetValue((Texture2D)null);
              _parameterShadowMap.SetValue((Texture2D)null);
              savedRenderState.Restore();
        }
Example #44
0
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              float deltaTime = (float)context.DeltaTime.TotalSeconds;

              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;
              var renderTargetPool = graphicsService.RenderTargetPool;

              var cameraNode = context.CameraNode;
              Projection projection = cameraNode.Camera.Projection;
              Pose view = cameraNode.PoseWorld.Inverse;

              // Around the camera we push the waves down to avoid that the camera cuts the near plane.
              // Get largest vector from camera to near plane corners.
              float nearPlaneRadius =
            new Vector3F(Math.Max(Math.Abs(projection.Right), Math.Abs(projection.Left)),
                     Math.Max(Math.Abs(projection.Top), Math.Abs(projection.Bottom)),
                     projection.Near
                    ).Length;

              var originalSourceTexture = context.SourceTexture;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              // Water surface is opaque.
              graphicsDevice.BlendState = BlendState.Opaque;

              #region ----- Common Effect Parameters -----

              _parameterView.SetValue(view);
              _parameterProjection.SetValue(projection);
              _parameterCameraParameters.SetValue(new Vector4(
            (Vector3)cameraNode.PoseWorld.Position,
            cameraNode.Camera.Projection.Far));

              var viewport = graphicsDevice.Viewport;
              _parameterViewportSize.SetValue(new Vector2(viewport.Width, viewport.Height));

              _parameterTime.SetValue((float)context.Time.TotalSeconds);

              // Query ambient and directional lights.
              var lightQuery = context.Scene.Query<GlobalLightQuery>(cameraNode, context);
              Vector3F ambientLight = Vector3F.Zero;
              if (lightQuery.AmbientLights.Count > 0)
              {
            var light = (AmbientLight)lightQuery.AmbientLights[0].Light;
            ambientLight = light.Color * light.Intensity * light.HdrScale;
              }

              _parameterAmbientLight.SetValue((Vector3)ambientLight);

              Vector3F directionalLightDirection = new Vector3F(0, -1, 0);
              Vector3F directionalLightIntensity = Vector3F.Zero;
              if (lightQuery.DirectionalLights.Count > 0)
              {
            var lightNode = lightQuery.DirectionalLights[0];
            var light = (DirectionalLight)lightNode.Light;
            directionalLightDirection = -lightNode.PoseWorld.Orientation.GetColumn(2);
            directionalLightIntensity = light.Color * light.SpecularIntensity * light.HdrScale;
              }

              _parameterDirectionalLightDirection.SetValue((Vector3)directionalLightDirection);
              _parameterDirectionalLightIntensity.SetValue((Vector3)directionalLightIntensity);

              _parameterGBuffer0.SetValue(context.GBuffer0);

              if (_parameterNoiseMap != null)
            _parameterNoiseMap.SetValue(_noiseMap);
              #endregion

              #region ----- Fog Parameters -----

              var fogNodes = context.Scene.Query<FogQuery>(cameraNode, context).FogNodes;
              SetFogParameters(fogNodes, cameraNode, directionalLightDirection);
              #endregion

              _parameterProjectedGridParameters.SetValue(new Vector3(
              ProjectedGridParameters.EdgeAttenuation,
              ProjectedGridParameters.DistanceAttenuationStart,
              ProjectedGridParameters.DistanceAttenuationEnd));

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as WaterNode;
            if (node == null)
              continue;

            // Node is visible in current frame.
            node.LastFrame = frame;

            var data = node.RenderData as WaterRenderData;
            if (data == null)
            {
              data = new WaterRenderData();
              node.RenderData = data;
            }

            var water = node.Water;
            bool isCameraUnderwater = node.EnableUnderwaterEffect && node.IsUnderwater(cameraNode.PoseWorld.Position);

            #region ----- Wave bending -----

            // Waves should not cut the near plane. --> Bend waves up or down if necessary.

            // Limits
            float upperLimit; // Waves must not move above this value.
            float lowerLimit; // Waves must not move below this value.

            // Bending fades in over interval [bendStart, bendEnd]:
            //   distance ≤ bendStart ............. Wave is bent up or down.
            //   bendStart < distance < bendEnd ... Lerp between normal wave and bent wave.
            //   distance ≥ bendEnd ............... Normal wave.
            float bendStart = 1 * nearPlaneRadius;
            float bendEnd = 10 * nearPlaneRadius;

            if (!isCameraUnderwater)
            {
              // Bend waves down below the camera.
              upperLimit = cameraNode.PoseWorld.Position.Y - nearPlaneRadius;
              lowerLimit = -1e20f;

              if (node.EnableUnderwaterEffect)
              {
            if (node.Waves == null || node.Waves.DisplacementMap == null)
            {
              // No displacement. The wave bending stuff does not work because the surface
              // is usually not tessellated. We have to render the underwater geometry when
              // camera near plane might cut the water surface.
              if (node.Volume == null)
              {
                // Test water plane.
                isCameraUnderwater = (cameraNode.PoseWorld.Position.Y - nearPlaneRadius) < node.PoseWorld.Position.Y;
              }
              else
              {
                // Test water AABB.
                var aabb = node.Aabb;
                aabb.Minimum -= new Vector3F(nearPlaneRadius);
                aabb.Maximum += new Vector3F(nearPlaneRadius);
                isCameraUnderwater = GeometryHelper.HaveContact(aabb, cameraNode.PoseWorld.Position);
              }
            }
              }
            }
            else
            {
              // Camera is underwater, bend triangles up above camera.
              upperLimit = 1e20f;
              lowerLimit = cameraNode.PoseWorld.Position.Y + nearPlaneRadius;
            }

            _parameterCameraMisc.SetValue(new Vector4(upperLimit, lowerLimit, bendStart, bendEnd));
            #endregion

            // Update the submesh for the given water volume.
            data.UpdateSubmesh(graphicsService, node);

            #region ----- Scroll Normal Maps -----

            // We update the normal map offsets once(!) per frame.
            // Note: We could skip the offsets and compute all in the shader using absolute
            // time instead of deltaTime, but then the user cannot change the NormalMapVelocity
            // smoothly.
            if (data.LastNormalUpdateFrame != frame)
            {
              data.LastNormalUpdateFrame = frame;

              var baseVelocity = (node.Flow != null) ? node.Flow.BaseVelocity : Vector3F.Zero;

              // Increase offset.
              // (Note: We have to subtract value and divide by scale because if the normal
              // should scroll to the right, we have to move the texcoords in the other direction.)
              data.NormalMapOffset0.X -= (water.NormalMap0Velocity.X + baseVelocity.X) * deltaTime / water.NormalMap0Scale;
              data.NormalMapOffset0.Y -= (water.NormalMap0Velocity.Z + baseVelocity.Y) * deltaTime / water.NormalMap0Scale;
              data.NormalMapOffset1.X -= (water.NormalMap1Velocity.X + baseVelocity.X) * deltaTime / water.NormalMap1Scale;
              data.NormalMapOffset1.Y -= (water.NormalMap1Velocity.Z + baseVelocity.Y) * deltaTime / water.NormalMap1Scale;

              // Keep only the fractional part to avoid overflow.
              data.NormalMapOffset0.X = MathHelper.Frac(data.NormalMapOffset0.X);
              data.NormalMapOffset0.Y = MathHelper.Frac(data.NormalMapOffset0.Y);
              data.NormalMapOffset1.X = MathHelper.Frac(data.NormalMapOffset1.X);
              data.NormalMapOffset1.Y = MathHelper.Frac(data.NormalMapOffset1.Y);
            }
            #endregion

            _parameterSurfaceLevel.SetValue(node.PoseWorld.Position.Y);

            #region ----- Reflection Parameters -----

            if (node.PlanarReflection != null
            && node.PlanarReflection.ActualIsEnabled
            && node.PlanarReflection.RenderToTexture.Texture is Texture2D)
            {
              // Planar reflection.
              var renderToTexture = node.PlanarReflection.RenderToTexture;
              var texture = (Texture2D)renderToTexture.Texture;

              _parameterReflectionTypeParameters.SetValue(new Vector2(0, 1));
              _parameterReflectionMatrix.SetValue((Matrix)renderToTexture.TextureMatrix);
              _parameterReflectionTextureSize.SetValue(new Vector2(texture.Width, texture.Height));
              if (_parameterPlanarReflectionMap != null)
            _parameterPlanarReflectionMap.SetValue(texture);

              _parameterReflectionParameters.SetValue(new Vector4(
            (Vector3)water.ReflectionColor,
            water.ReflectionDistortion));
            }
            else if (node.SkyboxReflection != null)
            {
              // Cube map reflection.
              var rgbmEncoding = node.SkyboxReflection.Encoding as RgbmEncoding;
              float rgbmMax = 1;
              if (rgbmEncoding != null)
            rgbmMax = GraphicsHelper.ToGamma(rgbmEncoding.Max);
              else if (!(node.SkyboxReflection.Encoding is SRgbEncoding))
            throw new NotImplementedException("The reflected skybox must be encoded using sRGB or RGBM.");

              _parameterReflectionTypeParameters.SetValue(new Vector2(1, rgbmMax));

              // Cube maps are left handed --> Sample with inverted z. (Otherwise, the
              // cube map and objects or texts in it are mirrored.)
              var mirrorZ = Matrix44F.CreateScale(1, 1, -1);
              Matrix33F orientation = node.SkyboxReflection.PoseWorld.Orientation;
              _parameterReflectionMatrix.SetValue((Matrix)(new Matrix44F(orientation, Vector3F.Zero) * mirrorZ));

              if (_parameterCubeReflectionMap != null)
            _parameterCubeReflectionMap.SetValue(node.SkyboxReflection.Texture);

              _parameterReflectionParameters.SetValue(new Vector4(
            (Vector3)(water.ReflectionColor * node.SkyboxReflection.Color),
            water.ReflectionDistortion));
            }
            else
            {
              // No reflection texture. The reflection shows only the ReflectionColor.
              _parameterReflectionTypeParameters.SetValue(new Vector2(-1, 1));
              _parameterReflectionParameters.SetValue(new Vector4(
            (Vector3)water.ReflectionColor,
            water.ReflectionDistortion));
            }
            #endregion

            #region ----- Refraction Parameters -----

            // If we do not have a source texture, resolve the current render target
            // and immediately rebuilt it.
            if (context.SourceTexture == null && context.RenderTarget != null)
            {
              // Get RebuildZBufferRenderer from RenderContext.
              RebuildZBufferRenderer rebuildZBufferRenderer = null;
              object obj;
              if (context.Data.TryGetValue(RenderContextKeys.RebuildZBufferRenderer, out obj))
            rebuildZBufferRenderer = obj as RebuildZBufferRenderer;

              // If we didn't find the renderer in the context, use a default instance.
              if (rebuildZBufferRenderer == null)
              {
            if (_defaultRebuildZBufferRenderer == null)
              _defaultRebuildZBufferRenderer = new RebuildZBufferRenderer(graphicsService);

            rebuildZBufferRenderer = _defaultRebuildZBufferRenderer;
              }

              context.SourceTexture = context.RenderTarget;
              context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(context.RenderTarget));
              graphicsDevice.SetRenderTarget(context.RenderTarget);
              graphicsDevice.Viewport = context.Viewport;
              rebuildZBufferRenderer.Render(context, context.SourceTexture);
            }

            _parameterRefractionTexture.SetValue(context.SourceTexture);
            _parameterRefractionParameters.SetValue(new Vector4(
              ((Vector3)water.RefractionColor),
              water.RefractionDistortion));
            #endregion

            #region ----- Other Water Effect Parameters -----

            if (water.NormalMap0 != null)
            {
              if (_parameterNormalMap0 != null)
            _parameterNormalMap0.SetValue(water.NormalMap0);

              _parameterNormalMap0Parameters.SetValue(new Vector4(
            1 / water.NormalMap0Scale,
            data.NormalMapOffset0.X,
            data.NormalMapOffset0.Y,
            water.NormalMap0Strength));
            }
            else
            {
              if (_parameterNormalMap0 != null)
            _parameterNormalMap0.SetValue(_graphicsService.GetDefaultNormalTexture());
              _parameterNormalMap0Parameters.SetValue(new Vector4(1, 0, 0, 0));
            }

            if (water.NormalMap1 != null)
            {
              if (_parameterNormalMap1 != null)
            _parameterNormalMap1.SetValue(water.NormalMap1);

              _parameterNormalMap1Parameters.SetValue(new Vector4(
            1 / water.NormalMap1Scale,
            data.NormalMapOffset1.X,
            data.NormalMapOffset1.Y,
            water.NormalMap1Strength));
            }
            else
            {
              if (_parameterNormalMap1 != null)
            _parameterNormalMap1.SetValue(_graphicsService.GetDefaultNormalTexture());
              _parameterNormalMap1Parameters.SetValue(new Vector4(1, 0, 0, 0));
            }

            _parameterSpecularParameters.SetValue(new Vector4((Vector3)water.SpecularColor, water.SpecularPower));
            _parameterUnderwaterFogParameters.SetValue((Vector3)water.UnderwaterFogDensity);
            _parameterFresnelParameters.SetValue(new Vector3(water.FresnelBias, water.FresnelScale, water.FresnelPower));
            _parameterIntersectionSoftness.SetValue(water.IntersectionSoftness);

            // We apply some arbitrary scale factors to the water and scatter colors to
            // move the values into a similar range from the user's perspective.
            _parameterWaterColor.SetValue((Vector3)water.WaterColor / 10);
            _parameterScatterColor.SetValue((Vector3)water.ScatterColor);

            if (_parameterFoamMap != null)
            {
              _parameterFoamMap.SetValue(water.FoamMap);
              _parameterFoamParameters0.SetValue(new Vector4(
            (Vector3)water.FoamColor,
            1 / water.FoamMapScale));

              _parameterFoamParameters1.SetValue(new Vector4(
            water.FoamDistortion,
            water.FoamShoreIntersection,
            // Enable crest foam only if we have waves.
            node.Waves != null ? water.FoamCrestMin : float.MaxValue,
            water.FoamCrestMax));
            }

            _parameterCausticsSampleCount.SetValue(water.CausticsSampleCount);
            _parameterCausticsParameters.SetValue(new Vector4(
              water.CausticsSampleOffset,
              water.CausticsDistortion,
              water.CausticsPower,
              water.CausticsIntensity));
            #endregion

            #region ----- Wave Map -----

            var waves = node.Waves;

            // The displacement map can be null but the normal map must not be null.
            if (waves != null && waves.NormalMap != null)
            {
              // Type: 0 = Tiling, 1 = Clamp.
              float waveType;
              if (waves.IsTiling)
            waveType = 0;
              else
            waveType = 1;

              _parameterWaveMapParameters.SetValue(new Vector4(
            1.0f / waves.TileSize,                          // Scale
            0.5f - waves.TileCenter.X / waves.TileSize,     // Offset X
            0.5f - waves.TileCenter.Z / waves.TileSize,     // Offset Y
            waveType));

              if (_parameterDisplacementTexture != null)
              {
            if (waves.DisplacementMap != null)
              _parameterDisplacementTexture.SetValue(waves.DisplacementMap);
            else
              _parameterDisplacementTexture.SetValue(graphicsService.GetDefaultTexture2DBlack4F());
              }

              _parameterWaveMapSize.SetValue(new Vector2(
            waves.NormalMap.Width,
            waves.NormalMap.Height));
              if (_parameterWaveNormalMap != null)
            _parameterWaveNormalMap.SetValue(waves.NormalMap);
            }
            else
            {
              _parameterWaveMapParameters.SetValue(new Vector4(0, 0, 0, 0));
            }
            #endregion

            #region ----- Flow -----

            if (node.Flow != null)
            {
              var flow = node.Flow;
              float flowMapSpeed = (flow.FlowMap != null) ? flow.FlowMapSpeed : 0;
              _parameterFlowParameters0.SetValue(new Vector4(flow.SurfaceSlopeSpeed, flowMapSpeed, flow.CycleDuration, flow.MaxSpeed));
              _parameterFlowParameters1.SetValue(new Vector3(flow.MinStrength, 1 / flow.NoiseMapScale, flow.NoiseMapStrength));

              if (_parameterFlowMap != null)
            _parameterFlowMap.SetValue(flow.FlowMap);

              // Get world space (x, z) to texture space matrix.
              Aabb aabb = node.Shape.GetAabb();
              Vector3F extent = aabb.Extent;
              Matrix44F m = Matrix44F.CreateScale(1 / extent.X, 1, 1 / extent.Z)
                        * Matrix44F.CreateTranslation(-aabb.Minimum.X, 0, -aabb.Minimum.Z)
                        * Matrix44F.CreateScale(1 / node.ScaleLocal.X, 1, 1 / node.ScaleLocal.Z)
                        * node.PoseWorld.Inverse;

              // We use a 3x3 2d scale/rotation/translation matrix, ignoring the y component.
              _parameterFlowMapTextureMatrix.SetValue(new Matrix(m.M00, m.M20, 0, 0,
                                                             m.M02, m.M22, 0, 0,
                                                             m.M03, m.M23, 1, 0,
                                                             0, 0, 0, 0));

              // Get local flow direction to world flow direction matrix.
              // We use a 2x2 2d rotation matrix, ignoring the y component.
              var r = node.PoseWorld.Orientation;
              _parameterFlowMapWorldMatrix.SetValue(new Matrix(r.M00, r.M20, 0, 0,
                                                           r.M02, r.M22, 0, 0,
                                                           0, 0, 0, 0,
                                                           0, 0, 0, 0));
            }
            else
            {
              _parameterFlowParameters0.SetValue(new Vector4(0, 0, 0, 0));
              _parameterFlowParameters1.SetValue(new Vector3(0, 0, 0));
            }
            #endregion

            if (isCameraUnderwater)
              RenderUnderwaterGeometry(node, cameraNode);

            RenderSurface(node, cameraNode, isCameraUnderwater);
              }

              // Reset texture effect parameters.
              _parameterGBuffer0.SetValue((Texture2D)null);
              _parameterRefractionTexture.SetValue((Texture2D)null);

              if (_parameterPlanarReflectionMap != null)
            _parameterPlanarReflectionMap.SetValue((Texture2D)null);

              if (_parameterCubeReflectionMap != null)
            _parameterCubeReflectionMap.SetValue((TextureCube)null);

              if (_parameterNormalMap0 != null)
            _parameterNormalMap0.SetValue((Texture2D)null);

              if (_parameterNormalMap1 != null)
            _parameterNormalMap1.SetValue((Texture2D)null);

              if (_parameterDisplacementTexture != null)
            _parameterDisplacementTexture.SetValue((Texture2D)null);

              if (_parameterNoiseMap != null)
            _parameterNoiseMap.SetValue((Texture2D)null);

              if (_parameterWaveNormalMap != null)
            _parameterWaveNormalMap.SetValue((Texture2D)null);

              if (_parameterFlowMap != null)
            _parameterFlowMap.SetValue((Texture2D)null);

              // This seems to be necessary because the Displacement Texture (vertex texture!)
              // is not automatically removed from the texture stage, and the WaterWavesRenderer
              // cannot write into it. XNA Bug!?
              _passProjectedGrid.Apply();

              savedRenderState.Restore();

              // Restore original render context.
              if (originalSourceTexture == null)
              {
            // Current render target has been resolved and used as source texture.
            // A new render target (from pool) has been set. (See region "Refraction Parameters".)
            // --> Previous render target needs to be recycled.
            renderTargetPool.Recycle(context.SourceTexture);
              }

              context.SourceTexture = originalSourceTexture;
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");
              if (context.Scene == null)
            throw new ArgumentException("Scene needs to be set in render context.", "context");
              if (context.CameraNode == null)
            throw new ArgumentException("Camera needs to be set in render context.", "context");
              if (!(context.CameraNode.Camera.Projection is PerspectiveProjection))
            throw new ArgumentException("The camera in the render context must use a perspective projection.", "context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              int frame = context.Frame;

              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              var originalRenderTarget = context.RenderTarget;
              var originalViewport = context.Viewport;
              var originalCameraNode = context.CameraNode;
              var originalLodCameraNode = context.LodCameraNode;
              float originalLodBias = context.LodBias;
              var originalReferenceNode = context.ReferenceNode;

              Pose originalCameraPose = originalCameraNode.PoseWorld;
              Vector3F originalCameraPosition = originalCameraPose.Position;
              Matrix33F originalCameraOrientation = originalCameraPose.Orientation;

              Vector3F right = originalCameraOrientation.GetColumn(0);
              Vector3F up = originalCameraOrientation.GetColumn(1);
              Vector3F back = originalCameraOrientation.GetColumn(2);

              try
              {
            // Use foreach instead of for-loop to catch InvalidOperationExceptions in
            // case the collection is modified.
            for (int i = 0; i < numberOfNodes; i++)
            {
              var node = nodes[i] as PlanarReflectionNode;
              if (node == null)
            continue;

              // Update each node only once per frame.
              if (node.LastFrame == frame)
            continue;

              node.LastFrame = frame;

              var texture = node.RenderToTexture.Texture;
              if (texture == null)
            continue;

              var renderTarget = texture as RenderTarget2D;
              if (renderTarget == null)
            throw new GraphicsException(
              "PlanarReflectionNode.RenderToTexture.Texture is invalid. The texture must be a RenderTarget2D.");

              // RenderToTexture instances can be shared. --> Update them only once per frame.
              if (node.RenderToTexture.LastFrame == frame)
            continue;

              // Do not render if we look at the back of the reflection plane.
              Vector3F planeNormal = node.NormalWorld;
              Vector3F planePosition = node.PoseWorld.Position;
              Vector3F planeToCamera = originalCameraPosition - planePosition;
              if (Vector3F.Dot(planeNormal, planeToCamera) < 0)
            continue;

              var cameraNode = node.CameraNode;

              // Reflect camera pose.
              Pose cameraPose;
              cameraPose.Position = planePosition + Reflect(planeToCamera, planeNormal);
              cameraPose.Orientation = new Matrix33F();
              cameraPose.Orientation.SetColumn(0, Reflect(right, planeNormal));
              cameraPose.Orientation.SetColumn(1, -Reflect(up, planeNormal));
              cameraPose.Orientation.SetColumn(2, Reflect(back, planeNormal));
              cameraNode.PoseWorld = cameraPose;

              // The projection of the player camera.
              var originalProjection = originalCameraNode.Camera.Projection;
              // The projection of the reflected camera.
              var projection = (PerspectiveProjection)cameraNode.Camera.Projection;

              // Choose optimal projection. We get the screen-space bounds of the reflection node.
              // Then we make the FOV so small that it exactly contains the node.
              projection.Set(originalProjection);

              var bounds = GraphicsHelper.GetBounds(cameraNode, node);

              // Abort if the bounds are empty.
              if (Numeric.AreEqual(bounds.X, bounds.Z) || Numeric.AreEqual(bounds.Y, bounds.W))
            continue;

              // Apply FOV scale to bounds.
              float fovScale = node.FieldOfViewScale;
              float deltaX = (bounds.Z - bounds.X) * (fovScale - 1) / 2;
              bounds.X -= deltaX;
              bounds.Z += deltaX;
              float deltaY = (bounds.W - bounds.Y) * (fovScale - 1) / 2;
              bounds.Y -= deltaY;
              bounds.W += deltaY;

              // Update projection to contain only the node bounds.
              projection.Left = projection.Left + bounds.X * projection.Width;
              projection.Right = projection.Left + bounds.Z * projection.Width;
              projection.Top = projection.Top - bounds.Y * projection.Height;
              projection.Bottom = projection.Top - bounds.W * projection.Height;

              // Set far clip plane.
              if (node.Far.HasValue)
            projection.Far = node.Far.Value;

              // Set near clip plane.
              Vector3F planeNormalCamera = cameraPose.ToLocalDirection(-node.NormalWorld);
              Vector3F planePointCamera = cameraPose.ToLocalPosition(node.PoseWorld.Position);
              projection.NearClipPlane = new Plane(planeNormalCamera, planePointCamera);

              context.CameraNode = cameraNode;
              context.LodCameraNode = cameraNode;
              context.LodBias = node.LodBias ?? originalLodBias;
              context.ReferenceNode = node;

              context.RenderTarget = renderTarget;
              context.Viewport = new Viewport(0, 0, renderTarget.Width, renderTarget.Height);

              RenderCallback(context);

              // Update other properties of RenderToTexture.
              node.RenderToTexture.LastFrame = frame;
              node.RenderToTexture.TextureMatrix = GraphicsHelper.ProjectorBiasMatrix
                                               * cameraNode.Camera.Projection
                                               * cameraNode.PoseWorld.Inverse;
            }
              }
              catch (InvalidOperationException exception)
              {
            throw new GraphicsException(
              "InvalidOperationException was raised in PlanarReflectionRenderer.Render(). "
              + "This can happen if a SceneQuery instance that is currently in use is modified in the "
              + "RenderCallback. --> Use different SceneQuery types in the method which calls "
              + "SceneCaptureRenderer.Render() and in the RenderCallback method.",
              exception);
              }

              graphicsDevice.SetRenderTarget(null);
              savedRenderState.Restore();

              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
              context.CameraNode = originalCameraNode;
              context.LodCameraNode = originalLodCameraNode;
              context.LodBias = originalLodBias;
              context.ReferenceNode = originalReferenceNode;
        }
Example #46
0
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

              if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (nodes.Count == 0)
            return;

              context.Validate(_spriteBatch);
              context.ThrowIfCameraMissing();

              var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);

              // Camera properties
              var cameraNode = context.CameraNode;
              Matrix44F viewProjection = cameraNode.Camera.Projection * cameraNode.View;
              var viewport = graphicsDevice.Viewport;

              // Update SceneNode.LastFrame for all visible nodes.
              int frame = context.Frame;
              cameraNode.LastFrame = frame;

              SpriteSortMode sortMode;
              switch (order)
              {
            case RenderOrder.Default:
              sortMode = SpriteSortMode.Texture;
              break;
            case RenderOrder.FrontToBack:
              sortMode = SpriteSortMode.FrontToBack;
              break;
            case RenderOrder.BackToFront:
              sortMode = SpriteSortMode.BackToFront;
              break;
            case RenderOrder.UserDefined:
            default:
              sortMode = SpriteSortMode.Deferred;
              break;
              }

              _spriteBatch.Begin(sortMode, graphicsDevice.BlendState, null, graphicsDevice.DepthStencilState, null);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var node = nodes[i] as SpriteNode;
            if (node == null)
              continue;

            // SpriteNode is visible in current frame.
            node.LastFrame = frame;

            // Position, size, and origin in pixels.
            Vector3F position = new Vector3F();
            Vector2 size = new Vector2();
            Vector2 origin = new Vector2();

            var bitmapSprite = node.Sprite as ImageSprite;
            if (bitmapSprite != null)
            {
              var packedTexture = bitmapSprite.Texture;
              if (packedTexture != null)
              {
            // Project into viewport and snap to pixels.
            position = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
            position.X = (int)(position.X + 0.5f);
            position.Y = (int)(position.Y + 0.5f);

            // Get source rectangle (pixel bounds).
            var sourceRectangle = packedTexture.GetBounds(node.AnimationTime);
            size = new Vector2(sourceRectangle.Width, sourceRectangle.Height);

            // Premultiply color.
            Vector3F color3F = node.Color;
            float alpha = node.Alpha;
            Color color = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

            // Get absolute origin (relative to pixel bounds).
            origin = (Vector2)node.Origin * size;

            // Draw using SpriteBatch.
            _spriteBatch.Draw(
              packedTexture.TextureAtlas, new Vector2(position.X, position.Y), sourceRectangle,
              color, node.Rotation, origin, (Vector2)node.Scale, SpriteEffects.None, position.Z);
              }
            }
            else
            {
              var textSprite = node.Sprite as TextSprite;
              if (textSprite != null)
              {
            var font = textSprite.Font ?? _spriteFont;
            if (font != null)
            {
              // Text can be a string or StringBuilder.
              var text = textSprite.Text as string;
              if (text != null)
              {
                if (text.Length > 0)
                {
                  // Project into viewport and snap to pixels.
                  position = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                  position.X = (int)(position.X + 0.5f);
                  position.Y = (int)(position.Y + 0.5f);

                  // Premultiply color.
                  Vector3F color3F = node.Color;
                  float alpha = node.Alpha;
                  Color color = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                  // Get absolute origin (relative to pixel bounds).
                  size = font.MeasureString(text);
                  origin = (Vector2)node.Origin * size;

                  // Draw using SpriteBatch.
                  _spriteBatch.DrawString(
                    font, text, new Vector2(position.X, position.Y),
                    color, node.Rotation, origin, (Vector2)node.Scale,
                    SpriteEffects.None, position.Z);
                }
              }
              else
              {
                var stringBuilder = textSprite.Text as StringBuilder;
                if (stringBuilder != null && stringBuilder.Length > 0)
                {
                  // Project into viewport and snap to pixels.
                  position = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                  position.X = (int)(position.X + 0.5f);
                  position.Y = (int)(position.Y + 0.5f);

                  // Premultiply color.
                  Vector3F color3F = node.Color;
                  float alpha = node.Alpha;
                  Color color = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                  // Get absolute origin (relative to pixel bounds).
                  size = font.MeasureString(stringBuilder);
                  origin = (Vector2)node.Origin * size;

                  // Draw using SpriteBatch.
                  _spriteBatch.DrawString(
                    font, stringBuilder, new Vector2(position.X, position.Y),
                    color, node.Rotation, origin, (Vector2)node.Scale,
                    SpriteEffects.None, position.Z);
                }
              }
            }
              }
            }

            // Store bounds an depth for hit tests.
            node.LastBounds = new Rectangle(
              (int)(position.X - origin.X),
              (int)(position.Y - origin.Y),
              (int)(size.X * node.Scale.X),
              (int)(size.Y * node.Scale.Y));

            node.LastDepth = position.Z;
              }

              _spriteBatch.End();
              savedRenderState.Restore();
        }
        public override void Render(IList<SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            throw new ArgumentNullException("nodes");
              if (context == null)
            throw new ArgumentNullException("context");

              int numberOfNodes = nodes.Count;
              if (numberOfNodes == 0)
            return;

              context.Validate(_effect);
              context.ThrowIfCameraMissing();

              var graphicsDevice = _effect.GraphicsDevice;
              var savedRenderState = new RenderStateSnapshot(graphicsDevice);
              graphicsDevice.DepthStencilState = DepthStencilState.None;
              graphicsDevice.RasterizerState = RasterizerState.CullNone;

              var cameraNode = context.CameraNode;
              _parameterViewInverse.SetValue(cameraNode.PoseWorld);
              _parameterGBuffer0.SetValue(context.GBuffer0);

              Viewport viewport = context.Viewport;
              _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

              if (_jitterMap == null)
            _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);

              _parameterJitterMap.SetValue(_jitterMap);

              for (int i = 0; i < numberOfNodes; i++)
              {
            var lightNode = nodes[i] as LightNode;
            if (lightNode == null)
              continue;

            var light = lightNode.Light as PointLight;
            if (light == null)
              return;

            var shadow = lightNode.Shadow as CubeMapShadow;
            if (shadow == null)
              continue;

            if (shadow.ShadowMap == null || shadow.ShadowMask == null)
              continue;

            // The effect must only render in a specific channel.
            // Do not change blend state if the correct write channels is already set, e.g. if this
            // shadow is part of a CompositeShadow, the correct blend state is already set.
            if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
              graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];

            _parameterParameters1.SetValue(new Vector4(
              shadow.Near,
              light.Range,
              shadow.EffectiveDepthBias,
              shadow.EffectiveNormalOffset));

            // If we use a subset of the Poisson kernel, we have to normalize the scale.
            int numberOfSamples = Math.Min(shadow.NumberOfSamples, StandardShadowMaskRenderer.PoissonKernel.Length);
            float filterRadius = shadow.FilterRadius;
            if (numberOfSamples > 0)
              filterRadius /= StandardShadowMaskRenderer.PoissonKernel[numberOfSamples - 1].Length();

            _parameterParameters2.SetValue(new Vector3(
              shadow.ShadowMap.Size,
              filterRadius,
              // The StandardShadow.JitterResolution is the number of texels per world unit.
              // In the shader the parameter JitterResolution contains the division by the jitter map size.
              shadow.JitterResolution / _jitterMap.Width));

            _parameterLightPosition.SetValue((Vector3)cameraNode.PoseWorld.ToLocalPosition(lightNode.PoseWorld.Position));

            _parameterShadowView.SetValue(lightNode.PoseWorld.Inverse * cameraNode.PoseWorld);
            _parameterShadowMap.SetValue(shadow.ShadowMap);

            var rectangle = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
            Vector2F texCoordTopLeft = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
            Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
            GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
            _parameterFrustumCorners.SetValue(_frustumFarCorners);

            var pass = GetPass(numberOfSamples);

            if (numberOfSamples > 0)
            {
              if (_lastNumberOfSamples != numberOfSamples)
              {
            // Create an array with the first n samples and the rest set to 0.
            _lastNumberOfSamples = numberOfSamples;
            for (int j = 0; j < numberOfSamples; j++)
            {
              _samples[j].Y = StandardShadowMaskRenderer.PoissonKernel[j].Y;
              _samples[j].X = StandardShadowMaskRenderer.PoissonKernel[j].X;
              _samples[j].Z = 1.0f / numberOfSamples;
            }

            // Set the rest to zero.
            for (int j = numberOfSamples; j < _samples.Length; j++)
              _samples[j] = Vector3.Zero;

            _parameterSamples.SetValue(_samples);
              }
              else if (i == 0)
              {
            // Apply offsets in the first loop.
            _parameterSamples.SetValue(_samples);
              }
            }

            pass.Apply();

            graphicsDevice.DrawQuad(rectangle);
              }

              _parameterGBuffer0.SetValue((Texture2D)null);
              _parameterJitterMap.SetValue((Texture2D)null);
              _parameterShadowMap.SetValue((Texture2D)null);
              savedRenderState.Restore();
        }
Example #48
0
        private void ProcessJobs(RenderContext context)
        {
            // Set render states.
            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.RasterizerState = RasterizerState.CullNone;

            bool renderFill = (Options & FigureRenderOptions.RenderFill) != 0;

            if (renderFill)
            {
                SetupFill(context);
            }

            bool renderStroke = (Options & FigureRenderOptions.RenderStroke) != 0;

            if (renderStroke)
            {
                SetupStroke(context);
            }

            var jobs     = _jobs.Array;
            int jobCount = _jobs.Count;

            _mode = RenderMode.Undefined;
            for (int i = 0; i < jobCount; i++)
            {
                var node       = jobs[i].Node;
                var renderData = node.Figure.RenderData;
                if (renderData == null)
                {
                    continue;
                }

                var vertices = renderData.Vertices;
                if (vertices == null || vertices.Count == 0)
                {
                    continue;
                }

                // We can cache a static vertex buffer for static figures with camera-independent dash patterns.
                if (node.IsStatic && node.DashInWorldSpace)
                {
                    var nodeRenderData = node.RenderData as FigureNodeRenderData;
                    if (nodeRenderData == null)
                    {
                        nodeRenderData  = new FigureNodeRenderData();
                        node.RenderData = nodeRenderData;
                    }

                    if (!nodeRenderData.IsValid)
                    {
                        CacheVertexBuffer(node, _graphicsService.GraphicsDevice);
                    }
                }

                // Render filled polygons.
                var fillIndices = renderData.FillIndices;
                if (renderFill &&
                    fillIndices != null &&
                    fillIndices.Count > 0 &&
                    !Numeric.IsZero(node.FillAlpha))
                {
                    Fill(node, vertices, fillIndices);
                }

                // Render stroked lines.
                var strokeIndices = renderData.StrokeIndices;
                if (renderStroke &&
                    strokeIndices != null &&
                    strokeIndices.Count > 0 &&
                    !Numeric.IsZero(node.StrokeThickness) &&
                    !Numeric.IsZero(node.StrokeAlpha))
                {
                    Stroke(node, vertices, strokeIndices);
                }
            }

            Flush();

            savedRenderState.Restore();
        }