Hi there! first of all Hello to all since this is my first post here
Ok, I am trying to port the SharpDX particle system posted here: http://www.gamedev.net/topic/644489-gpu-particles/ by lwn: https://github.com/sharpdx/SharpDX/commit/71d289e05a0c383e5bc0680333150f06c25197d9
However I'm having an error creating the ID3D11InputLayout *particleLayout. The main problem is here, everything before that returns succesfully :
device->CreateInputLayout(pLayOutDescription,numElements,PassDesc.pIAInputSignature,PassDesc.IAInputSignatureSize,&particleLayout);
The whole function is here. Or if you want, can check the code in Github https://github.com/neroziros/ParticleSystemDX11
If it helps, the error that HRESULT_CODE(result) is returning is. Error Code: 87
// Initialize the particle system shader (ie, the meat of the particle system)
bool Particleclass::InitializeShader(ID3D11Device* device, HWND hwnd,LPCSTR fxFilename)
{
// Initial variables declaration
HRESULT result;
ID3D10Blob* errorMessage;
ID3D10Blob* effectShaderBuffer;
// Compile the effect shader code.
result = D3DX11CompileFromFile(fxFilename, NULL, NULL, NULL, "fx_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL,
&effectShaderBuffer, &errorMessage, NULL);
// Compiling error check
if(FAILED(result))
{
// If the shader failed to compile it should have writen something to the error message.
if(errorMessage)
{
OutputShaderErrorMessage(errorMessage, hwnd, fxFilename);
}
// If there was nothing in the error message then it simply could not find the shader file itself.
else
{
MessageBox(hwnd, fxFilename, "Missing Shader File", MB_OK);
}
return false;
}
// Create the effect buffer
result = D3DX11CreateEffectFromMemory(effectShaderBuffer->GetBufferPointer(),effectShaderBuffer->GetBufferSize(),NULL,device,&pEffect);
// Creation error check
if(FAILED(result) || pEffect== nullptr)
{
// Show the error
std::stringstream stream;
stream << "Error Code::" << HRESULT_CODE(result);
MessageBox(NULL,stream.str().c_str(),"Effect Creation Error", MB_OK);
return false;
}
// Get uniform variables references. These will ease the variable updates
m_viewMatrixPtr = pEffect->GetVariableByName("_view")->AsMatrix();
if(!m_viewMatrixPtr->IsValid())return false;
m_projectionMatrixPtr = pEffect->GetVariableByName("_proj")->AsMatrix();
if(!m_projectionMatrixPtr->IsValid())return false;
m_lookAtMatrixPtr = pEffect->GetVariableByName("_lookAtMatrix")->AsMatrix();
if(!m_lookAtMatrixPtr->IsValid())return false;
m_gravity = pEffect->GetVariableByName("_gravity")->AsVector();
if(!m_gravity->IsValid())return false;
m_camDir = pEffect->GetVariableByName("_camDir")->AsVector();
if(!m_camDir->IsValid())return false;
m_elapsedSeconds = pEffect->GetVariableByName("_elapsedSeconds")->AsScalar();
if(!m_elapsedSeconds->IsValid())return false;
// Get the shader techniques (update and render)
updatePass = pEffect->GetTechniqueByName("UpdateTeq")->GetPassByIndex(0); //Update pass
if(!updatePass->IsValid())return false;
renderPass = pEffect->GetTechniqueByName("RenderTeq")->GetPassByIndex(0); //Render pass
if(!renderPass->IsValid())return false;
// Input layout description
const D3D11_INPUT_ELEMENT_DESC pLayOutDescription[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0 , D3D11_INPUT_PER_VERTEX_DATA, 0 }, // Position D3DXVECTOR3
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // Velocity D3DXVECTOR3
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // Color D3DXCOLOR
{ "TEXCOORD0",0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // TimerLifetime D3DXVECTOR2
{ "TEXCOORD1",0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // SizeStartEnd D3DXVECTOR2
};
// Num of elements in the layout description
UINT numElements = sizeof(pLayOutDescription)/sizeof(pLayOutDescription[0]);
// Get pass description (UPDATE)
D3DX11_PASS_DESC PassDesc;
result = updatePass->GetDesc(&PassDesc);
// Error check
if(FAILED(result)) return false;
// Create input layout for UPDATE technique
result = device->CreateInputLayout(pLayOutDescription,numElements,PassDesc.pIAInputSignature,PassDesc.IAInputSignatureSize,&particleLayout);
// Error check
if(FAILED(result) || particleLayout== nullptr)
{
// Show the error
std::stringstream stream; stream << "Error Code::" << HRESULT_CODE(result);
MessageBox(NULL,stream.str().c_str(),"Input layout creation error", MB_OK);
return false;
}
// Return approved value
return true;
}
And the translated FX file:
//
// Particle effect using geometry shader and stream out
// 2013 Christoph Romstoeck (lwm) (Original) / 2014 José Conteras (Modified)
//
Texture2D<float4> _texture;
sampler _sampler : register(s0);
// Constant buffer. All shaders can access these variables anytime
cbuffer EveryFrame : register(b0) {
float4x4 _view;
float4x4 _proj;
float4x4 _lookAtMatrix;
float3 _camDir;
float _elapsedSeconds;
float3 _gravity;
};
struct ParticleVertex
{
float3 Position : POSITION;
float3 Velocity : NORMAL;
float4 Color : COLOR;
float2 TimerLifetime : TEXCOORD0;
float2 SizeStartEnd : TEXCOORD1;
};
struct ParticleVertexGsUpdateOut
{
float4 Position : SV_POSITION;
float3 Velocity : NORMAL;
float4 Color : COLOR;
float2 TimerLifetime : TEXCOORD0;
float2 SizeStartEnd : TEXCOORD1;
};
struct ParticleVertexGsOut
{
float4 Position : SV_POSITION;
float4 Color : COLOR;
float2 TexCoord : TEXCOORD0;
float4 PositionVS : TEXCOORD1;
};
// ===
// Vertex shader has no work to do.
// Simply pass vertex on to the next stage.
ParticleVertex VS_Passthrough(ParticleVertex v)
{
return v;
}
// Geometry shader to update one particle.
[maxvertexcount(1)]
void GS_Update(point ParticleVertex vertex[1], inout PointStream<ParticleVertexGsUpdateOut> stream) {
ParticleVertex input = vertex[0];
// Calculate new age of the particle.
float newTimer = input.TimerLifetime.x + _elapsedSeconds;
// If the particle is older than its lifetime, don't do anything.
if(newTimer > input.TimerLifetime.y)
return;
// Calculate new position by adding the particle's velocity.
float3 newPosition = input.Position + input.Velocity * _elapsedSeconds;
// Calculate new velocity by adding the world's gravity.
float3 newVelocity = input.Velocity + _gravity * _elapsedSeconds;
ParticleVertexGsUpdateOut output;
output.Position = float4(newPosition, 1);
output.Velocity = newVelocity;
output.Color = input.Color;
output.TimerLifetime.x = newTimer;
output.TimerLifetime.y = input.TimerLifetime.y;
output.SizeStartEnd = input.SizeStartEnd;
// Append updated particle to output stream.
stream.Append(output);
}
GeometryShader pGSComp = CompileShader(gs_5_0, GS_Update());
GeometryShader gsStreamOut = ConstructGSWithSO( pGSComp, "SV_POSITION.xyz; NORMAL.xyz; COLOR.xyzw; TEXCOORD0.xy; TEXCOORD1.xy;" );
technique11 UpdateTeq
{
pass Pass1
{
SetVertexShader( CompileShader( vs_5_0, VS_Passthrough() ) );
SetGeometryShader( gsStreamOut );
SetPixelShader( NULL );
}
}
// ===============================================
// Geometry shader to expand the vertex into a quad.
[maxvertexcount(4)]
void GS_Render(point ParticleVertex inputArray[1], inout TriangleStream<ParticleVertexGsOut> stream) {
ParticleVertex input = inputArray[0];
// Calculate the particles age in [0..1]
float age = input.TimerLifetime.x / input.TimerLifetime.y;
ParticleVertexGsOut v;
// Determine the particle's color based on its age.
v.Color = input.Color;
v.Color.a *= (-4 * (age - 0.5f) * (age - 0.5f) + 1);
// Calculate the particle's current size
float2 size = lerp(input.SizeStartEnd.x, input.SizeStartEnd.y, age);
// Check if one of the quad's axes should be constrained to the particle's velocity.
//bool constrained = (input.Flags & FLAG_CONSTRAINED) > 0;
float3 right, up;
/*if(constrained)
{
right = normalize(input.Velocity);
up = cross(_camDir, right) * size.y;
right *= size.x;
}
else
{*/
float2 xr = float4(size.x, 0, 0, 1);
float2 yr = float4(0, size.y, 0, 1);
right = mul(xr, _lookAtMatrix).xyz;
up = mul(yr, _lookAtMatrix).xyz;
//}
// Create and append four vertices to form a quad.
float4 positionWS = float4(input.Position + right + up, 1.f);
v.PositionVS = mul(positionWS, _view);
v.Position = mul(v.PositionVS, _proj);
v.TexCoord = float2(1, 1);
stream.Append(v);
positionWS = float4(input.Position - right + up, 1.f);
v.PositionVS = mul(positionWS, _view);
v.Position = mul(v.PositionVS, _proj);
v.TexCoord = float2(0, 1);
stream.Append(v);
positionWS = float4(input.Position + right - up, 1.f);
v.PositionVS = mul(positionWS, _view);
v.Position = mul(v.PositionVS, _proj);
v.TexCoord = float2(1, 0);
stream.Append(v);
positionWS = float4(input.Position - right - up, 1.f);
v.PositionVS = mul(positionWS, _view);
v.Position = mul(v.PositionVS, _proj);
v.TexCoord = float2(0, 0);
stream.Append(v);
stream.RestartStrip();
}
// Simple pixel shader to render the particles.
float4 PS_Render(ParticleVertexGsOut input) : SV_Target
{
float4 tex = _texture.Sample(_sampler, input.TexCoord);
return tex * input.Color;
}
technique11 RenderTeq
{
pass Pass1
{
SetVertexShader( CompileShader( vs_5_0, VS_Passthrough() ) );
SetGeometryShader(CompileShader( gs_5_0, GS_Render()) );
SetPixelShader(CompileShader( ps_5_0, PS_Render()));
}
}
Cheers and thanks for any help you can offer.