Search code examples
graphicsrenderingdirectxdirectxtk

Applying a texture to a custom effect using DirectXTK results in the texture being stretched


I'm trying to apply a custom effect using the DirectXTK. The effect is supposed to be an "unlit" shader with just one texture. But for some reason, the texture is stretched across the model. I looked in renderdoc and the texturecoordinates appear to be loaded correctly so i'm not sure what's going on.

UnlitEffect.h

#pragma once
#include <vector>
class UnlitEffect : public DirectX::IEffect, public DirectX::IEffectMatrices
{
public:
    explicit UnlitEffect(ID3D11Device* device);
    UnlitEffect() = default;
    virtual void Apply(_In_ ID3D11DeviceContext* deviceContext) override;
    virtual void GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) override;
    void SetTexture(ID3D11ShaderResourceView* value);

    void XM_CALLCONV SetWorld(DirectX::FXMMATRIX value) override;
    void XM_CALLCONV SetView(DirectX::FXMMATRIX value) override;
    void XM_CALLCONV SetProjection(DirectX::FXMMATRIX value) override;
    void XM_CALLCONV SetMatrices(DirectX::FXMMATRIX world, DirectX::CXMMATRIX view, DirectX::CXMMATRIX projection) override;

    struct __declspec(align(16)) UnlitEffectConstants
    {
        DirectX::XMMATRIX MVP;
    };

    DirectX::ConstantBuffer<UnlitEffectConstants> m_constantBuffer;

protected:
    Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vs;
    Microsoft::WRL::ComPtr<ID3D11PixelShader> m_ps;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_texture;
    std::vector<uint8_t> m_vsBlob;

    DirectX::SimpleMath::Matrix m_World;
    DirectX::SimpleMath::Matrix m_View;
    DirectX::SimpleMath::Matrix m_Projection;
    DirectX::SimpleMath::Matrix m_MVP;

    uint32_t m_dirtyFlags;
};

UnlitEffect.cpp

#include "pch.h"
#include "UnlitEffect.h"
#include "ReadData.h"
namespace
{
    constexpr uint32_t DirtyConstantBuffer = 0x1;
    constexpr uint32_t DirtyMVPMatrix= 0x2;
}

UnlitEffect::UnlitEffect(ID3D11Device* device)
    :m_constantBuffer(device),m_dirtyFlags(uint32_t(-1))
{
    m_vsBlob = DX::ReadData(L"Shaders/UnlitVS.cso");

    DX::ThrowIfFailed(
        device->CreateVertexShader(m_vsBlob.data(), m_vsBlob.size(), nullptr, m_vs.ReleaseAndGetAddressOf())
    );

    auto ps_blob = DX::ReadData(L"Shaders/UnlitPS.cso");
    DX::ThrowIfFailed(
        device->CreatePixelShader(ps_blob.data(), ps_blob.size(), nullptr, m_ps.ReleaseAndGetAddressOf())
    );
}

void UnlitEffect::Apply(_In_ ID3D11DeviceContext* deviceContext)
{
    
    if(m_dirtyFlags & DirtyMVPMatrix)
    {
        m_MVP = m_World * m_View;
        m_MVP = m_MVP * m_Projection;

        m_dirtyFlags &= ~DirtyMVPMatrix;
        m_dirtyFlags |= DirtyConstantBuffer;
    }

    if(m_dirtyFlags & DirtyConstantBuffer)
    {
        UnlitEffectConstants constants;

        constants.MVP = m_MVP.Transpose();
        m_constantBuffer.SetData(deviceContext, constants);

        m_dirtyFlags &= ~DirtyConstantBuffer;
    }

    auto cb = m_constantBuffer.GetBuffer();

    deviceContext->VSSetConstantBuffers(0, 1, &cb);
    deviceContext->PSSetShaderResources(0, 1, m_texture.GetAddressOf());
    
    deviceContext->VSSetShader(m_vs.Get(), nullptr, 0);
    deviceContext->PSSetShader(m_ps.Get(), nullptr, 0);
}

void UnlitEffect::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength)
{
    assert(pShaderByteCode != nullptr && pByteCodeLength != nullptr);
    *pShaderByteCode = m_vsBlob.data();
    *pByteCodeLength = m_vsBlob.size();
}

void UnlitEffect::SetTexture(ID3D11ShaderResourceView* value)
{
    m_texture = value;
}

void XM_CALLCONV UnlitEffect::SetWorld(DirectX::FXMMATRIX value)
{
    m_World = value;
    m_dirtyFlags |= DirtyMVPMatrix;
}

void XM_CALLCONV UnlitEffect::SetView(DirectX::FXMMATRIX value)
{
    m_View = value;
    m_dirtyFlags |= DirtyMVPMatrix;
}

void XM_CALLCONV UnlitEffect::SetProjection(DirectX::FXMMATRIX value)
{
    m_Projection = value;
    m_dirtyFlags |= DirtyMVPMatrix;
}

void XM_CALLCONV UnlitEffect::SetMatrices(DirectX::FXMMATRIX world, DirectX::CXMMATRIX view, DirectX::CXMMATRIX projection)
{
    m_View = view;
    m_World = world;
    m_Projection = projection;
    m_dirtyFlags |= DirtyMVPMatrix;
}

Unlit.hlsli

#ifndef __UNLINT_HLSLI__
#define __UNLINT_HLSLI__



cbuffer UnlitConstants : register(b0)
{
    float4x4 MVP;
}

struct VSOutput
{
    float4 PositionPS : SV_Position;
    float2 TexCoord : TEXCOORD0;
};

struct VSInput
{
    float4 Position : SV_Position;
    float2 TexCoord : TEXCOORD0;
};

#endif

UnlitPS.hlsl

#include "Unlit.hlsli"

Texture2D BaseColor : register(t0);
SamplerState SampleType : register(s0);

float4 main(VSOutput vout) : SV_TARGET0
{
    return BaseColor.Sample(SampleType, normalize(vout.TexCoord));

}

UnlitVS.hlsl

#include "Unlit.hlsli"


VSOutput main(VSInput vin)
{
    VSOutput vout;
    vout.PositionPS = mul(vin.Position, MVP);
    vout.TexCoord = vin.TexCoord;
    return vout;

}

here is the result


Solution

  • Chuck Walbourn was correct. My issue was that I was normalizing my texture coordinates in the pixel shader. The correct code is return BaseColor.Sample(SampleType, vout.TexCoord);