Search code examples
c++hlsldirectx-11

Set uniform color to pixel shader


I am a newbie in DirectX11, so sorry for a dull question. I have a pixel shader:

struct PixelShaderInput
{
    float4 pos : SV_POSITION;   
    float2 texCoord : TEXCOORD0;
};

Texture2D s_texture : register(t0);

SamplerState s_sampleParams
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = CLAMP;
    AddressV = CLAMP;
};

float4 main(PixelShaderInput input) : SV_TARGET
{
    float4 t = s_texture.Sample(s_sampleParams, input.texCoord);
    return t;
}

Now I want to add a color to my shader:

struct PixelShaderInput
{
    float4 pos : SV_POSITION;   
    float2 texCoord : TEXCOORD0;
};

Texture2D s_texture : register(t0);
float4 s_color;

SamplerState s_sampleParams
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = CLAMP;
    AddressV = CLAMP;
};

float4 main(PixelShaderInput input) : SV_TARGET
{
    float4 t = s_texture.Sample(s_sampleParams, input.texCoord);
    return t * s_color;
}

How do I set s_color from C++ code? Do I have to use m_d3dContext->PSSetConstantBuffers? In this case I should change

`float4 s_color;`

to

cbuffer ColorOnlyConstantBuffer : register(b0)
{
    float4 m_color;
};

, right?

Or I can keep simple definition float4 s_color; and set it from C++ somehow else?


Solution

  • As far as I remember, you specify input items for vertex shader by using specific structure:

    D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[2] =
    {
        { "Position",
            0,
            DXGI_FORMAT_R32G32B32_FLOAT,
            0,
            D3D11_APPEND_ALIGNED_ELEMENT,
            D3D11_INPUT_PER_VERTEX_DATA,
            0
        },
        { "Color",
          0,
          DXGI_FORMAT_R32G32B32_FLOAT,
          0,
          D3D11_APPEND_ALIGNED_ELEMENT,
          D3D11_INPUT_PER_VERTEX_DATA,
          0
        }
    };
    

    This structure is being used to create ID3D11InputLayout:

    const UINT inputLayoutDescCount = 2;
    
    hr = device->CreateInputLayout(
        inputLayoutDesc,
        inputLayoutDescCount,
        compiledVsShader->GetBufferPointer(),
        compiledVsShader->GetBufferSize(),
        &inputLayout);
    

    You can then use semantics to specify, which element represents which entry:

    struct VS_INPUT
    {
        float4 Pos : POSITION;
        float4 Col : COLOR;
    };
    

    Edit: in response to comments.

    Sorry, didn't get that. You'll need a constant buffer. Relevant (sample) parts of code follows. Just modify them to your needs:

    struct PixelConstantBuffer
    {
        XMFLOAT4 lightPos;
        XMFLOAT4 observerPos;
    };
    
    // ***
    
    D3D11_BUFFER_DESC pixelConstantBufferDesc;
    pixelConstantBufferDesc.ByteWidth = sizeof(PixelConstantBuffer);
    pixelConstantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    pixelConstantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    pixelConstantBufferDesc.CPUAccessFlags = 0;
    pixelConstantBufferDesc.MiscFlags = 0;
    pixelConstantBufferDesc.StructureByteStride = 0;
    
    hr = device->CreateBuffer(&pixelConstantBufferDesc, nullptr, &pixelConstantBuffer);
    
    // ***
    
    context->PSSetConstantBuffers(1, 1, &pixelConstantBuffer);
    context->PSSetShader(pixelShader, nullptr, 0);
    
    // ***
    
    PixelConstantBuffer pcBuffer;
    pcBuffer.lightPos = XMFLOAT4(lightPos.m128_f32[0], lightPos.m128_f32[1], lightPos.m128_f32[2], lightPos.m128_f32[3]);
    pcBuffer.observerPos = XMFLOAT4(camPos.m128_f32[0], camPos.m128_f32[1], camPos.m128_f32[2], camPos.m128_f32[3]);
    
    context->UpdateSubresource(pixelConstantBuffer, 0, nullptr, &pcBuffer, 0, 0);
    
    // *** (hlsl)
    
    cbuffer PixelConstantBuffer : register(b1)
    {
        float4 LightPos;
        float4 ObserverPos;
    }