繁体   English   中英

顶点着色器中的采样返回缓冲区始终返回0和float1而不是float4

[英]Sampling Back Buffer in vertex Shader always returns 0 and float1 instead of float4

我现在完全迷路了。 几天来一直在尝试读取顶点着色器中的backbuffer,但没有任何运气。

我正在尝试从后缓冲区及其附近的像素读取顶点位置。 (我试图计算顶点周围有多少个黑色像素,以及像素着色器中是否有顶点红色的颜色)。 我创建了一个单独的ID3D11Texture2D和一个SRV与backBuffer一起使用。 我将后缓冲区复制到此SRV的资源中。 使用VSSetShaderResources绑定SRV,但似乎无法从顶点着色器中读取SRV。

我将在此处分享这些元素的创建过程中的一些代码,以及一些RenderDoc屏幕快照,这些屏幕快照始终显示SRV已绑定到VS舞台并具有正确的纹理,但每个Load或[] operator或tex2dlod或SampleLevel(我也绑定了SamplerState)仅保持返回一个1.0值,而其余的float4则永不返回,这意味着我只能获得一个float1。 如果有人想看看,我还将提供一个renderdoc捕获文件。

这是rastertek.com网站上的教程42中的一个简单场景,上面有一个带有立方体和球体的地平面:

https://i.imgur.com/cbVC48E.gif

// Here is some code when creating the secondary texture and SRV that houses a //backBuffer
// Get the pointer to the back buffer.
    result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
    if(FAILED(result))
    {
        MessageBox((*(hwnd)), L"Get the pointer to the back buffer FAILED", L"Error", MB_OK);
        return false;
    }


    // Create another texture2d that we will use to make an SRV out of, and this texture2d will be used to copy the backbuffer to so we can read it in a shader
    D3D11_TEXTURE2D_DESC bbDesc;
    backBufferPtr->GetDesc(&bbDesc);
    bbDesc.MipLevels = 1;
    bbDesc.ArraySize = 1;
    bbDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    bbDesc.Usage = D3D11_USAGE_DEFAULT;
    bbDesc.MiscFlags = 0;
    bbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    result = m_device->CreateTexture2D(&bbDesc, NULL, &m_backBufferTx2D);
    if (FAILED(result))
    {
        MessageBox((*(m_hwnd)), L"Create a Tx2D for backbuffer SRV FAILED", L"Error", MB_OK);
        return false;
    }
    D3D11_SHADER_RESOURCE_VIEW_DESC descSRV;
    ZeroMemory(&descSRV, sizeof(descSRV));
    descSRV.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    descSRV.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    descSRV.Texture2D.MipLevels = 1;
    descSRV.Texture2D.MostDetailedMip = 0;
    result = GetDevice()->CreateShaderResourceView(m_backBufferTx2D, &descSRV, &m_backBufferSRV);
    if (FAILED(result))
    {
        MessageBox((*(m_hwnd)), L"Creating BackBuffer SRV FAILED.", L"Error", MB_OK);
        return false;
    }

    // Create the render target view with the back buffer pointer.
    result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);

首先,我将场景渲染为全白,然后将其复制到SRV,并将其绑定到应该采样的下一个着色器。 当我在屏幕上的顶点位置采样后缓冲时,我期望返回一个float4(1.0,1.0,1.0,1.0)值

https://i.imgur.com/N9CYg8c.png

如事件浏览器左上角所示,有三个drawindexed调用以白色呈现所有内容,然后是CopyResource。 我选择了下一个(第四个)DrawIndexed,并在右侧用红色勾勒出了下一个着色器的输入,清楚地表明backBuffer已成功绑定到顶点着色器。

现在让我麻烦的部分

https://i.imgur.com/ENuXk0n.png

我将如屏幕截图所示调试该左上角的顶点,该顶点着色器具有Texture2D prevBackBuffer:register(t0); 写在顶部

https://i.imgur.com/8cihNsq.png

当尝试采样左相邻像素时,此代码行在纹理视图中输入这些像素值时返回newCoord = float2(158,220),我得到了这个像素

https://i.imgur.com/DT72Fl1.png

因此到目前为止,坐标还可以,并且如概述所示,我希望在我对该像素进行采样时得到一个float4(0.0、0.0、0.0、1,0)返回(我正在尝试计算一个像素周围有多少个黑色像素)顶点,以及像素着色器中是否有任何顶点为红色的颜色)

而且,当我在更改像素坐标后立即采样该像素时,因为负载从左下角开始计数像素,所以我需要newCoord = float2(158,379),我得到了

https://i.imgur.com/8SuwOzz.png

为什么会这样,即使超出范围,负载也应返回全零,因为我不确定从左下角开始的总负载计数,因此我尝试使用左上角坐标(158,220)进行采样,但最终得到0.0 ,?,?,?

我完全迷住了,不知道下一步该怎么做。 我试过使用示例状态:

// Create a clamp texture sampler state description.
    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 1;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    // Create the texture sampler state.
    result = device->CreateSamplerState(&samplerDesc, &m_sampleStateClamp);

但在读取纹理时仍永远不会返回正确的float4。

任何想法,建议,在这一点上我都会采取任何措施。 哦,这是我正在检查的框架的RenderDoc文件: http : //www.mediafire.com/file/1bfiqdpjkau4l0n/my_capture.rdc/file

因此,以我的经验来看,从后台缓冲区读取并不是真正要首先执行的操作。 如果必须对渲染的场景进行任何操作,最好的方法是将场景渲染为中间纹理,对该纹理执行操作,然后将最终的场景渲染到后台缓冲区。 通常这是完成动态阴影之类的方式-从灯光的角度渲染场景,然后解释生成的缓冲区以获取阴影值,然后将其应用于最终场景(这也是为什么动态光源是受限于商业游戏引擎-使用起来相当昂贵)。

类似的想法可以在这里应用。 首先,将整个场景渲染为中间纹理,绑定为渲染目标视图(其中像素格式由您( 程序员 )指定)。 接下来,将中间纹理重新绑定为着色器资源视图,并使用边缘检测着色器和实际的后缓冲区(其中像素格式由硬件定义)再次渲染场景。

从根本上讲,这就是我认为的问题-后备缓冲区是与设备相关的资源,其格式可以根据硬件而改变。 因此,从着色器使用它并不安全,因为您并不总是知道格式是什么。 另一方面,与设备无关的资源将始终具有相同的格式,并且可以从着色器中随意使用,但可以放心使用。

我无法在顶点着色器中对SRV进行采样,但是我能够使用的是在计算着色器中使用backBuffer.SampleLevel,我还必须将采样器更改为如下所示:

D3D11_SAMPLER_DESC samplerDesc;

samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0.5f;
samplerDesc.BorderColor[1] = 0.5f;
samplerDesc.BorderColor[2] = 0.5f;
samplerDesc.BorderColor[3] = 0.5f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = 0;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM