Esempio n. 1
0
        protected internal override void Execute(ParallelizationProvider pp)
        {
            // See if we need to resize the light plane and get the new GBuffer
            Camera        input;
            SceneViewport output;

            Texture2D <TexelFormat.RGBA32Float>[] currentGBuffer;
            geometryPass.GetLightPassParameters(out currentGBuffer, out input, out output);
            Vector2 outputSizePixels = output.SizePixels;

            if (outputSizePixels.X <= 0f || outputSizePixels.Y <= 0f)
            {
                return;
            }
            RenderTargetViewHandle windowRTV; DepthStencilViewHandle windowDSV;
            bool windowStillOpen = output.TargetWindow.GetWindowRTVAndDSV(out windowRTV, out windowDSV);

            if (!windowStillOpen)
            {
                return;
            }
            CheckGeometryPassParameters(currentGBuffer, outputSizePixels);

            // Clear the bloom textures
            QueueRenderCommand(RenderCommand.ClearRenderTarget(preBloomBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(reducedBloomBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(bloomTargetBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(nonDepthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(reducedNonDepthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(depthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearDepthStencil(bloomResizeCopyDSDSV));
            QueueRenderCommand(RenderCommand.ClearDepthStencil(dsThrowawayBufferDSV));

            // Set topology
            QueueRenderCommand(RenderCommand.SetPrimitiveTopology(RenderCommand.DEFAULT_PRIMITIVE_TOPOLOGY));

            // Set input layout
            QueueRenderCommand(RenderCommand.SetInputLayout(lightPlaneInputLayout));

            // Enqueue VS commands
            QueueShaderSwitch(dlLightVS);
            QueueShaderResourceUpdate(dlLightVS, vsResPackage);

            /* =======================================
             * STAGE: DYNAMIC LIGHTING APPLICATION
             * ======================================= */

            // Enqueue FS commands
            Vector4 cameraPos = input.Position;

            ((ConstantBufferBinding)dlLightFS.GetBindingByIdentifier("CameraProperties")).SetValue((byte *)(&cameraPos));
            QueueShaderSwitch(dlLightFS);

            // Set rasterizer state
            QueueRenderCommand(RenderCommand.SetRasterizerState(rsState));
            QueueRenderCommand(RenderCommand.SetViewport(output));

            // Set depth stencil state
            QueueRenderCommand(RenderCommand.SetDepthStencilState(dsState));

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(dsThrowawayBufferDSV.ResourceViewHandle, nonDepthOfFieldBackBufferRTV.ResourceViewHandle, preBloomBufferRTV.ResourceViewHandle));

            // Draw lights
            //input = new Camera();
            //input.Position = Vector3.ZERO;
            //input.Orient(Vector3.FORWARD, Vector3.UP);

            var frustum            = input.GetFrustum(output);
            int numLights          = addedLights.Count;
            int numLightsInFrustum = 0;

            for (int i = 0; i < numLights; ++i)
            {
                if (!frustum.IsWithinFrustum(new Sphere(addedLights[i].Position, addedLights[i].Radius)))
                {
                    continue;
                }
                lightPropsWorkspace[numLightsInFrustum++] = addedLights[i].Properties;
            }
            if (numLightsInFrustum > dynamicLightCap)
            {
                dynamicLightComparer.CameraPosition = input.Position;
                Array.Sort(lightPropsWorkspace, 0, numLightsInFrustum, dynamicLightComparer);
                numLightsInFrustum = dynamicLightCap;
            }

            Buffer <LightProperties> lightBuffer = (Buffer <LightProperties>)(((ResourceViewBinding)dlLightFS.GetBindingByIdentifier("LightBuffer")).GetBoundResource().Resource);
            var lightMetaCBuffer = (ConstantBufferBinding)dlLightFS.GetBindingByIdentifier("LightMeta");

            QueueShaderResourceUpdate(dlLightFS, fsResPackage);

            Array.Clear(perTileLightPropCounts, 0, perTileLightPropCounts.Length);



            Vector3 upDir          = input.UpDirection;
            Vector3 downDir        = -input.UpDirection;
            Vector3 rightDir       = upDir.Cross(input.Orientation);
            Vector3 leftDir        = -rightDir;
            var     worldToProjMat = (*((Matrix *)input.GetRecalculatedViewMatrix()) * *((Matrix *)output.GetRecalculatedProjectionMatrix(input)));

            for (int i = 0; i < numLightsInFrustum; ++i)
            {
                var lightProps = lightPropsWorkspace[i];
                //lightProps = new LightProperties(
                //	Vector3.LEFT + Vector3.BACKWARD, 3f, Vector3.ONE
                //);
                var lightCentre    = lightProps.Position;
                var lightTop       = new Vector4(lightCentre + upDir * lightProps.Radius, w: 1f);
                var lightBottom    = new Vector4(lightCentre + downDir * lightProps.Radius, w: 1f);
                var lightLeftmost  = new Vector4(lightCentre + leftDir * lightProps.Radius, w: 1f);
                var lightRightmost = new Vector4(lightCentre + rightDir * lightProps.Radius, w: 1f);

                var lightTopProjspace       = lightTop * worldToProjMat;
                var lightBottomProjspace    = lightBottom * worldToProjMat;
                var lightLeftmostProjspace  = lightLeftmost * worldToProjMat;
                var lightRightmostProjspace = lightRightmost * worldToProjMat;

                var lightTopScreenSpace       = lightTopProjspace / Math.Abs(lightTopProjspace.W);
                var lightBottomScreenSpace    = lightBottomProjspace / Math.Abs(lightBottomProjspace.W);
                var lightLeftmostScreenSpace  = lightLeftmostProjspace / Math.Abs(lightLeftmostProjspace.W);
                var lightRightmostScreenSpace = lightRightmostProjspace / Math.Abs(lightRightmostProjspace.W);

                var xMin = ((float)MathUtils.Clamp(lightLeftmostScreenSpace.X, -1f, 1f) + 1f) * 0.5f;
                var xMax = ((float)MathUtils.Clamp(lightRightmostScreenSpace.X, -1f, 1f) + 1f) * 0.5f;
                var yMin = ((float)MathUtils.Clamp(lightBottomScreenSpace.Y, -1f, 1f) + 1f) * 0.5f;
                var yMax = ((float)MathUtils.Clamp(lightTopScreenSpace.Y, -1f, 1f) + 1f) * 0.5f;

                for (int x = 0; x < LIGHTING_TILE_GRANULARITY; ++x)
                {
                    for (int y = 0; y < LIGHTING_TILE_GRANULARITY; ++y)
                    {
                        var tileXMin = tileOffsetsX[x];
                        var tileXMax = tileOffsetsX[x + 1];
                        var tileYMin = tileOffsetsY[y];
                        var tileYMax = tileOffsetsY[y + 1];

                        if (xMax < tileXMin ||
                            xMin > tileXMax ||
                            yMax < tileYMin ||
                            yMin > tileYMax)
                        {
                            continue;
                        }

                        var bucketIndex = x * LIGHTING_TILE_GRANULARITY + y;
                        perTileLightPropsWorkspace[bucketIndex][perTileLightPropCounts[bucketIndex]++] = lightProps;
                    }
                }
            }

            for (int x = 0; x < LIGHTING_TILE_GRANULARITY; ++x)
            {
                for (int y = 0; y < LIGHTING_TILE_GRANULARITY; ++y)
                {
                    var bucketIndex         = x * LIGHTING_TILE_GRANULARITY + y;
                    var numLightsOnThisTile = perTileLightPropCounts[bucketIndex];

                    if (numLightsOnThisTile == 0)
                    {
                        continue;
                    }

                    var scalars = new Vector4(tileOffsetsX[x], tileOffsetsX[x + 1], tileOffsetsY[y], tileOffsetsY[y + 1]);                     // 0f to 1f, from bottom left corner
                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(
                                           lightBuffer,
                                           new ArraySlice <LightProperties>(perTileLightPropsWorkspace[bucketIndex], 0U, (uint)numLightsOnThisTile),
                                           (uint)sizeof(LightProperties)
                                           ));
                    int *numLightsWithPadding = stackalloc int[4];
                    numLightsWithPadding[0] = numLightsOnThisTile;

                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightMetaCBuffer, (IntPtr)(numLightsWithPadding)));

                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightVSScalarsBufferBinding, (IntPtr)(&scalars)));
                    QueueRenderCommand(RenderCommand.Draw(0, 3U));
                    QueueRenderCommand(RenderCommand.Draw(3, 3U));
                }
            }



            // Unbind gbuffer
            QueueShaderResourceUpdate(dlLightFS, fsUnbindResPackage);

            /* =======================================
             * STAGE: ADD AMBIENT LIGHT (DL FINAL)
             * ======================================= */

            // Switch to finalization shader
            var scalarsFinal = new Vector4(0f, 1f, 0f, 1f);

            QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightVSScalarsBufferBinding, (IntPtr)(&scalarsFinal)));
            QueueShaderSwitch(dlFinalFS);
            QueueShaderResourceUpdate(dlFinalFS, finalizationShaderResPackage);

            // Draw finalization triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(dlFinalFS, finalizationShaderUnbindResPackage);

            /* =======================================
             * STAGE: OUTLINING
             * ======================================= */

            // Switch to outlining shader
            QueueShaderSwitch(outliningShader);
            QueueShaderResourceUpdate(outliningShader, outliningShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(outliningBlendState));

            // Draw outlining triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(outliningShader, outliningShaderUnbindResPackage);

            /* =======================================
             * STAGE: DOWNSCALE PRE-BLOOM BUFFER TEX
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, reducedBloomBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(copyShader);
            QueueShaderResourceUpdate(copyShader, copyShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyShader, copyShaderUnbindResPackage);

            /* =======================================
             * STAGE: BLOOM RENDER TO BLOOM TARGET
             * ======================================= */

            // Clear DSV
            QueueRenderCommand(RenderCommand.ClearDepthStencil(bloomResizeCopyDSDSV));

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, bloomTargetBufferRTV));

            // Switch to bloom H shader
            QueueShaderSwitch(bloomHShader);
            QueueShaderResourceUpdate(bloomHShader, bloomHShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(bloomHShader, bloomHShaderUnbindResPackage);

            // Switch to bloom V shader
            QueueShaderSwitch(bloomVShader);
            QueueShaderResourceUpdate(bloomVShader, bloomVShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(bloomVShader, bloomVShaderUnbindResPackage);

            /* =======================================
             * STAGE: COPY BLOOM RESULT ON TO NON-DoF BUFFER
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(dsThrowawayBufferDSV.ResourceViewHandle, nonDepthOfFieldBackBufferRTV));

            // Switch to reverse copy shader
            QueueShaderSwitch(copyReverseShader);
            QueueShaderResourceUpdate(copyReverseShader, copyReverseShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyReverseShader, copyReverseShaderUnbindResPackage);

            /* =======================================
             * STAGE: DOWNSCALE NON-DoF SCENE
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, reducedNonDepthOfFieldBackBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(copyShader);
            QueueShaderResourceUpdate(copyShader, copyDoFShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyShader, copyDoFShaderUnbindResPackage);

            /* =======================================
             * STAGE: BLUR NON-DoF SCENE
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, depthOfFieldBackBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(blurShader);
            QueueShaderResourceUpdate(blurShader, blurShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(blurShader, blurShaderUnbindResPackage);

            /* =======================================
             * STAGE: RENDER TO BACK BUFFER WITH DoF SELECTION
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(windowDSV, windowRTV));

            // Switch to copy shader
            QueueShaderSwitch(dofShader);
            QueueShaderResourceUpdate(dofShader, dofShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(dofShader, dofShaderUnbindResPackage);



            // Flush + present
            FlushRenderCommands();
            if (presentAfterPass)
            {
                PresentBackBuffer(output.TargetWindow);
            }
        }