Я пытаюсь добавить систему частиц в свою графическую демонстрацию Directx11, и поэтому я использовал «Введение в 3d-программирование игры с помощью DirectX 11».HLSL Система частиц не отображает
Из-за этого я пытаюсь использовать технику HLSL StreamOut для обновления системы частиц и отдельной техники для визуализации частиц.
Ниже приведен код HLSL для системы частиц, я пробовал регулировать ускорение и скорость, когда скорость посылала частицы с экрана, однако это не имело никакого эффекта.
cbuffer cbPerFrame
{
\t float3 gEyePosW;
\t
\t float3 gEmitPosW;
\t float3 gEmitDirW;
\t float gGameTime;
\t float gTimeStep;
\t float4x4 gViewProj;
};
cbuffer cbFixed
{
\t // Net constant acceleration used to accerlate the particles.
\t float3 gAccelW = {0.0f, 0.2f, 0.0f};
\t // Texture coordinates for billbording are always the same - we use a qquad in this effect :)
\t float2 gTexC[4] =
\t {
\t \t float2(0.0f, 1.0f),
\t \t float2(0.0f, 0.0f),
\t \t float2(1.0f, 1.0f),
\t \t float2(1.0f, 0.0f)
\t };
};
// Nonnumeric values cannot be added to a cbuffer.
Texture2DArray gTextureMapArray;
// Random texture used to generate random numbers in shaders.
Texture1D gRandomTexture;
SamplerState samLinear
{
\t Filter = MIN_MAG_MIP_LINEAR;
\t AddressU = WRAP;
\t AddressV = WRAP;
};
DepthStencilState DisableDepth
{
DepthEnable = FALSE;
DepthWriteMask = ZERO;
};
DepthStencilState NoDepthWrites
{
DepthEnable = TRUE;
DepthWriteMask = ZERO;
};
BlendState AdditiveBlending
{
AlphaToCoverageEnable = FALSE;
BlendEnable[0] = TRUE;
SrcBlend = SRC_ALPHA;
DestBlend = ONE;
BlendOp = ADD;
SrcBlendAlpha = ZERO;
DestBlendAlpha = ZERO;
BlendOpAlpha = ADD;
RenderTargetWriteMask[0] = 0x0F;
};
///////////////////////////////////////////////////////////////
// \t \t Helper functions
//
///////////////////////////////////////////////////////////////
float3 RandUnitVec3(float offset)
{
\t // Use game time plus offset to sample random texture.
\t float u = (gGameTime + offset);
\t
\t // coordinates in [-1,1]
\t float3 v = gRandomTexture.SampleLevel(samLinear, u, 0).xyz;
\t
\t // project onto unit sphere (Normalize)
\t return normalize(v);
}
///////////////////////////////////////////////////////////////
// \t \t Stream Out Technique
//
///////////////////////////////////////////////////////////////
#define PT_EMITTER 0
#define PT_FLARE 1
struct Particle
{
\t float3 InitPosW : POSITION;
\t float3 InitVelW : VELOCITY;
\t float2 SizeW \t : SIZE;
\t float Age \t \t : AGE;
\t uint Type \t \t : Type;
};
Particle StreamOutVS(Particle vin)
{
\t return vin;
}
// The stream-out GS is just responsible for emitting
// new particles and destroying old particles. The logic
// programed here will generally vary from particle system
// to particle system, as the destroy/spawn rules will be
// different.
[maxvertexcount(2)]
void StreamOutGS(point Particle gin[1],
\t \t \t \t inout PointStream<Particle> ptStream)
{
\t gin[0].Age += gTimeStep;
\t // if particle is emitter particle
\t if (gin[0].Type == PT_EMITTER)
\t {
\t \t // If it's time to emit new particle
\t \t if (gin[0].Age > 0.005f)
\t \t {
\t \t \t float3 vRandom = RandUnitVec3(0.0f);
\t \t \t vRandom.x *= 0.5f;
\t \t \t vRandom.z *= 0.5f;
\t \t \t Particle p;
\t \t \t p.InitPosW \t = gEmitPosW.xyz;
\t \t \t p.InitVelW \t = 0.5f*vRandom;
\t \t \t p.SizeW \t \t = float2(3.0f, 3.0f);
\t \t \t p.Age \t \t = 0.0f;
\t \t \t p.Type \t \t = PT_FLARE;
\t \t \t ptStream.Append(p);
\t \t \t // reset the time to emit
\t \t \t gin[0].Age = 0.0f;
\t \t }
\t \t // always keep emitters
\t \t ptStream.Append(gin[0]);
\t }
\t else
\t {
\t \t // Set conditions to keep a particle - in this case age limit
\t \t if (gin[0].Age <= 1.0f)
\t \t {
\t \t \t ptStream.Append(gin[0]);
\t \t }
\t }
}
GeometryShader gsStreamOut = ConstructGSWithSO(
\t \t CompileShader(gs_5_0, StreamOutGS()),
\t \t "POSITION.xyz; VELOCITY.xyz; SIZE.xyz; AGE.x; TYPE.x");
technique11 StreamOutTech
{
\t pass P0
\t {
\t \t SetVertexShader(CompileShader(vs_5_0, StreamOutVS()));
\t \t SetGeometryShader(gsStreamOut);
\t \t // disable pixel shader for stream-out only
SetPixelShader(NULL);
// we must also disable the depth buffer for stream-out only
SetDepthStencilState(DisableDepth, 0);
\t }
}
///////////////////////////////////////////////////////////////
// \t \t Draw Technique
//
///////////////////////////////////////////////////////////////
struct VertexIn
{
\t float3 Pos : POSITION;
\t float2 SizeW : SIZE;
};
struct VertexOut
{
\t float3 PosW \t \t \t : POSITION;
float2 SizeW \t \t : SIZE;
\t float4 Colour \t \t : COLOR;
\t uint Type \t \t \t : TYPE;
};
VertexOut DrawVS(Particle vin)
{
\t VertexOut vout;
\t float t = vin.Age;
\t // constant Acceleration equation
\t vout.PosW = 0.5f*t*t*gAccelW + t*vin.InitVelW + vin.InitPosW;
\t // fade colour with time
\t float opacity = 1.0f - smoothstep(0.0f, 1.0f, t/1.0f);
\t vout.Colour = float4(1.0f, 1.0f, 1.0f, opacity);
\t vout.SizeW = vin.SizeW;
\t vout.Type = vin.Type;
\t return vout;
}
struct GeoOut
{
\t float4 PosH \t \t : SV_POSITION;
float4 Colour \t : COLOR;
float2 Tex \t \t : TEXCOORD;
};
// Expand each 'Point' into a quad (4 verticies)
[maxvertexcount(4)]
void DrawGS(point VertexOut gin[1],
\t \t inout TriangleStream<GeoOut> triStream)
{
\t // Do not draw Emiter particles in this system
\t if (gin[0].Type != PT_EMITTER)
\t {
\t \t //
\t \t // Compute world matrix so that billboard faces the camera.
\t \t //
\t \t float3 look = normalize(gEyePosW.xyz - gin[0].PosW);
\t \t float3 right = normalize(cross(float3(0,1,0), look));
\t \t float3 up = cross(look, right);
\t \t //
\t \t // Compute triangle strip vertices (quad) in world space.
\t \t //
\t \t float halfWidth = 0.5f*gin[0].SizeW.x;
\t \t float halfHeight = 0.5f*gin[0].SizeW.y;
\t \t float4 v[4];
\t \t v[0] = float4(gin[0].PosW + halfWidth*right - halfHeight*up, 1.0f);
\t \t v[1] = float4(gin[0].PosW + halfWidth*right + halfHeight*up, 1.0f);
\t \t v[2] = float4(gin[0].PosW - halfWidth*right - halfHeight*up, 1.0f);
\t \t v[3] = float4(gin[0].PosW - halfWidth*right + halfHeight*up, 1.0f);
\t \t //
\t \t // Transform quad vertices to world space and output
\t \t // them as a triangle strip.
\t \t //
\t \t GeoOut gout;
\t \t [unroll]
\t \t for(int i = 0; i < 4; ++i)
\t \t {
\t \t \t gout.PosH = mul(v[i], gViewProj);
\t \t \t gout.Tex = gTexC[i];
\t \t \t gout.Colour = gin[0].Colour;
\t \t \t triStream.Append(gout);
\t \t }
\t } \t
}
float DrawPS(GeoOut pin) : SV_TARGET
{
\t return gTextureMapArray.Sample(samLinear, float3(pin.Tex, 0)) * pin.Colour;
}
technique11 DrawTech
{
pass P0
{
SetVertexShader( CompileShader(vs_5_0, DrawVS()));
SetGeometryShader(CompileShader(gs_5_0, DrawGS()));
SetPixelShader( CompileShader(ps_5_0, DrawPS()));
SetBlendState(AdditiveBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff);
SetDepthStencilState(NoDepthWrites, 0);
}
}
Ниже приведен код для построения VB.
void ParticleSystem::BuildVB(ID3D11Device* device)
{
\t /////////////////////////////////////////////////////////
\t // Create the buffer to start the particle system.
\t /////////////////////////////////////////////////////////
\t D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_DEFAULT;
\t vbd.ByteWidth = sizeof(Vertex::Particle) * 1;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
\t vbd.StructureByteStride = 0;
\t // The initial particle emitter has type 0 and age 0. The rest
\t // of the particle attributes do not apply to an emitter.
\t Vertex::Particle p;
\t ZeroMemory(&p, sizeof(Vertex::Particle));
\t p.Age = 0.0f;
\t p.Type = 0;
\t D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &p;
\t HR(device->CreateBuffer(&vbd, &vinitData, &mInitVB));
\t //////////////////////////////////////////////////////////////
\t // Create the buffers which swap back and forth for stream-out and drawing.
\t //////////////////////////////////////////////////////////////
\t vbd.ByteWidth = sizeof(Vertex::Particle) * mMaxParticles;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
\t HR(device->CreateBuffer(&vbd, 0, &mDrawVB));
\t HR(device->CreateBuffer(&vbd, 0, &mStreamOutVB));
}
И теперь код Draw каст.
void ParticleSystem::Draw(ID3D11DeviceContext* dc, const XMMATRIX& viewProj)
{
\t //
\t // Set constants.
\t //
\t mFX->SetViewProj(viewProj);
\t mFX->SetGameTime(mGameTime);
\t mFX->SetTimeStep(mTimeStep);
\t mFX->SetEyePosW(mEyePosW);
\t mFX->SetEmitPosW(mEmitPosW);
\t mFX->SetEmitDirW(mEmitDirW);
\t mFX->SetTexArray(mTextureArraySRV);
\t mFX->SetRandomTex(mRandomTextureSRV);
\t //
\t // Set IA stage.
\t //
\t dc->IASetInputLayout(InputLayouts::Particle);
dc->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
\t UINT stride = sizeof(Vertex::Particle);
UINT offset = 0;
\t // On the first pass, use the initialization VB. Otherwise, use
\t // the VB that contains the current particle list.
\t if(mFirstRun)
\t \t dc->IASetVertexBuffers(0, 1, &mInitVB, &stride, &offset);
\t else
\t \t dc->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
\t //
\t // Draw the current particle list using stream-out only to update them.
\t // The updated vertices are streamed-out to the target VB.
\t //
\t dc->SOSetTargets(1, &mStreamOutVB, &offset);
\t D3DX11_TECHNIQUE_DESC techDesc;
\t mFX->StreamOutTech->GetDesc(&techDesc);
for(UINT p = 0; p < techDesc.Passes; ++p)
{
mFX->StreamOutTech->GetPassByIndex(p)->Apply(0, dc);
\t \t if(mFirstRun)
\t \t {
\t \t \t dc->Draw(1, 0);
\t \t \t mFirstRun = false;
\t \t }
\t \t else
\t \t {
\t \t \t dc->DrawAuto();
\t \t }
}
\t // done streaming-out--unbind the vertex buffer
\t ID3D11Buffer* bufferArray[1] = {0};
\t dc->SOSetTargets(1, bufferArray, &offset);
\t // ping-pong the vertex buffers
\t std::swap(mDrawVB, mStreamOutVB);
\t //
\t // Draw the updated particle system we just streamed-out.
\t //
\t dc->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
\t mFX->DrawTech->GetDesc(&techDesc);
for(UINT p = 0; p < techDesc.Passes; ++p)
{
mFX->DrawTech->GetPassByIndex(p)->Apply(0, dc);
\t \t dc->DrawAuto();
}
}
Я думал, что, возможно, либо состояние смеси или состояние глубины используется некоторыми из других объектов в моей сцене может быть причиной проблемы, (возможно, я неправильно понял то, что я установленный ранее). Я попытался удалить все остальные коды рендеринга, оставив только код ничьей выше, но без результатов.
На мой взгляд, я могу думать только о нескольких возможных причинах проблемы, которые у меня есть, но пока я не могу найти решение.
- Шкала системы неверна для моей сцены. например. частицы рисуют, но движутся с экрана, чтобы быстро видеть.
- Как уже упоминалось выше, я попытался удалить ускорение и скорость частиц в коде HLSL, чтобы увидеть неподвижные частицы. Это не имело никакого эффекта.
- Состояние смесителя/состояние трафарета неправильное. Например. Как уже упоминалось выше.
- Частица эмиттера по какой-либо причине не производится/размещается правильно. в результате чего по очереди не образуются «выталкиваемые» частицы. Поскольку большая часть этого кода находится в файле .fx, я не могу пройти, чтобы проверить частицы эмиттера. Я думаю, что это более вероятная проблема, но я раньше ошибался.
Любая помощь по этому вопросу была бы очень признательна, я хорошо и по-настоящему придерживался этого. Ниже я добавил дополнительные фрагменты кода, которые могут быть полезны.
E.G. Макет ввода.
const D3D11_INPUT_ELEMENT_DESC InputLayoutDesc::Particle[5] =
{
\t {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
\t {"VELOCITY", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
\t {"SIZE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
\t {"AGE", 0, DXGI_FORMAT_R32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
\t {"TYPE", 0, DXGI_FORMAT_R32_UINT, 0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
и система частиц INIT
mFire.Init(md3dDevice, AppEffects::FireFX, mFlareTextureSRV, mRandomTextureSRV, 500);
\t mFire.SetEmitPos(XMFLOAT3(1.0f, 0.5f, 0.0f));
void ParticleSystem::Init(ID3D11Device* device, ParticleEffect* fx,
\t \t ID3D11ShaderResourceView* textureArraySRV,
\t \t ID3D11ShaderResourceView* randomTextureSRV,
\t \t UINT maxParticles)
{
\t mMaxParticles = maxParticles;
\t mFX = fx;
\t mTextureArraySRV = textureArraySRV;
\t mRandomTextureSRV = randomTextureSRV;
\t BuildVB(device);
}
Если я пропустил какой-либо участок кода, который вы должны были бы видеть, дайте мне знать.
Заранее спасибо.