===================== 编辑:解决方案=====================
我终于找到了问题所在,因为答案对于正在学习 DirectX 的初学者可能很重要,所以我将其发布在这里。(我使用 F# 和 SharpDX 作为 DirectX 的 .NET 包装器)
在我的程序中,资源(缓冲区、视图等)仅在调整交换链大小时发生变化。所以我把所有的资源分配(IA、OM、VS、PS)放到一个函数switchTo2DLayout
中。如果交换链没有switchTo2DLayout
调整大小,则立即返回(不做任何事情)。这是由一个标志控制的。
后来我发现这个标志从未被重置,因此资源分配是在每次绘制调用之前完成的。我纠正了这个错误,但现在图像仅在第一次调用renderPixels
. 事实证明,我必须在绘制调用之前设置ShaderresourceView
每次。
let renderPixels () =
switchTo2DLayout()
// this line was missing:
context.PixelShader.SetShaderResource(COUNT_COLOR_SLOT, countColorSRV_2D)
context.ClearRenderTargetView (renderTargetView2D, Color.White.ToColor4())
context.Draw(4,0)
swapChain.Present(1, PresentFlags.None)
这完全出乎我的意料。我使用的有关 DirectX 的书籍从未明确说明哪些资源可以分配一次(只要不更改设置),哪些资源必须在每次绘制调用时分配。
对于网格渲染,我使用了类似的设置(这里没有我提到的错误),同样缺少等效的行:
let draw3D() =
switchTo3DLayout()
// this line was missing:
context.VertexShader.SetShaderResource(TRIANGLE_SLOT, triangleSRV )
context.ClearDepthStencilView(depthView3D, DepthStencilClearFlags.Depth, 1.0f, 0uy
context.ClearRenderTargetView(renderTargetView2D, Color4.Black )
context.Draw(triangleCount, 0)
swapChain.Present(1, PresentFlags.None)
这解释了为什么 2D 渲染因为这个错误(像素着色器从缓冲区读取)而工作,而 3D 没有(顶点着色器从缓冲区读取)。
======================= 我的原帖:=================
几天前,我发布了一个问题 [链接:]如何使用顶点缓冲区将计算着色器结果输入到顶点着色器中?这可能太复杂而无法回答。同时,我将设置简化为一个更简单的情况:
struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
RWStructuredBuffer<float4> colorOutputTable : register (u5);
StructuredBuffer<float4> output2 : register (t5);
案例 A:像素着色器设置颜色(有效)
// vertex shader A
PS_IN VS_A ( uint vid : SV_VertexID )
{
PS_IN output = (PS_IN)0;
if (vid == 0) output.pos = float4(-1, -1, 0, 1);
if (vid == 1) output.pos = float4( 1, -1, 0, 1);
if (vid == 2) output.pos = float4(-1, 1, 0, 1);
if (vid == 3) output.pos = float4( 1, 1, 0, 1);
return output;
}
// pixel shader A
float4 PS_A ( float4 input : SV_Position) : SV_Target
{
uint2 pixel = uint2(input.x, input.y);
return output2[ pixel.y * width + pixel.x]; // PS accesses buffer (works)
}
案例 B:顶点着色器设置颜色(不起作用)
// vertex shader B
PS_IN VS_B ( uint vid : SV_VertexID )
{
PS_IN output = (PS_IN)0;
if (vid == 0) output.pos = float4(-1, -1, 0, 1);
if (vid == 1) output.pos = float4( 1, -1, 0, 1);
if (vid == 2) output.pos = float4(-1, 1, 0, 1);
if (vid == 3) output.pos = float4( 1, 1, 0, 1);
output.col = output2[vid]; // VS accesses buffer (does not work)
return output;
}
// pixel shader B
float4 PS_B (PS_IN input ) : SV_Target
{
return input.col;
}
显然,像素着色器可以访问“output2”缓冲区,而顶点着色器不能(读取始终为零)。
在互联网上搜索我找不到这种行为的任何解释。在我的“真实”应用程序中,计算着色器计算一个三角形列表并将其存储在 RWStructuredBuffer 中,因此我需要从顶点着色器(通过映射槽)访问该表。
我想许多使用计算着色器的人可能会偶然发现这个问题。知道如何解决这个问题吗?(我目前用不了Level 11.1或者11.2,得找个基于11.0的解决方案)