0

I want implement Particle system based on stream out structure to my bigger project. I saw few articles about that method and I build one particle. It works almost correctly but in geometry shader with stream out i cant get value of InitVel.z and age because it always is 0. If i change order of age(for example age is before Position) it works fine for age but 6th float of order is still 0. It looks like he push only 5 first positions. I had no idea what i do wrong because i try change almost all(create input layout for vertex, the same like entry SO Declaration, change number of strides for static 28, change it to 32 but in this case he draw chaotic so size of strides is probably good). I think it is problem with limits of NumEntry in declaration Entry but on site msdn i saw the limit for directx is D3D11_SO_STREAM_COUNT(4)*D3D11_SO_OUTPUT_COMPONENT_COUNT(128) not 5. Pls can you look in this code and give me the way or hope of implement it correctly?? Thanks a lot for help.

Structure of particle

struct Particle{
Particle() {}
Particle(float x, float y, float z,float vx, float vy, float vz,float 
l /*UINT typ*/)
:InitPos(x, y, z), InitVel(vx, vy, vz), Age(l) /*, Type(typ)*/{}
XMFLOAT3 InitPos;
XMFLOAT3 InitVel;
float Age;
//UINT Type;
};

SO Entry

D3D11_SO_DECLARATION_ENTRY PartlayoutSO[] =
{

{ 0,"POSITION", 0, 0 , 3, 0 },  // output all components of position
{ 0,"VELOCITY", 0, 0, 3, 0 },     
{ 0,"AGE", 0, 0, 1, 0 }
//{ 0,"TYPE", 0, 0, 1, 0 }
};

Global Variables

//streamout shaders
ID3D11VertexShader* Part_VSSO;
ID3D11GeometryShader* Part_GSSO;
ID3DBlob *Part_GSSO_Buffer;
ID3DBlob *Part_VSSO_Buffer;
//normal shaders
ID3D11VertexShader* Part_VS;
ID3D11GeometryShader* Part_GS;
ID3DBlob *Part_GS_Buffer;
ID3D11PixelShader* Part_PS;
ID3DBlob *Part_VS_Buffer; 
ID3DBlob *Part_PS_Buffer;
ID3D11Buffer* PartVertBufferInit;
//ID3D11Buffer* Popy;
ID3D11Buffer* mDrawVB;
ID3D11Buffer* mStreamOutVB;
ID3D11InputLayout* PartVertLayout;// I try to set input layout too

void ParticleSystem::InitParticles()
{
mFirstRun = true;
srand(time(NULL));
hr = D3DCompileFromFile(L"ParticleVertexShaderSO4.hlsl", NULL, 
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL, 
&Part_VSSO_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderSO4.hlsl", NULL, 
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL, 
&Part_GSSO_Buffer, NULL);

UINT StrideArray[1] = { sizeof(Particle) };//I try to set static 28 bits-7*4 
per float
hr = device->CreateVertexShader(Part_VSSO_Buffer->GetBufferPointer(), 
Part_VSSO_Buffer->GetBufferSize(), NULL, &Part_VSSO);
hr = device->CreateGeometryShaderWithStreamOutput(Part_GSSO_Buffer- 
>GetBufferPointer(), Part_GSSO_Buffer->GetBufferSize(), PartlayoutSO ,3/* 
sizeof(PartlayoutSO)*/ , StrideArray, 1,D3D11_SO_NO_RASTERIZED_STREAM, 
NULL,&Part_GSSO);

//Draw Shaders
hr = D3DCompileFromFile(L"ParticleVertexShaderDRAW4.hlsl", NULL, 
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL, 
&Part_VS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderDRAW4.hlsl", NULL, 
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL, 
&Part_GS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticlePixelShaderDRAW4.hlsl", NULL, 
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "ps_5_0", NULL, NULL, 
&Part_PS_Buffer, NULL);

hr = device->CreateVertexShader(Part_VS_Buffer->GetBufferPointer(), 
Part_VS_Buffer->GetBufferSize(), NULL, &Part_VS);
hr = device->CreateGeometryShader(Part_GS_Buffer->GetBufferPointer(), 
Part_GS_Buffer->GetBufferSize(), NULL, &Part_GS);
hr = device->CreatePixelShader(Part_PS_Buffer->GetBufferPointer(), 
Part_PS_Buffer->GetBufferSize(), NULL, &Part_PS);
BuildVertBuffer();
}
void ParticleSystem::BuildVertBuffer()
{
D3D11_BUFFER_DESC vertexBufferDesc1;
ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc1.ByteWidth = sizeof(Particle)*1; //*numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER;// | 
D3D11_BIND_STREAM_OUTPUT;
vertexBufferDesc1.CPUAccessFlags = 0;
vertexBufferDesc1.MiscFlags = 0;
vertexBufferDesc1.StructureByteStride = 0;// I tried to comment this too

Particle p;
ZeroMemory(&p, sizeof(Particle));
p.InitPos = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.InitVel = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.Age = 0.0f;
//p.Type = 100.0f;
D3D11_SUBRESOURCE_DATA vertexBufferData1;
ZeroMemory(&vertexBufferData1, sizeof(vertexBufferData1));
vertexBufferData1.pSysMem = &p;//było &p
vertexBufferData1.SysMemPitch = 0;
vertexBufferData1.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&vertexBufferDesc1, &vertexBufferData1, 
&PartVertBufferInit);

ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.ByteWidth = sizeof(Particle) * numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER | 
D3D11_BIND_STREAM_OUTPUT;
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mDrawVB);
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mStreamOutVB);
}
void ParticleSystem::LoadDataParticles()
{
UINT stride = sizeof(Particle);
UINT offset = 0;

//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VSSO_Buffer- 
//>GetBufferPointer(), 
//  Part_VSSO_Buffer->GetBufferSize(), &PartVertLayout); 
//Set the Input Layout
//context->IASetInputLayout(PartVertLayout);


//Set Primitive Topology
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);

if (mFirstRun)
{
//  context->CopyResource(Popy, PartVertBufferInit);    
context->IASetVertexBuffers(0, 1, &PartVertBufferInit, &stride, 
&offset);   
}
else
{   
context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
}

context->SOSetTargets(1, &mStreamOutVB, &offset);
context->VSSetShader(Part_VSSO, NULL, 0);
context->GSSetShader(Part_GSSO, NULL, 0);
context->PSSetShader(NULL, NULL, 0);
//context->PSSetShader(Part_PS, NULL, 0);

ID3D11DepthStencilState* depthState;//disable depth
D3D11_DEPTH_STENCIL_DESC depthStateDesc;
depthStateDesc.DepthEnable = false;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0); 

if (mFirstRun)
{
//mFirstRun;
context->Draw(1, 0);
mFirstRun = false;
}
else
{
context->DrawAuto();
}
//}
// done streaming-out--unbind the vertex buffer
ID3D11Buffer* bufferArray[1] = { 0 }; 
context->SOSetTargets(1, bufferArray, &offset); 

// ping-pong the vertex buffers
std::swap(mStreamOutVB, mDrawVB);

// Draw the updated particle system we just streamed-out. 

//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VS_Buffer- 
//>GetBufferPointer(),
//  Part_VS_Buffer->GetBufferSize(), &PartVertLayout);

//Set the normal Input Layout
//context->IASetInputLayout(PartVertLayout);

context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
ZeroMemory(&depthStateDesc, sizeof(depthStateDesc));
depthStateDesc.DepthEnable = true;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0);
//I tried add normal layout here the same like Entry SO but no changes
//Set Primitive Topology
//context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
context->VSSetShader(Part_VS, NULL, 0);
context->GSSetShader(Part_GS, NULL, 0);
context->PSSetShader(Part_PS, NULL, 0);
context->DrawAuto();
//mFirstRun = true;
context->GSSetShader(NULL, NULL, 0);
}
void ParticleSystem::RenderParticles()
{
//mFirstRun = true;
LoadDataParticles();
}

And the code of shaders: VertexShader to stream out

struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type     : TYPE;
};

Particle main(Particle vin)
{
return vin;// just push data into geomtrywithso
}

GeometrywithSo

struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type : TYPE;
};
float RandomPosition(float offset)
{
float u = Time + offset;// (Time + offset);
float v = ObjTexture13.SampleLevel(ObjSamplerState, u, 0).r;
return (v);
}

[maxvertexcount(6)]
void main(
point Particle gin[1],
inout PointStream< Particle > Output
)
{
//gin[0].Age = Time;

if ( StartPart == 1.0f  )
{
//if (gin[0].Age < 100.0f)
//{
for (int i = 0; i < 6; i++)
{
float3 VelRandom; //= 5.0f * RandomPosition((float)i / 5.0f);
VelRandom.y = 10.0f+i;
VelRandom.x = 35 * i* RandomPosition((float)i / 5.0f);//+ offse;
VelRandom.z = 10.0f;//35*i * RandomPosition((float)i / 5.0f);
Particle p;
p.InitPos = VelRandom;//float3(0.0f, 5.0f, 0.0f); //+ VelRandom;
p.InitVel = float3(10.0f, 10.0f, 10.0f);
p.Age = 0.0f;//VelRandom.y;
//p.Type = PT_FLARE;
Output.Append(p);

}
Output.Append(gin[0]);
}
else if (StartPart == 0.0f)
{
if (gin[0].Age >= 0)
{
Output.Append(gin[0]);
}
}
}

If I change Age in geometry with so: for example Age += Time from const buffer In geometry shader its fine once but in draw shader it is 0 and next time if it is reading in geometry with so it is 0 too.

Vertex shader to draw

struct VertexOut
{
float3 Pos          : POSITION;
float4 Colour       : COLOR;
//uint Type         : TYPE;
};
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//  uint Type       : TYPE;
};

VertexOut main(Particle vin)
{
VertexOut vout;
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);
float t = vin.Age;
//float b = Time/10000;
// constant Acceleration equation
vout.Pos = vin.InitVel+ (0.7f * gAccelW)*Time/100;
//vout.Pos.x = t;                           
vout.Colour = float4(1.0f, 0.0f, 0.0f, 1.0f);
//vout.Age = vout.Pos.y;
//vout.Type =  vin.Type;

return vout;
}

Geometry shader to change point into line

struct VertexOut
{
float3 Pos          : POSITION;
float4 Colour       : COLOR;
//uint Type         : TYPE;
};

struct GSOutput
{
float4 Pos      : SV_POSITION;
float4 Colour   : COLOR;
//float2 Tex        : TEXCOORD;
};

[maxvertexcount(2)]
void main(
point VertexOut gin[1],
inout LineStream< GSOutput > Output
)
{
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);

//if (gin[0].Type != PT_EMITTER)
{   
float4 v[2];
v[0] = float4(gin[0].Pos, 1.0f);
v[1] = float4((gin[0].Pos + gAccelW), 1.0f);
GSOutput gout;
[unroll]
for (int i = 0; i < 2; ++i)
{
gout.Pos = mul(v[i], WVP);// mul(v[i], gViewProj);
gout.Colour = gin[0].Colour;
Output.Append(gout);
}
}
}

And pixel Shader

struct GSOutput
{
float4 Pos      : SV_POSITION;
float4 Colour   : COLOR;
};

float4 main(GSOutput pin) : SV_TARGET
{
return pin.Colour;
}
  • Note that in the Direct3D 10 timeframe, the idea of using the GS+Stream Out for a GPU particle system was one of the samples (``ParticlesGS``), but in practice the physical hardware never put enough effort into making GS fast. With DirectX 11 and ``D3D_FEATURE_LEVEL_11_0`` or better hardware, the better solution is to use DirectCompute such as the [FluidCS](https://github.com/walbourn/directx-sdk-samples/tree/master/FluidCS11) sample. – Chuck Walbourn May 30 '18 at 16:32
  • Thanks. I try to implement FluidCS, but before I try rewrite my code once again maybe i get mistake somewhere and I don't see that. "Note that in the Direct3D 10 timeframe, the idea of using the GS+Stream Out for a GPU particle system was one of the samples (ParticlesGS), but in practice the physical hardware never put enough effort into making GS fast" Problem is not that method it's not too fast but It lose data of particle somewhere and i had to use only 5 floats because always more than 5th float is 0 :( – Piotr Kowalski May 31 '18 at 10:28
  • Maybe it is some method to see Vertex Buffers in each step of pipeline?? Or I saw the D3D11_SO_DECLARATION_ENTRY have option to use 0-4 slots of data.Now I use only one, maybe i can push other data in other slots but how to use that option ?? And it slows performance?? – Piotr Kowalski May 31 '18 at 10:35
  • I use D3D11_CREATE_DEVICE_DEBUG flag and i get warning that input layout size is too less 28 (minimum is 32 bits) and a lot of D3D11 WARNING: Live Object at 0x00FCF224, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]. I repaired first warning by add one float more to D3D11_SO_DECLARATION_ENTRY, but that didn't change anything. Could be the second warning is my problem?? – Piotr Kowalski Jun 02 '18 at 14:16

0 Answers0