zoukankan      html  css  js  c++  java
  • DirectX12 Samples 学习笔记 – PredicationQueries

    一、效果

    这是一个比较简单的sample,运行sample可以看到,当红橙色长方形完全覆盖白色正方形时,白色正方形不显示,其他情况,均显示白色正方形。

    二、实现

    Render主要由三个部分组成

    1.Far quad
    2.Near quad Far
    3.Quad bounding box

    2和3都是是无论如何都要画的。在画3的时候,会进行一个Query,看3是不是所有的pixel都没有通过depth test(即是否被2全部覆盖)。根据上一帧Query的结果看是否画1,如果全部覆盖则不画1,否则画1。

    程序逻辑如下:

    1. 设置FarQuad的CBV(Constant Buffer View),根据上一帧Query的结果来SetPredication,画FarQuad;

    2. SetPredication(NULL),设置NearQuad的CBV,画NearQuad;

    3. 设置BoundingBox的CBV,为Query设置PSO(Pipeline State Object),BeginQuery – 画BoundingBox – EndQuery,导出Query的结果。

    三、代码

    首先要介绍一下API:

    void SetPredication(
      [in, optional] ID3D12Resource       *pBuffer,
      [in]           UINT64               AlignedBufferOffset,
      [in]           D3D12_PREDICATION_OP Operation
    );

    官方SDK上面也有介绍,这里就简单说下,这个API表示,如果pBuffer里的数据满足Operation(=0或≠0),则后面的Rendering以及Resource操作都不会生效。如果pBuffer = NULL,则Predication被Disable掉(失效)。

    Query的用法跟以前类似,需要注意的是,现在的SDK要求,除非Query type为TIMESTAMP,否则BeginQuery和EndQuery必须成对出现。

    下面就来看一下代码。和这些samples相关的框架以及一些基本的API就不再赘述了,这里主要就介绍一下和PredicationQueries相关的代码。

    D3D12PredicationQueries::LoadPipeline()

    创建QueryHeap,类型为OCCLUSION,就是用来Query通过depth test的点的个数。

    // Describe and create a heap for occlusion queries.
    D3D12_QUERY_HEAP_DESC queryHeapDesc = {};
    queryHeapDesc.Count = 1;
    queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_OCCLUSION;
    ThrowIfFailed(m_device->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&m_queryHeap)));

    void D3D12PredicationQueries::LoadAssets()

    为了能看到红橙色长方形下面是否画了白色正方形,必须打开Alpha blend

    // Enable alpha blending so we can visualize the occlusion query results.
    CD3DX12_BLEND_DESC blendDesc(D3D12_DEFAULT);
    blendDesc.RenderTarget[0] =
    {
        TRUE, FALSE,
        D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
        D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
        D3D12_LOGIC_OP_NOOP,
        D3D12_COLOR_WRITE_ENABLE_ALL,
    };

    在画Bounding box的时候,只是为了做Occlusion Query,因此不需要把render结果写到RT(RenderTarget)和DS(Depth Stencil)里面去。

    // Disable color writes and depth writes for the occlusion query's state.
    psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0;
    psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
     
    ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_queryState)));

    void D3D12PredicationQueries::OnUpdate()里面主要就是去更新红橙色长方形的CBV(即它的位置),因为它以一个速度从左至右移动。

    void D3D12PredicationQueries::PopulateCommandList()

    这里就是按照之前介绍的逻辑进行Render。

    CD3DX12_GPU_DESCRIPTOR_HANDLE cbvFarQuad(m_cbvHeap->GetGPUDescriptorHandleForHeapStart(), m_frameIndex * CbvCountPerFrame, m_cbvSrvDescriptorSize);
    CD3DX12_GPU_DESCRIPTOR_HANDLE cbvNearQuad(cbvFarQuad, m_cbvSrvDescriptorSize);
     
    m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
     
    // Draw the far quad conditionally based on the result of the occlusion query
    // from the previous frame.
    m_commandList->SetGraphicsRootDescriptorTable(0, cbvFarQuad);
    m_commandList->SetPredication(m_queryResult.Get(), 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
    m_commandList->DrawInstanced(4, 1, 0, 0);
     
    // Disable predication and always draw the near quad.
    m_commandList->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
    m_commandList->SetGraphicsRootDescriptorTable(0, cbvNearQuad);
    m_commandList->DrawInstanced(4, 1, 4, 0);
     
    // Run the occlusion query with the bounding box quad.
    m_commandList->SetGraphicsRootDescriptorTable(0, cbvFarQuad);
    m_commandList->SetPipelineState(m_queryState.Get());
    m_commandList->BeginQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0);
    m_commandList->DrawInstanced(4, 1, 8, 0);
    m_commandList->EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0);
     
    // Resolve the occlusion query and store the results in the query result buffer
    // to be used on the subsequent frame.
    m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_queryResult.Get(), D3D12_RESOURCE_STATE_PREDICATION, D3D12_RESOURCE_STATE_COPY_DEST));
    m_commandList->ResolveQueryData(m_queryHeap.Get(), D3D12_QUERY_TYPE_BINARY_OCCLUSION, 0, 1, m_queryResult.Get(), 0);
    m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_queryResult.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D

    从上面的代码可以看到,最后一个Draw实际上就是去Query通过Depth test的点的个数,ResolveQueryData会将Query的结果Resolve到一块buffer里面。Query Type为D3D12_QUERY_TYPE_BINARY_OCCLUSION表示Query结果只有两种:0表示点通过depth stencil test,1表示至少有一个点通过。也就是说在下一帧Draw far quad之前,会根据这个buffer里面的结果是否等于0来SetPredication。如果结果为0,表示上一帧的长方形完全覆盖住白色正方形,则后面的Draw失效,不画白色正方形。

    话说有个问题就是,为什么不把Draw bounding box放在最前面?那样就可以实时的判断当前帧是否需要画白色正方形。不知道放在后面,让下一帧再去判断是什么意思。

  • 相关阅读:
    java表格的使用 单元格绘制二
    Java表格的简单使用一
    Servlet接口五种方法介绍
    C# 图片识别
    asp.net 使用rabbitmq事例
    Windows下安装使用python的Flask框架
    python中闭包的理解
    sql中遍历字符串
    asp.net mvc easyui tree
    c# Castle Windsor简单例子
  • 原文地址:https://www.cnblogs.com/lvrcbl/p/6255156.html
Copyright © 2011-2022 走看看