DirectX11 HLSL 着色器不是 运行
DirectX11 HLSL shaders not running
我完全不熟悉使用 DirectX 进行 3D 绘图,因此,我想学习它的基础知识,因此,我尝试混合使用我在网上偶然发现的每个示例。
我的第一个 objective 是简单地在屏幕上画几条线,但到目前为止,我唯一能意识到的是用一些不同的颜色清除屏幕...
为了绘制我的2D线,我实际上使用了HLSL顶点和像素着色器,由Visual Studio的2015版本直接编译成cso文件。 (我最初在使用像素着色器时遇到了问题,但设法发现必须设置它的属性)
当我使用 Visual Studio 图形 Analyzer/Debugger 时,我可以看到 IA 步骤 似乎 在绘制线条时是正确的。但是在这一步之后,尽管我可以在顶点着色器中逐步调试并且我在位置和颜色参数中看到了正确的值,但我什么也看不到了。
这里的主要问题是:
- 在像素历史记录中,我看不到对 deviceContext 发出的任何 Draw() 调用。我只能看到 ClearRenderTarget()
- 像素着色器显示消息“舞台没有运行。没有输出”
我不知道这个过程有什么问题,world/view/projection矩阵或depthStencilView是强制性的吗?我是否忘记为交换链和管道提供特定的缓冲区?我试图在 rasterState 对象中禁用深度、剪刀和剔除,但我不能确定。
我为我的顶点使用了一个结构,它是:
#define LINES_NB 1000
struct Point
{
float x, y, z, rhw;
float r, g, b, a;
} lineList[LINES_NB];
最后,这里是 VERTEX SHADER 的代码:
struct VIn
{
float4 position : POSITION;
float4 color : COLOR;
};
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut main(VIn input)
{
VOut output;
output.position = input.position;
output.color = input.color;
return output;
}
我用以下行编译:
/Zi /E"main" /Od /Fo"E:\PATH\VertexShader.cso" /vs"_5_0" /nologo
像素着色器的代码如下:
struct PIn
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
float4 main(PIn input) : SV_TARGET
{
return input.color;
}
我使用以下行编译:
/Zi /E"main" /Od /Fo"E:\PATH\PixelShader.cso" /ps"_5_0" /nologo
这是 RASTERIZER STATE 创建部分:
D3D11_RASTERIZER_DESC rasterDesc;
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_NONE;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = false;
rasterDesc.FillMode = D3D11_FILL_WIREFRAME;
rasterDesc.FrontCounterClockwise = true;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
result = _device->CreateRasterizerState(&rasterDesc, &_rasterState);
if (FAILED(result))
{
OutputDebugString("FAILED TO CREATE RASTERIZER STATE.\n");
HR(result);
return -1;
}
_immediateContext->RSSetState(_rasterState);
这是INPUT LAYOUT注册部分(_vertexShaderCode->code包含vertexShader.cso和_vertexShaderCode->size的内容,这些内容的大小):
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
HR(_device->CreateInputLayout(ied, sizeof(ied) / sizeof(D3D11_INPUT_ELEMENT_DESC), _vertexShaderCode->code, _vertexShaderCode->size, &_vertexInputLayout));
_immediateContext->IASetInputLayout(_vertexInputLayout);
其中变量声明为:
struct Shader
{
BYTE *code;
UINT size;
};
ID3D11Device* _device;
ID3D11DeviceContext* _immediateContext;
ID3D11RasterizerState* _rasterState;
ID3D11InputLayout* _vertexInputLayout;
Shader* _vertexShaderCode;
Shader* _pixelShaderCode;
我的 VERTEX BUFFER 是通过调用 createLinesBuffer 一次,然后调用 renderVertice 创建的在每次绘制调用时对其进行映射:
void DxDraw::createLinesBuffer(ID3D11Device* device)
{
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDesc.ByteWidth = sizeof(Point) * LINES_NB;
std::cout << "buffer size : " << sizeof(Point) * LINES_NB << std::endl;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = lineList;
std::cout << "lineList : " << lineList << std::endl;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
HR(device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &_vertexBuffer));
}
void DxDraw::renderVertice(ID3D11DeviceContext* ctx, UINT count, D3D11_PRIMITIVE_TOPOLOGY type)
{
D3D11_MAPPED_SUBRESOURCE ms;
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
// map the buffer
HR(ctx->Map(_vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms));
// copy the data to it
memcpy(ms.pData, lineList, sizeof(lineList));
// unmap it
ctx->Unmap(_vertexBuffer, NULL);
// select which vertex buffer to display
UINT stride = sizeof(Point);
UINT offset = 0;
ctx->IASetVertexBuffers(0, 1, &_vertexBuffer, &stride, &offset);
// select which primtive type we are using
ctx->IASetPrimitiveTopology(type);
// draw the vertex buffer to the back buffer
ctx->Draw(count, 0);
}
这里有很多地方可能出错了,可能你可以检查一下:
- 是否正确声明了输入布局?看起来你的顶点着色器没有得到任何几何体
- 你如何声明你的Rasterizer Stage?有时可能会出现一些问题,例如剔除、深度裁剪等。
- 你的几何形状怎么样?在将几何应用到 Input Assembler 之前,您是否应用了任何 world/view/projection 转换?
- 你是如何构造你的顶点缓冲区的?你Map/Unmap吗?或者,也许您为每个绘图调用都构建了这个?
我不能保证这会有所帮助,但恕我直言,所有这些都值得一试。
至于 Pixel Shader 没有输出,似乎没有任何东西输入它 - 所以一定有 VS 输出或 RS 以某种方式剪切了所有几何体(由于剔除、深度测试等)
Copied from comment, since it solved the issue.
InputLayout 看起来不错,VertexBuffer 看起来也不错。此时,我会检查实际的顶点坐标。从您的屏幕截图来看,您似乎使用了相当大的数字,例如 x = 271,y = 147。通常,这些位置是通过世界视图投影转换进行转换的,因此它们最终以 <-1.0f;1.0f 结束> 范围。由于您没有使用任何转换,我建议更改您的 lineGenerator 函数,以便它在 <-1.0f 内生成几何图形; 1.0f> x 和 y 坐标的范围。 例如,如果您当前的 x 值为 271,则将其设置为 0.271f
我完全不熟悉使用 DirectX 进行 3D 绘图,因此,我想学习它的基础知识,因此,我尝试混合使用我在网上偶然发现的每个示例。
我的第一个 objective 是简单地在屏幕上画几条线,但到目前为止,我唯一能意识到的是用一些不同的颜色清除屏幕...
为了绘制我的2D线,我实际上使用了HLSL顶点和像素着色器,由Visual Studio的2015版本直接编译成cso文件。 (我最初在使用像素着色器时遇到了问题,但设法发现必须设置它的属性)
当我使用 Visual Studio 图形 Analyzer/Debugger 时,我可以看到 IA 步骤 似乎 在绘制线条时是正确的。但是在这一步之后,尽管我可以在顶点着色器中逐步调试并且我在位置和颜色参数中看到了正确的值,但我什么也看不到了。
这里的主要问题是:
- 在像素历史记录中,我看不到对 deviceContext 发出的任何 Draw() 调用。我只能看到 ClearRenderTarget()
- 像素着色器显示消息“舞台没有运行。没有输出”
我不知道这个过程有什么问题,world/view/projection矩阵或depthStencilView是强制性的吗?我是否忘记为交换链和管道提供特定的缓冲区?我试图在 rasterState 对象中禁用深度、剪刀和剔除,但我不能确定。
我为我的顶点使用了一个结构,它是:
#define LINES_NB 1000
struct Point
{
float x, y, z, rhw;
float r, g, b, a;
} lineList[LINES_NB];
最后,这里是 VERTEX SHADER 的代码:
struct VIn
{
float4 position : POSITION;
float4 color : COLOR;
};
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut main(VIn input)
{
VOut output;
output.position = input.position;
output.color = input.color;
return output;
}
我用以下行编译:
/Zi /E"main" /Od /Fo"E:\PATH\VertexShader.cso" /vs"_5_0" /nologo
像素着色器的代码如下:
struct PIn
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
float4 main(PIn input) : SV_TARGET
{
return input.color;
}
我使用以下行编译:
/Zi /E"main" /Od /Fo"E:\PATH\PixelShader.cso" /ps"_5_0" /nologo
这是 RASTERIZER STATE 创建部分:
D3D11_RASTERIZER_DESC rasterDesc;
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_NONE;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = false;
rasterDesc.FillMode = D3D11_FILL_WIREFRAME;
rasterDesc.FrontCounterClockwise = true;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
result = _device->CreateRasterizerState(&rasterDesc, &_rasterState);
if (FAILED(result))
{
OutputDebugString("FAILED TO CREATE RASTERIZER STATE.\n");
HR(result);
return -1;
}
_immediateContext->RSSetState(_rasterState);
这是INPUT LAYOUT注册部分(_vertexShaderCode->code包含vertexShader.cso和_vertexShaderCode->size的内容,这些内容的大小):
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
HR(_device->CreateInputLayout(ied, sizeof(ied) / sizeof(D3D11_INPUT_ELEMENT_DESC), _vertexShaderCode->code, _vertexShaderCode->size, &_vertexInputLayout));
_immediateContext->IASetInputLayout(_vertexInputLayout);
其中变量声明为:
struct Shader
{
BYTE *code;
UINT size;
};
ID3D11Device* _device;
ID3D11DeviceContext* _immediateContext;
ID3D11RasterizerState* _rasterState;
ID3D11InputLayout* _vertexInputLayout;
Shader* _vertexShaderCode;
Shader* _pixelShaderCode;
我的 VERTEX BUFFER 是通过调用 createLinesBuffer 一次,然后调用 renderVertice 创建的在每次绘制调用时对其进行映射:
void DxDraw::createLinesBuffer(ID3D11Device* device)
{
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDesc.ByteWidth = sizeof(Point) * LINES_NB;
std::cout << "buffer size : " << sizeof(Point) * LINES_NB << std::endl;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = lineList;
std::cout << "lineList : " << lineList << std::endl;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
HR(device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &_vertexBuffer));
}
void DxDraw::renderVertice(ID3D11DeviceContext* ctx, UINT count, D3D11_PRIMITIVE_TOPOLOGY type)
{
D3D11_MAPPED_SUBRESOURCE ms;
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
// map the buffer
HR(ctx->Map(_vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms));
// copy the data to it
memcpy(ms.pData, lineList, sizeof(lineList));
// unmap it
ctx->Unmap(_vertexBuffer, NULL);
// select which vertex buffer to display
UINT stride = sizeof(Point);
UINT offset = 0;
ctx->IASetVertexBuffers(0, 1, &_vertexBuffer, &stride, &offset);
// select which primtive type we are using
ctx->IASetPrimitiveTopology(type);
// draw the vertex buffer to the back buffer
ctx->Draw(count, 0);
}
这里有很多地方可能出错了,可能你可以检查一下:
- 是否正确声明了输入布局?看起来你的顶点着色器没有得到任何几何体
- 你如何声明你的Rasterizer Stage?有时可能会出现一些问题,例如剔除、深度裁剪等。
- 你的几何形状怎么样?在将几何应用到 Input Assembler 之前,您是否应用了任何 world/view/projection 转换?
- 你是如何构造你的顶点缓冲区的?你Map/Unmap吗?或者,也许您为每个绘图调用都构建了这个?
我不能保证这会有所帮助,但恕我直言,所有这些都值得一试。
至于 Pixel Shader 没有输出,似乎没有任何东西输入它 - 所以一定有 VS 输出或 RS 以某种方式剪切了所有几何体(由于剔除、深度测试等)
Copied from comment, since it solved the issue.
InputLayout 看起来不错,VertexBuffer 看起来也不错。此时,我会检查实际的顶点坐标。从您的屏幕截图来看,您似乎使用了相当大的数字,例如 x = 271,y = 147。通常,这些位置是通过世界视图投影转换进行转换的,因此它们最终以 <-1.0f;1.0f 结束> 范围。由于您没有使用任何转换,我建议更改您的 lineGenerator 函数,以便它在 <-1.0f 内生成几何图形; 1.0f> x 和 y 坐标的范围。 例如,如果您当前的 x 值为 271,则将其设置为 0.271f