Search code examples
c++shaderdirectx-11fragment-shadercompute-shader

Why is Constant Buffer initialized in Compute Shader, but not in Pixel Shader?


I'm learning DirectX11 and trying to make a Particle System. I have a structure in C++ that corresponds to the cbuffer in .hlsl. In my compute shader I can access cbuffer's variable. However in other shaders of the graphics pipeline, such as pixel or geometry shader, the value is not initialized.

Therefore I currently have a black square floating around, when it should be white.

This is my CBUFFER in C++ :

CBUFFER(ParticleSystemCB, CBSLOT_PARTICLESYSTEM)
{
    lu::math::Color startTint;
    lu::math::Color endTint;
    lu::math::Quaternion startRot;
    lu::math::Quaternion endRot;
    float lifeTime;
    float elapsedTime;
    float deltaTime;

    float startSize;
    float endSize;
    float startSpeed;
    float endSpeed;
    
    int elementCount;
};

And my cbuffer in .hlsl:

cbuffer ParticleSystem : register(b3)
{
    float4  particleStartTint;
    float4  particleEndTint;
    float4  particleStartRotation;
    float4  particleEndRotation;
    float   particleLifetime;
    float   particleElapsedTime;
    float   particleDeltaTime;
    
    float   particleStartSize;
    float   particleEndSize;
    float   particleStartSpeed;
    float   particleEndSpeed;
    
    uint elementCount;
}

I am binding all my shaders every frame, in the order of transform constant buffer -> particle constant buffer-> other shaders.

graphics::StructedBuffer* mParticleBuffer;
graphics::StructedBuffer* mSharedBuffer;
std::shared_ptr<ParticleShader> mParticleShader;

void ParticleSystem::Render()
{
    Owner()->GetComponent<Transform>()->BindConstantBuffer();
    mParticleShader->OnExecute();//binds and dispatches compute shader
    mParticleShader->SetParticles(mParticleBuffer, this);
    mParticleShader->SetSharedBuffer(mSharedBuffer);

    mParticleBuffer->BindSRV(eShaderStage::VS, 14);
    mParticleBuffer->BindSRV(eShaderStage::GS, 14);
    mParticleBuffer->BindSRV(eShaderStage::PS, 14);

    GetMaterial()->Binds();
    GetMesh()->RenderInstanced(1000);

    mParticleBuffer->clear();
}
void ParticleShader::SetParticles(StructedBuffer* particleBuffer, ParticleSystem* ps)
{
    mParticleBuffer = particleBuffer;
    ConstantBuffer* cb = renderer::constantBuffer[(UINT)eCBType::ParticleSystem];

    renderer::ParticleSystemCB data = {};
    data.startTint = ps->mStartTint;
        //and other data Initializations

    cb->SetData(&data);
    cb->Bind(eShaderStage::CS);
}

In my compute shader I am assigning particleLifetime, which is correctly applied:

RWStructuredBuffer<Particle> ParticleBuffer : register(u0);
RWStructuredBuffer<ParticleShared> ParticleSharedBuffer : register(u1);

void InitializeParticle(int id)
{
//correctly assigned
    ParticleBuffer[id].lifeTime = particleLifetime;
}

And in my pixel shader particleStartTint should be white(1, 1, 1, 1), but color was (0, 0, 0, 0), I tweaked w to make it visible.

float4 main(GSOut In) : SV_TARGET
{
    color = particleStartTint;
    color.w = 1;

    return color;
}

These are the parts I confirmed:

  • there are no syntax errors in .hlsl (ID3DBlob check)
  • cbuffer slot is correct (I tripled checked)
  • structure CBUFFER has correct info
  • Compute Shader after cbuffer has binded correctly retrieves information
  • pixel shader is also binded after cbuffer, but does not work

Currently I want the resulting color to be white.

Thank you for taking your time.


Solution

  • cb->Bind(eShaderStage::CS);
    

    You only bind your cbuffer to the compute stage, you also need to do :

    cb->Bind(eShaderStage::PS);
    

    (You need to bind it to every stage where you use the cbuffer also, so if you use it on other graphics stages, you need to bind there too)