Пиксельный шейдер DirectX11 в конвейере отсутствует

Я пишу программу, которая отображает модель MS3D с использованием DirectX, и, к сожалению, результат ничего не показывает на экране.
Когда я использую графический отладчик из Visual Studio 13, я замечаю, что пиксельный шейдер отсутствует в конвейере, как показано на рисунке ниже.

образ

Это мой исходный код пиксельного шейдера:

 cbuffer SkinningTransforms
{
matrix WorldMatrix;
matrix ViewProjMatrix;
};
//--------------------------------------------------------------------------------
// Inter-stage structures
//--------------------------------------------------------------------------------
struct VS_INPUT
{
float3  position        : POSITION;
int4    bone            : BONEID;
float4  weights         : BONEWEIGHT;
float3  normal          : NORMAL;
float3  tangent         : TANGENT;
float2  tex             : TEXCOORD;
};
//--------------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 position         : SV_Position;
float3 normal           : NORMAL;
float3 light            : LIGHT;
float2 tex              : TEXCOORDS;
};

Texture2D       ColorTexture : register( t0 );
SamplerState    LinearSampler : register( s0 );

//--------------------------------------------------------------------------------
VS_OUTPUT VSMAIN( in VS_INPUT input )
{
VS_OUTPUT output;
//Transform vertex and pass them to the pixel shader
return output;
}

//--------------------------------------------------------------------------------
float4 PSMAIN( in VS_OUTPUT input ) : SV_Target
{
// Calculate the lighting
float3 n = normalize( input.normal );
float3 l = normalize( input.light );float4 texColor = ColorTexture.Sample( LinearSampler, input.tex );

float4 color = texColor * (max(dot(n,l),0) + 0.05f );
return( color );
}

Как мне было известно из Graphics Debugger, все графические события верны. Ниже перечислены важные события, которые могут быть связаны с Pixel Shader:

106:(obj:4) ID3D11Device::CreateDepthStencilView(obj:24,NULL,obj:25)*
108:(obj:5) ID3D11DeviceContext::OMSetRenderTargets(8,{obj:1,NULL,NULL,NULL,NULL,NULL,NULL,NULL},obj:25)*
109:(obj:5) ID3D11DeviceContext::ClearRenderTargetView(obj:1,addr:21)*
111:(obj:5) ID3D11DeviceContext::ClearDepthStencilView(obj:25,1,1.000f,0)*
119:(obj:4) ID3D11Device::CreateSamplerState(addr:24,obj:27)*
134:(obj:4) ID3D11Device::CreatePixelShader(addr:27,21056,NULL,obj:30)*
135:CreateObject(D3D11 Pixel Shader,obj:30)
136:(obj:5) ID3D11DeviceContext::PSSetShader(obj:30,NULL,0)*
137:(obj:5) ID3D11DeviceContext::PSSetSamplers(0,1,{obj:27})*
139:(obj:4) ID3D11Device::CreateTexture2D(addr:28,addr:5,obj:31)*
140:CreateObject(D3D11 Texture2D,obj:31)
142:(obj:4) ID3D11Device::CreateShaderResourceView(obj:31,NULL,obj:32)*
143:CreateObject(D3D11 Shader Resource View,obj:32)
144:(obj:5) ID3D11DeviceContext::PSSetShaderResources(0,1,{obj:32})*
146:(obj:4) ID3D11Device::CreateRasterizerState(addr:29,obj:33)*
147:CreateObject(D3D11 Rasterizer State,obj:33)
152:(obj:5) ID3D11DeviceContext::RSSetState(obj:33)*
154:(obj:5) ID3D11DeviceContext::RSSetViewports(1,addr:30)*
156:(obj:4) ID3D11Device::CreateBlendState(addr:11,obj:34)*
157:CreateObject(D3D11 Blend State,obj:34)
159:(obj:5) ID3D11DeviceContext::OMSetBlendState(obj:34,addr:31,-1)*
162:(obj:4) ID3D11Device::CreateDepthStencilState(addr:32,obj:35)*
163:CreateObject(D3D11 Depth-Stencil State,obj:35)
165:(obj:5) ID3D11DeviceContext::OMSetDepthStencilState(obj:35,0)*

Я отлаживал все функции в приведенном выше списке, и все они возвращали ОК. Ничего плохого.
Мой вопрос заключается в том, что является причиной отсутствия пиксельного шейдера в pipleline, что, в свою очередь, может привести к пустому экрану.

2

Решение

В дополнение к другим ответам, постоянная буферная организация может быть причиной этой проблемы. В моем случае пиксельный шейдер отсутствовал в конвейере, но и вершинный шейдер неправильно преобразовывал вершины. При проверке было обнаружено, что мировая матрица имела неправильные значения, потому что логическое значение в верхней части константного буфера вызывало смещение данных. HLSL упаковывает данные в 16-байтовые границы, которые называются векторы которые имеют 4 компонента. Логическое значение составляет 4 байта, что то же самое с плавающей точкой.

cbuffer cbPerObject : register( b1 )
{
bool gUseTexture ;

row_major float4x4 gWorld ;
row_major float4x4 gWorldInvTranspose ;
row_major float4x4 gWorldViewProj ;
row_major float4x4 gTexTransform ;
Material gMaterial ;
} ;

Таким образом, в указанном выше константном буфере логическое значение + первые 3 компонента первой строки мировой матрицы отображается на первый вектор и это приводит к тому, что все сдвигается на 3 компонента, что приводит к неправильному выравниванию матрицы мира (и других матриц, следующих и, возможно, других данных).

Два возможных решения:

  1. Переместите логическое значение в конец структуры. Я сделал это, и это сработало.
  2. Добавить 3-х компонентный размер набивка переменная между мировой матрицей и логическим значением.
    Я попробовал это, добавив XMFLOAT3 в структуру c ++ и float3 в HLSL. Это тоже сработало.

Короче говоря, обратите внимание на упаковку HLSL.

РЕДАКТИРОВАТЬ: В то время я думал, что эти методы работают, так как все переменные, кроме логического, имеют правильные значения. Я не использовал bool в то время, поэтому я предположил, что это тоже хорошо. Оказывается, это не так.

Bools HLSL и bools c ++ имеют разные размеры. Bools HLSL имеют размер 4 байта, тогда как bool c ++ определяется реализацией (например, 1 байт на моей машине). В любом случае, они, скорее всего, будут другими, и это вызывает проблемы.

Либо используйте тип Windows BOOL, либо другое значение соответствующего размера, например, int или uint.

Взгляни на https://gamedev.stackexchange.com/a/22605.

Также со второго по последний пост Вот объясняет ситуацию четко (эта ссылка также указана в ответе в ссылке на gamedev выше).

Будьте осторожны, потому что упаковка все еще является проблемой. Даже если вы используете BOOL или uint или что-то еще, если вы поместите его в начале в структуре выше, как и раньше, вы получите неправильные значения в вашем постоянном буфере. Поэтому при работе с постоянными буферами учитывайте обе эти проблемы (выравнивание данных и логическая проблема).

3

Другие решения

Как я написал в своем комментарии, у меня была похожая проблема.

В моем случае пиксельный шейдер был правильно привязан (см. http://msdn.microsoft.com/en-us/library/jj191650.aspx). Кроме того, отладкой вершинного шейдера я гарантировал, что результат преобразования должен быть видимым и, следовательно, генерировать видимые фрагменты.

В этом случае (который, как вы описываете), убедитесь, что ваше растеризированное состояние корректно. Возможно, вы захотите проверить, что он действительно установлен (используя вид графического объекта непосредственного контекста) и что он позволяет вашей геометрии пройти. В целях отладки мне показалось полезным отключить выборку задней поверхности. я использую

D3D11_RASTERIZER_DESC rasterDesc;
ZeroMemory(&rasterDesc, sizeof(rasterDesc));
rasterDesc.CullMode = D3D11_CULL_MODE::D3D11_CULL_NONE;
rasterDesc.FillMode = D3D11_FILL_MODE::D3D11_FILL_SOLID;
1

По вопросам рекламы [email protected]