2015-02-09 9 views
0

Я пытаюсь добавить систему частиц в свою графическую демонстрацию 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(); 
 
    } 
 

 
}

Я думал, что, возможно, либо состояние смеси или состояние глубины используется некоторыми из других объектов в моей сцене может быть причиной проблемы, (возможно, я неправильно понял то, что я установленный ранее). Я попытался удалить все остальные коды рендеринга, оставив только код ничьей выше, но без результатов.

На мой взгляд, я могу думать только о нескольких возможных причинах проблемы, которые у меня есть, но пока я не могу найти решение.

  1. Шкала системы неверна для моей сцены. например. частицы рисуют, но движутся с экрана, чтобы быстро видеть.
    • Как уже упоминалось выше, я попытался удалить ускорение и скорость частиц в коде HLSL, чтобы увидеть неподвижные частицы. Это не имело никакого эффекта.
  2. Состояние смесителя/состояние трафарета неправильное. Например. Как уже упоминалось выше.
  3. Частица эмиттера по какой-либо причине не производится/размещается правильно. в результате чего по очереди не образуются «выталкиваемые» частицы. Поскольку большая часть этого кода находится в файле .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); 
 
}

Если я пропустил какой-либо участок кода, который вы должны были бы видеть, дайте мне знать.

Заранее спасибо.

ответ

0

Извините за этот глупый вопрос. Оказывается, это была глупая ошибка в пиксельном шейдере. Я установил пиксельный шейдер как float вместо float4.