Exemplo n.º 1
0
        internal static UpsampleFilter GetUpsampleFilter(this IGraphicsService graphicsService)
        {
            if (graphicsService == null)
            {
                throw new ArgumentNullException("graphicsService");
            }

            const string Key = "__UpsampleFilter";
            object       obj;

            graphicsService.Data.TryGetValue(Key, out obj);
            var instance = obj as UpsampleFilter;

            if (instance == null)
            {
                instance = new UpsampleFilter(graphicsService);
                graphicsService.Data[Key] = instance;
            }

            return(instance);
        }
Exemplo n.º 2
0
    /// <inheritdoc/>
    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 (order != RenderOrder.UserDefined)
        throw new NotImplementedException("Render order must be 'UserDefined'.");
      if (context.CameraNode == null)
        throw new GraphicsException("Camera node needs to be set in render context.");
      if (context.GBuffer0 == null)
        throw new GraphicsException("GBuffer0 needs to be set in render context.");

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

      var graphicsService = context.GraphicsService;
      var graphicsDevice = graphicsService.GraphicsDevice;
      var viewport = context.Viewport;
      int width = viewport.Width;
      int height = viewport.Height;
      var renderTargetPool = graphicsService.RenderTargetPool;
      var cameraNode = context.CameraNode;
      var projection = cameraNode.Camera.Projection;
      Pose view = cameraNode.PoseWorld.Inverse;
      Pose cameraPose = cameraNode.PoseWorld;
      float near = projection.Near;
      float far = projection.Far;

      int frame = context.Frame;
      cameraNode.LastFrame = frame;

      // Save render state.
      var originalRasterizerState = graphicsDevice.RasterizerState;
      var originalDepthStencilState = graphicsDevice.DepthStencilState;
      var originalBlendState = graphicsDevice.BlendState;

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

      RenderTarget2D offscreenBuffer = null;
      Texture depthBufferHalf = null;
      if (!EnableOffscreenRendering || context.RenderTarget == null)
      {
        graphicsDevice.BlendState = BlendState.AlphaBlend;
        _parameterGBuffer0.SetValue(context.GBuffer0);
      }
      else
      {
        // Render at half resolution into off-screen buffer.
        width = Math.Max(1, width / 2);
        height = Math.Max(1, height / 2);

        graphicsDevice.BlendState = BlendStateOffscreen;

        offscreenBuffer = renderTargetPool.Obtain2D(
          new RenderTargetFormat(width, height, false, context.RenderTarget.Format, DepthFormat.None));
        graphicsDevice.SetRenderTarget(offscreenBuffer);
        graphicsDevice.Clear(Color.Black);

        // Get half-res depth buffer.
        object obj;
        if (context.Data.TryGetValue(RenderContextKeys.DepthBufferHalf, out obj)
            && obj is Texture2D)
        {
          depthBufferHalf = (Texture2D)obj;
          _parameterGBuffer0.SetValue(depthBufferHalf);
        }
        else
        {
          string message = "Downsampled depth buffer is not set in render context. (The downsampled "
                             + "depth buffer (half width and height) is required by the VolumetricLightRenderer "
                             + "to use half-res off-screen rendering. It needs to be stored in "
                             + "RenderContext.Data[RenderContextKeys.DepthBufferHalf].)";
          throw new GraphicsException(message);
        }
      }

      // Set global effect parameters.
      _parameterViewportSize.SetValue(new Vector2(width, height));

      var isHdrEnabled = context.RenderTarget != null && context.RenderTarget.Format == SurfaceFormat.HdrBlendable;

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

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

        // Effect parameters for volumetric light properties.
        _parameterColor.SetValue((Vector3)node.Color / node.NumberOfSamples);
        _parameterNumberOfSamples.SetValue(node.NumberOfSamples);
        _parameterLightTextureMipMap.SetValue((float)node.MipMapBias);

        // The volumetric light effect is created for the parent light node.
        var lightNode = node.Parent as LightNode;
        if (lightNode == null)
          continue;

        Pose lightPose = lightNode.PoseWorld;

        // Get start and end depth values of light AABB in view space.
        var lightAabbView = lightNode.Shape.GetAabb(lightNode.ScaleWorld, view * lightPose);
        var startZ = Math.Max(-lightAabbView.Maximum.Z, near) / far;
        var endZ = Math.Min(-lightAabbView.Minimum.Z / far, 1);
        _parameterDepthInterval.SetValue(new Vector2(startZ, endZ));

        // Get a rectangle that covers the light in screen space.
        var rectangle = GraphicsHelper.GetScissorRectangle(cameraNode, new Viewport(0, 0, width, height), lightNode);
        var texCoordTopLeft = new Vector2F(rectangle.Left / (float)width, rectangle.Top / (float)height);
        var texCoordBottomRight = new Vector2F(rectangle.Right / (float)width, rectangle.Bottom / (float)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);

        Vector2 randomSeed = AnimateNoise ? new Vector2((float)MathHelper.Frac(context.Time.TotalSeconds))
                                          : new Vector2(0);
        _parameterRandomSeed.SetValue(randomSeed);

        // Set light parameters and apply effect pass.
        if (lightNode.Light is PointLight)
        {
          var light = (PointLight)lightNode.Light;

          float hdrScale = isHdrEnabled ? light.HdrScale : 1;
          _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
          _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
          _parameterLightRange.SetValue(light.Range);
          _parameterLightAttenuation.SetValue(light.Attenuation);

          bool hasTexture = (light.Texture != null);
          if (hasTexture)
          {
            _parameterLightTexture.SetValue(light.Texture);

            // 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);
            _parameterLightTextureMatrix.SetValue((Matrix)(mirrorZ * lightPose.Inverse));
          }

          if (hasTexture)
          {
            if (light.Texture.Format == SurfaceFormat.Alpha8)
              _passPointLightTextureAlpha.Apply();
            else
              _passPointLightTextureRgb.Apply();
          }
          else
          {
            _passPointLight.Apply();
          }
        }
        else if (lightNode.Light is Spotlight)
        {
          var light = (Spotlight)lightNode.Light;

          float hdrScale = isHdrEnabled ? light.HdrScale : 1;
          _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
          _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
          _parameterLightRange.SetValue(light.Range);
          _parameterLightAttenuation.SetValue(light.Attenuation);
          _parameterLightDirection.SetValue((Vector3)lightPose.ToWorldDirection(Vector3F.Forward));
          _parameterLightAngles.SetValue(new Vector2(light.FalloffAngle, light.CutoffAngle));

          bool hasTexture = (light.Texture != null);
          if (hasTexture)
          {
            _parameterLightTexture.SetValue(light.Texture);

            var proj = Matrix44F.CreatePerspectiveFieldOfView(light.CutoffAngle * 2, 1, 0.1f, 100);
            _parameterLightTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * proj * (lightPose.Inverse * new Pose(cameraPose.Position))));
          }

          if (hasTexture)
          {
            if (light.Texture.Format == SurfaceFormat.Alpha8)
              _passSpotlightTextureAlpha.Apply();
            else
              _passSpotlightTextureRgb.Apply();
          }
          else
          {
            _passSpotlight.Apply();
          }
        }
        else if (lightNode.Light is ProjectorLight)
        {
          var light = (ProjectorLight)lightNode.Light;

          float hdrScale = isHdrEnabled ? light.HdrScale : 1;
          _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
          _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
          _parameterLightRange.SetValue(light.Projection.Far);
          _parameterLightAttenuation.SetValue(light.Attenuation);

          _parameterLightTexture.SetValue(light.Texture);

          _parameterLightTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * light.Projection * (lightPose.Inverse * new Pose(cameraPose.Position))));

          if (light.Texture.Format == SurfaceFormat.Alpha8)
            _passProjectorLightTextureAlpha.Apply();
          else
            _passProjectorLightTextureRgb.Apply();
        }
        else
        {
          continue;
        }

        // Draw a screen space quad covering the light.
        graphicsDevice.DrawQuad(rectangle);
      }

      _parameterGBuffer0.SetValue((Texture)null);
      _parameterLightTexture.SetValue((Texture)null);

      if (offscreenBuffer != null)
      {
        // ----- Combine off-screen buffer with scene.
        graphicsDevice.BlendState = BlendState.Opaque;

        // The previous scene render target is bound as texture.
        // --> Switch scene render targets!
        var sceneRenderTarget = context.RenderTarget;
        var renderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(sceneRenderTarget));
        context.SourceTexture = offscreenBuffer;
        context.RenderTarget = renderTarget;

        // Use the UpsampleFilter, which supports "nearest-depth upsampling".
        // (Nearest-depth upsampling is an "edge-aware" method that tries to
        // maintain the original geometry and prevent blurred edges.)
        if (_upsampleFilter == null)
        {
          _upsampleFilter = new UpsampleFilter(graphicsService);
          _upsampleFilter.Mode = UpsamplingMode.NearestDepth;
          _upsampleFilter.RebuildZBuffer = true;
        }

        _upsampleFilter.DepthThreshold = DepthThreshold;
        context.SceneTexture = sceneRenderTarget;

        _upsampleFilter.Process(context);

        context.SceneTexture = null;
        context.SourceTexture = null;
        renderTargetPool.Recycle(offscreenBuffer);
        renderTargetPool.Recycle(sceneRenderTarget);
      }

      // Restore render states.
      graphicsDevice.RasterizerState = originalRasterizerState;
      graphicsDevice.DepthStencilState = originalDepthStencilState;
      graphicsDevice.BlendState = originalBlendState;
    }
Exemplo n.º 3
0
        private void PostProcess(RenderContext context, RenderTarget2D source, RenderTarget2D target)
        {
            Debug.Assert(source != null);
              Debug.Assert(target != null);

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

              if (Filter != null && Filter.Enabled)
              {
            context.SourceTexture = source;
            context.RenderTarget = source;
            context.Viewport = new Viewport(0, 0, source.Width, source.Height);
            Filter.Process(context);
              }

              bool doUpsampling = UseHalfResolution && Numeric.IsGreater(UpsampleDepthSensitivity, 0);

              Debug.Assert(doUpsampling && source != target || !doUpsampling && source == target);

              if (doUpsampling)
              {
            if (_upsampleFilter == null)
              _upsampleFilter = _graphicsService.GetUpsampleFilter();

            var graphicsDevice = _graphicsService.GraphicsDevice;
            var originalBlendState = graphicsDevice.BlendState;
            graphicsDevice.BlendState = BlendState.Opaque;

            // The previous scene render target is bound as texture.
            // --> Switch scene render targets!
            context.SourceTexture = source;
            context.RenderTarget = target;
            context.Viewport = new Viewport(0, 0, target.Width, target.Height);
            _upsampleFilter.DepthSensitivity = UpsampleDepthSensitivity;
            _upsampleFilter.Mode = UpsamplingMode.Bilateral;
            _upsampleFilter.RebuildZBuffer = false;
            _upsampleFilter.Process(context);

            if (originalBlendState != null)
              graphicsDevice.BlendState = originalBlendState;
              }

              context.SourceTexture = originalSourceTexture;
              context.RenderTarget = originalRenderTarget;
              context.Viewport = originalViewport;
        }
Exemplo n.º 4
0
        internal static UpsampleFilter GetUpsampleFilter(this IGraphicsService graphicsService)
        {
            if (graphicsService == null)
            throw new ArgumentNullException("graphicsService");

              const string Key = "__UpsampleFilter";
              object obj;
              graphicsService.Data.TryGetValue(Key, out obj);
              var instance = obj as UpsampleFilter;
              if (instance == null)
              {
            instance = new UpsampleFilter(graphicsService);
            graphicsService.Data[Key] = instance;
              }

              return instance;
        }