I'm writing a program which displays a MS3D model using DirectX, and unfortunately, the result shows nothing on the screen. When I use the Graphics Debugger from Visual Studio 13, I notice that the pixel shader is missing from the pipeline, as it is shown in the below picture
This is my pixel shader source code:
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 );
}
As I was known from Graphics Debugger, all of the graphics event are right. I listed in below important events, which might be relating to 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)*
I debugged all of the function in the above list, and all of them return OK. Nothing wrong. My question is what is the reason the pixex shader is missing from pipleline, which in turn may result in the empty screen.
Adding to the other answers, constant buffer organization can be the cause of this problem. In my case, the pixel shader was missing from the pipeline but also the vertex shader wasn't transforming the vertices correctly. Upon inspection it was revealed that the world matrix had incorrect values because the boolean value at the top of the constant buffer was causing data misalignment. HLSL packs data into 16 byte boundries which are so called vectors that have 4 components. A boolean is 4 bytes which is the same with a float.
So in the constant buffer above, the boolean + the first 3 components of the first row of the world matrix gets mapped to the first vector and this causes everything to get shifted by 3 components, misaligning the world matrix (and the other matrices following and possibly other data).
Two possible solutions :
Long story short, pay attention to HLSL packing.
EDIT : At the time I thought these methods worked, as all variables except the boolean had correct values. I didn't use the bool at the time so I assumed that was fine too. Turns out it's not.
HLSL bools and c++ bools have different sizes. HLSL bools are 4 bytes, whereas c++ bools are implementation defined (1 byte on my machine for example). Anyways, they will most likely be different and it causes problems.
Either use Windows BOOL type or another appropriately-sized value like an int or a uint.
Take a look at https://gamedev.stackexchange.com/a/22605.
Also the second to last post here explains the situation clearly (this link is referenced in the answer in the gamedev link above also).
Beware though because packing is still an issue. Even if you use a BOOL or a uint or whatever, if you place it in the beginning in the above structure as before, you will get incorrect values in your constant buffer. So take both of these issues (data alignment and the boolean problem) into consideration when working with constant buffers.