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.
cbuffer cbPerObject : register( b1 )
{
bool gUseTexture ;
row_major float4x4 gWorld ;
row_major float4x4 gWorldInvTranspose ;
row_major float4x4 gWorldViewProj ;
row_major float4x4 gTexTransform ;
Material gMaterial ;
} ;
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 :
Move the boolean to the end of the structure. I did this and it worked.
Add a 3-component sized padding variable between the world matrix and the boolean.
I tried this by adding an XMFLOAT3 in the c++ structure and a float3 in HLSL. This worked too.
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.
As I wrote in my comment, I had a similar problem.
In my case, the pixel shader was correctly bound (see http://msdn.microsoft.com/en-us/library/jj191650.aspx). Furthermore, I ensured by debugging the vertex shader that the result of the Transformation should be visible and hence should generate visible fragments.
In this case (which seems to be the same you describe), make sure that your rasteriser state is correct. You might want to check that it is actually set (using the graphics object view of the immediate context) and that it lets your geometry through. For debugging purposes, I found it helpful disabling backface culling. I use
D3D11_RASTERIZER_DESC rasterDesc;
ZeroMemory(&rasterDesc, sizeof(rasterDesc));
rasterDesc.CullMode = D3D11_CULL_MODE::D3D11_CULL_NONE;
rasterDesc.FillMode = D3D11_FILL_MODE::D3D11_FILL_SOLID;
Related
I am trying to compile a very simple Effect Shader targeting DirectX9 and shader model 2. I am trying to pass in directly the screen coords for the vertex Positions instead of multiplying by a world, view, and projection matrices so I use the POSITIONT semantic instead of the POSTION0 semantic in the VertexShaderInput structure. However when I try to compile the shader using
fxc.exe /Od /Zi /T fx_2_0 /Fo simple.fxo simple.fx
I get the following error: "error X4502: Invalid input semantics - POSITIONT0"
It seems to be automatically adding a 0 to the end of the semantic for some reason. This seems like I bug to me because POSITIONT is clear described as a valid input semantic here:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx#PS
and it is the only one that does not allow extra integers to be appended at the end of the semantic.
EDIT: I have just discovered that if I change POSITIONT to POSITIONT1 it works fine. This seem counter to what the documentation above describes.
Contents of simple.fx:
struct VertexShaderInput
{
float4 Position : POSITIONT;
float4 Color : COLOR0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
output.Position = input.Position;
output.Color = input.Color;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
return input.Color;
}
technique Ambient
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
For legacy Direct3D9 there is a special D3DDECLUSAGE_POSITIONT which means to just skip vertex processing. Therefore, you can only use POSITIONT in the PIXEL SHADER input--i.e. it can't be used in a VERTEX SHADER at all.
Change your shader to use POSITION or POSITION0.
I am investigating a E_INVALIDARG exception that is thrown when I attempt to create a second constant buffer that stores the information for my lights:
// create matrix stack early
CD3D11_BUFFER_DESC constantMatrixBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantMatrixBufferDesc,
nullptr,
&m_constantMatrixBuffer
)
);
DX::ThrowIfFailed(
m_matrixStack.Initialize(m_d3dContext, m_constantMatrixBuffer, &m_constantMatrixBufferData)
);
// also create the light buffer early, we must create it now but we will later
// update it with the light information that we parsed from the model
CD3D11_BUFFER_DESC constantLightBufferDesc(sizeof(LightConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
/* !!!!---- AN E_INVALIDARG IS THROWN BY THE FOLLOWING LINE ----!!!! */
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantLightBufferDesc,
nullptr,
&m_constantLightBuffer
)
);
At this point, it appears that the parameters being passed into the Light's CreateBuffer call are in the same state that the Matrix's are! The problem seems to have to do with the number of bytes being stored in the buffer description.
The buffer is defined as such in the module:
// a constant buffer that contains the 3 matrices needed to
// transform points so that they're rendered correctly
struct ModelViewProjectionConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};
// a constant buffer that contains up to 4 directional or point lights
struct LightConstantBuffer
{
DirectX::XMFLOAT3 ambient[4];
DirectX::XMFLOAT3 diffuse[4];
DirectX::XMFLOAT3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
DirectX::XMFLOAT3 attenuation[4];
// the position and direction of the light
DirectX::XMFLOAT3 position[4];
DirectX::XMFLOAT3 direction[4];
// the type of light that we're working with, defined in lights.h
UINT type[4];
// a number from 0 to 4 that tells us how many lights there are
UINT num;
};
And as such in the vertex shader (.hlsl):
cbuffer ModelViewProjectionConstantBuffer : register (b0)
{
matrix model;
matrix view;
matrix projection;
};
cbuffer LightConstantBuffer : register (b1)
{
float3 ambient[4];
float3 diffuse[4];
float3 specular[4];
// the first spot in the array is the constant attenuation term,
// the second is the linear term, and the third is quadradic
float3 attenuation[4];
// the position and direction of the light
float3 position[4];
float3 direction[4];
// the type of light that we're working with, defined in lights.h
uint type[4];
// a number from 0 to 4 that tells us how many lights there are
uint num;
}
In an attempt to figure out what is causing this, I have stumbled across this line in the MSDN HLSL Shader documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ff476898(v=vs.85).aspx):
Each element stores a 1-to-4 component constant, determined by the format of the data stored.
What does this mean and is it the reason for this exception? I have noticed that in the Visual Studio 3D Starter Kit (http://code.msdn.microsoft.com/wpapps/Visual-Studio-3D-Starter-455a15f1), the buffers have extra floats padding them:
///////////////////////////////////////////////////////////////////////////////////////////
//
// Constant buffer structures
//
// These structs use padding and different data types in places to adhere
// to the shader constant's alignment.
//
struct MaterialConstants
{
MaterialConstants()
{
Ambient = DirectX::XMFLOAT4(0.0f,0.0f,0.0f,1.0f);
Diffuse = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
Specular = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
Emissive = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
SpecularPower = 1.0f;
Padding0 = 0.0f;
Padding1 = 0.0f;
Padding2 = 0.0f;
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 Diffuse;
DirectX::XMFLOAT4 Specular;
DirectX::XMFLOAT4 Emissive;
float SpecularPower;
float Padding0;
float Padding1;
float Padding2;
};
struct LightConstants
{
LightConstants()
{
ZeroMemory(this, sizeof(LightConstants));
Ambient = DirectX::XMFLOAT4(1.0f,1.0f,1.0f,1.0f);
}
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 LightColor[4];
DirectX::XMFLOAT4 LightAttenuation[4];
DirectX::XMFLOAT4 LightDirection[4];
DirectX::XMFLOAT4 LightSpecularIntensity[4];
UINT IsPointLight[4*4];
UINT ActiveLights;
float Padding0;
float Padding1;
float Padding2;
};
... // and there's even more where that came from
So am I just not padding these things correctly? And if so, how should I pad them? Or is it something completely different that I'm missing?
I greatly appreciate you reading this and trying to help.
It is hard to fix your problem because lack of important info, but let's make a try.
Obviously, 'E_INVALIDARG' says that invalid argument passed to function. Now we must figure out what parameter is wrong.
ID3D11Device::CreateBuffer method accepts 3 parameters: D3D11_BUFFER_DESC, D3D11_SUBRESOURCE_DATA, and ID3D11Buffer** itself.
And you feed to it &constantLightBufferDesc, nullptr, &m_constantLightBuffer.
Now you must carefully read all 4 MSDN articles to find out what is wrong.
constantLightBuffer it is not a problem, just check that it has ID3D11Buffer pointer type.
nullptr it is unlikely a problem, but AFAIK it is not C++ standard keyword, so probably simple '0' will be better here. Actually, it is a standard since C++11
Unfortunately you don't provide your constantLightBufferDesc definition, which is a candidate to be a problem:
as you've stated there can be buffer alignment mistake: if your constantLightBufferDesc.BindFlags has D3D11_BIND_CONSTANT_BUFFER flag and constantLightBufferDesc.ByteWidth is not a multiple of 16, buffer creation fails. But that's just a guess. You can have any other mismatch here, so, you can make a guesses infinetely.
Fortunalely, there are another way of diagnostic: if you creating your ID3D11Device with D3D11_CREATE_DEVICE_DEBUG flag, in Visual Studio output window you will see all the warnings and errors according to D3D11. For example, in case of misalignment you will see:
D3D11 ERROR: ID3D11Device::CreateBuffer: The Dimensions are invalid.
For ConstantBuffers, marked with the D3D11_BIND_CONSTANT_BUFFER
BindFlag, the ByteWidth (value = 10) must be a multiple of 16.
ByteWidth must also be less than or equal to 65536 on the current
driver. [ STATE_CREATION ERROR #66: CREATEBUFFER_INVALIDDIMENSIONS]
So, if CreateBuffer() failing because of wrong buffer size, there are several ways to handle this:
Resize your structures: add padding members so total sizeof() will become multiple of 16.
Declare your structures as 16-bit aligned. AFAIK there are only compiler-specific ways to do this: for example #pragma pack for msvc.
Assign to ByteWidth not a real structure size, but rounded up to next multiple of 16: link
Happy debugging! =)
I understand there's a limitation in HLSL shader model 5.0 where one cannot load data from a non-scalar typed RWTexture2D resource. That is to say, the following is illegal:
RWTexture2D<float4> __color;
float4 c = __color[PixelCoord]; // error here
So what exactly is the workaround? I'm trying to accumulate into a float4 buffer in a compute shader, like so:
c = computeColor( ... );
__color[PixelCoord] += c;
Try doing:
float4 c = __color.Load( int3( UV, 0 ) );
Where UV is the xy coordinate in screen space (0 -> Resolution) of the texel you want to sample.
If you need to write to it, make sure it is bound from a UAV and not a shader resource view.
I'm a beginner pixel shader writer and I'm running into some trouble. I want to take a 256x256, 16-bit input (DXGI_FORMAT_R16_UINT) image, and pass it through a 256x256 look-up texture (DXGI_FORMAT_R8_UNORM) to convert it to a 256x256 8-bit output.
Unfortunately, I seem to be running into a lot of trouble and the output seems to always clamp to black or white.
Also, I'm not sure which DXGI formats I should be using, and also, which data type correlates with each format.
// Global Variables
Texture2D<uint> imgTexture : register( t0 );
Texture2D lutTexture : register( t1 );
SamplerState SampleType : register( s0 );
// Structures
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};
// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
uint pixelValue = imgTexture[input.Tex];
uint2 index = { pixelValue / 256, pixelValue % 256 };
// uint row = pixelValue / 256;
// uint col = pixelValue % 256;
float4 output = lutTexture[index];
output.g = output.r;
output.b = output.r;
output.a = 1.0f;
return output;
}
Should I be normalizing the pixelValue before trying to turn it into a 2D index?
Should I be normalizing the index before using it?
Should I be sampling instead?
Am I even on the right path here?
I would appreciate ANY help, thanks!
You are definitely on the right track. But, like Valmond mentioned, the value of pixelValue will be in the range [0..1].
How exactly is the LUT set up? I'm guessing that the first axis is the value to be transformed, but what is the second? Once I know that, I can give a solution with code.
You are using :
uint pixelValue = imgTexture[input.Tex];
Which requires pixel value, but you are providing input.Tex (which I guess is normalized from 0 to 1).
So in that case you are loading the same pixel.
you can use :
uint pixelValue = imgTexture[input.Pos.xy];
or :
uint pixelValue = imgTexture.Load(int3(input.Pos.xy, 0));
instead.
And yes your formats are correct for your use case (no need to normalize or denormalize).
I've started at the beginning, and my code will capably display the grand total of some text. I've been adding support for sprites. The trouble that I've run in to, is that it doesn't seem to recognize my HLSL. I set the technique, began it, began the pass, drew the sprites, flushed them, ended the pass, the technique. And D3D comes up with this little "Using FF to PS converter" in the VS output. Same for VS. I'm not trying to do anything advanced with my HLSL - just use it and get a little more familiar with it and make sure I know how to implement it. That's C++0x auto, by the way, so automatic type deduction (because I'm lazy).
#define D3DCALL(a) { auto __ = a; if (FAILED(__)) DXTrace(__FILE__, __LINE__, __, WIDEN(#a), TRUE); }
D3DCALL(spriteeffect->SetTechnique(spritetechnique));
D3DCALL(spriteeffect->Begin(&passes, NULL));
D3DCALL(spriteeffect->BeginPass(0)); // We know this is zero.
D3DCALL(sprite->Begin(D3DXSPRITE_OBJECTSPACE | D3DXSPRITE_DO_NOT_ADDREF_TEXTURE | D3DXSPRITE_SORT_TEXTURE | D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_DEPTH_FRONTTOBACK));
RenderAndCleanUp(common->sprites);
D3DCALL(sprite->End());
D3DCALL(spriteeffect->EndPass());
D3DCALL(spriteeffect->End());
where RenderAndCleanUp is a simple templated function that loops through the sprites, destroys those that need to be, and renders the rest, and common->sprites is a simple vector of all the sprite objects. Since DXTrace never goes off, I'll guarantee that none of the functions fail. I've also set the control panel to max debugging.
I checked the D3DXHANDLEs and they're all non-NULL. It doesn't report any compilation errors, or any errors or warnings.
// Contains the HLSL for sprites.
// Based on transform.fx, by Frank Luna.
// FX parameter (global variable to the shader).
uniform extern float4x4 gWVP;
// Structure
struct OutputVS
{
float4 posH : POSITION0;
float4 color : COLOR0;
};
// Vertex shader
OutputVS SpriteVS(float3 post : POSITION0,
float4 col : COLOR0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;
outVS.posH = mul(float4(post, 1.0f), gWVP); // Transform
outVS.color = col;
// Done--return the output.
return outVS;
}
// Pixel shader - take the original colour of the pixel and just return it. Nothing fancy.
float4 SpritePS( float4 col : COLOR0 ) : COLOR
{
return col;
}
technique Sprite
{
pass P0
{
// Specify the vertex and pixel shader associated
// with this pass.
vertexShader = compile vs_3_0 SpriteVS();
pixelShader = compile ps_3_0 SpritePS();
}
}
This is native C++ looking at Direct3D9.
AFAIR D3DXSprite and D3DXFont rendering is implemented inside of D3DX itself. So, it sets its own shaders, states (emulates fixed-function pipeline) and renders text/sprites. So, your shaders and states have no effect on these objects.
You may implement your own text/sprite rendering subsystem, it's not so hard. Another vote for this is that Microsoft officially deprecated D3DX.