예제 #1
0
        public GBufferRenderer(IGraphicsService graphicsService, SceneNodeRenderer sceneNodeRenderer, DecalRenderer decalRenderer)
        {
            _clearGBufferRenderer = new ClearGBufferRenderer(graphicsService);
              _sceneNodeRenderer = sceneNodeRenderer;
              _decalRenderer = decalRenderer;

              // This filter is used to downsample the depth buffer (GBuffer0).
              _downsampleFilter = PostProcessHelper.GetDownsampleFilter(graphicsService);
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ShadowMapRenderer"/> class using the specified
        /// scene node renderer.
        /// </summary>
        /// <param name="sceneNodeRenderer">
        /// The renderer for shadow-casting objects. A <see cref="RenderCallback"/> is created
        /// automatically which calls the specified renderer.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="sceneNodeRenderer"/> is <see langword="null"/>.
        /// </exception>
        public ShadowMapRenderer(SceneNodeRenderer sceneNodeRenderer)
        {
            if (sceneNodeRenderer == null)
            {
                throw new ArgumentNullException("sceneNodeRenderer");
            }

            _renderCallback = context =>
            {
                var query = context.Scene.Query <ShadowCasterQuery>(context.CameraNode, context);
                if (query.ShadowCasters.Count == 0)
                {
                    return(false);
                }

                sceneNodeRenderer.Render(query.ShadowCasters, context);
                return(true);
            };

            AddDefaultRenderers(_renderCallback);
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ShadowMapRenderer"/> class using the specified
        /// scene node renderer.
        /// </summary>
        /// <param name="sceneNodeRenderer">
        /// The renderer for shadow-casting objects. A <see cref="RenderCallback"/> is created
        /// automatically which calls the specified renderer.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="sceneNodeRenderer"/> is <see langword="null"/>.
        /// </exception>
        public ShadowMapRenderer(SceneNodeRenderer sceneNodeRenderer)
        {
            if (sceneNodeRenderer == null)
            throw new ArgumentNullException("sceneNodeRenderer");

              _renderCallback = context =>
                        {
                          var query = context.Scene.Query<ShadowCasterQuery>(context.CameraNode, context);
                          if (query.ShadowCasters.Count == 0)
                            return false;

                          sceneNodeRenderer.Render(query.ShadowCasters, context);
                          return true;
                        };

              AddDefaultRenderers(_renderCallback);
        }
예제 #4
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;
        }
예제 #5
0
 public void Render(IList<SceneNode> occluders, SceneNodeRenderer renderer, RenderContext context)
 {
     Render(occluders, null, renderer, context);
 }
예제 #6
0
        /// <summary>
        /// Sorts occluders by type (<see cref="IOcclusionProxy"/> vs. <see cref="SceneNode"/>).
        /// </summary>
        /// <param name="nodes">The nodes.</param>
        /// <param name="renderer">The renderer.</param>
        /// <param name="context">The context.</param>
        private void SortOccluders(IList<SceneNode> nodes, SceneNodeRenderer renderer, RenderContext context)
        {
            Debug.Assert(_occlusionProxies.Count == 0, "The list of IOcclusionProxy has not been cleared.");
              Debug.Assert(_sceneNodes.Count == 0, "The list of SceneNodes has not been cleared.");

              if (nodes == null)
            return;

              int numberOfNodes = nodes.Count;
              if (renderer == null)
              {
            // Search only for IOcclusionProxy.
            for (int i = 0; i < numberOfNodes; i++)
            {
              var node = nodes[i];
              if (node == null)
            continue;

              var occlusionProxy = node as IOcclusionProxy;
              if (occlusionProxy != null && occlusionProxy.HasOccluder)
            _occlusionProxies.Add(occlusionProxy);
            }
              }
              else
              {
            // Search for IOcclusionProxy and renderable scene nodes.
            for (int i = 0; i < numberOfNodes; i++)
            {
              var node = nodes[i];
              if (node == null)
            continue;

              var occlusionProxy = node as IOcclusionProxy;
              if (occlusionProxy != null && occlusionProxy.HasOccluder)
            _occlusionProxies.Add(occlusionProxy);
              else if (renderer.CanRender(node, context))
            _sceneNodes.Add(node);
            }
              }
        }
예제 #7
0
        /// <summary>
        /// Renders the occluders.
        /// </summary>
        /// <param name="renderer">
        /// Optional: A <see cref="SceneNodeRenderer"/> for rendering custom scene nodes into the
        /// occlusion buffer.
        /// </param>
        /// <param name="context">The context.</param>
        private void RenderOccluders(SceneNodeRenderer renderer, RenderContext context)
        {
            // ----- Clear occlusion buffer.
              var graphicsService = context.GraphicsService;
              var graphicsDevice = graphicsService.GraphicsDevice;

              graphicsDevice.SetRenderTarget(_hzbLevels[0]);
              context.RenderTarget = _hzbLevels[0];
              context.Viewport = graphicsDevice.Viewport;
              graphicsDevice.Clear(Color.White);

              // ----- Render scene nodes using custom scene node renderer.
              if (renderer != null && _sceneNodes.Count > 0)
              {
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState = RasterizerState.CullNone;
            graphicsDevice.BlendState = BlendState.Opaque;

            renderer.Render(_sceneNodes, context);
              }

              // ----- Render all IOcclusionProxy.
              if (EnableMultithreading)
            _updateTask.Wait();

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

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

              // Go through list of occluders and submit triangles to render batch.
              int numberOfOccluders = _occlusionProxies.Count;
              for (int i = 0; i < numberOfOccluders; i++)
              {
            var data = _occlusionProxies[i].GetOccluder();

            int vertexBufferIndex, indexBufferIndex;
            _renderBatch.Submit(PrimitiveType.TriangleList, data.Vertices.Length, data.Indices.Length, out vertexBufferIndex, out indexBufferIndex);

            // Copy triangle vertices.
            data.Vertices.CopyTo(_renderBatch.Vertices, vertexBufferIndex);

            // Adjust and copy triangle indices.
            for (int j = 0; j < data.Indices.Length; j++, indexBufferIndex++)
              _renderBatch.Indices[indexBufferIndex] = (ushort)(vertexBufferIndex + data.Indices[j]);
              }

              _renderBatch.Flush();
        }