0
votes

I'm very new at directx11, and I wanted to add texture to a shader I'm using. (until now, I hadn't used any texture yet in directx11)

But sampling doesn't seem to work (it's always float4(0,0,0,0)), and I get the warning: "D3D11 WARNING: ID3D11DeviceContext::DrawIndexed: The Pixel Shader unit expects a Sampler to be set at Slot 0, but none is bound."

I searched for this, but all answers say to use

_d3dContext->PSSetSamplers(0, 1, &_sampler);

But I already do that. Does anyone know what could be wrong?

This is my entire shader:

Texture2D tex;
SamplerState TexSampler : register(S0)
{
    Texture = (Slope);
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = clamp;
    AddressV = clamp;
};

struct PixelShaderInput
{
    float4 color : COLOR0;
    //.r : slope
    //.g : relative distance on road (compared the the rider)
    //.b : shadow (currently darker on lower parts)
    //.a : cameradepth
    float fogfactor : COLOR1;
};

float4 main(PixelShaderInput input) : SV_TARGET
{
    const float4 fogColor = float4(0.9, 0.9, 1, 1);

    const float halfWidth = 0.0016f;

    float4 color;

    if (input.color.g < -halfWidth * input.color.a)
    {
        color = float4(0.5, 0.85, 1, 1);
    }
    else if (input.color.g < halfWidth * input.color.a)
    {
        color = float4(1, 1, 1, 1);
    }
    else
    {
        color = tex.Sample(TexSampler, float2(input.color.r, 0.5));
    }

    if (input.color.b < 0.999)
    {
        input.color.b *= 0.94; //makes the sides a bit darker
    }
    color.rgb *= input.color.b;

    color.rgb = lerp(color.rgb, fogColor.rgb, input.fogfactor);

    return color;
}

And in c++/cx I do this (not the full code, just fragments):

Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    _slopeGradient;
Microsoft::WRL::ComPtr<ID3D11SamplerState>          _sampler;

D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
_d3dDevice->CreateSamplerState(&sampDesc, &_sampler);

_d3dContext->PSSetShaderResources(0, 1, &_slopeGradient);
_d3dContext->PSSetSamplers(0, 1, &_sampler);
1

1 Answers

3
votes

The problem is your usage of ComPtr. The operator& overload for Microsoft::WRL::ComPtr calls ReleaseAndGetAddressOf, not GetAddressOf. Therefore, you are basically doing this right now which is always setting these resources to nullptr (i.e. clearing the slot):

_d3dContext->PSSetShaderResources(0, 1, _slopeGradient.ReleaseAndGetAddressOf());
_d3dContext->PSSetSamplers(0, 1, _sampler.ReleaseAndGetAddressOf());

You should use:

_d3dContext->PSSetShaderResources(0, 1, _slopeGradient.GetAddressOf());
_d3dContext->PSSetSamplers(0, 1, _sampler.GetAddressOf());

The old ATL CComPtr had the operator& overload map toGetAddressOf but asserted that it was a nullptr which often resulted in inadvertent memory leaks. The operator& is assumed to be used in initialization by these smart-pointers, and that's not what you are doing here. You really want the address of the initialized raw pointer.

Remember that both of these methods are actually taking an array of COM pointers. In C you can of course treat a pointer as an array of size one, but you may find it more clear to do something like:

ID3D11ShaderResourceView* srvs[] = { _slopeGradient.GetAddressOf() };
_d3dContext->PSSetShaderResources(0, _countof(srvs), srvs);

ID3D11SamplerState* samplers[] = { _sampler.GetAddressOf() };
_d3dContext->PSSetSamplers(0, _countof(samplers), samplers);

Also note that you are defining some elements of the legacy Effects system in your HLSL source that is ignored in standard DirectX API usage. You can just delete it.

{
    Texture = (Slope);
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = clamp;
    AddressV = clamp;
}

As you are new to DirectX 11, you should look at DirectX Tool Kit.