SharpDX to DX11 PARTICLE SYSTEM problem

Started by
1 comment, last by neroziros 10 years, 1 month ago

Hi there! first of all Hello to all since this is my first post here smile.png

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.

Advertisement

If you're failing to create an input layout, that usually means that your vertex shader expects an input that isn't being provided by your vertex buffer(s). If you create your device with the debug flag and check the native debugging output stream, you'll get the full error message when this occurs.

In your particular case I think it's your last two elements. For input element desc, you don't want to put the semantic index (the number at the end) into your string. You'll want to put it in the second member of the struct, called SemanticIndex. Also just FYI, you can use whatever semantic names you want in DX11. So you don't need to use the old "NORMAL" and "TEXCOORD" names from DX9.

Thank you so much, you were absolutely right it was a semantic problem!

Again thanks for your help smile.png

PS: For anyone who want to use the code. I just renamed it the semantics:


float2 TimerLifetime : TEXCOOR0;
float2 SizeStartEnd : TEXCOOR1;

to


float2 TimerLifetime : TIMERLIFE;
float2 SizeStartEnd : SIZESTART;

And updated the D3D11_INPUT_ELEMENT_DESC accordingly.

This topic is closed to new replies.

Advertisement