DirectX::SpriteBatchで円形ゲージを表示する(DirectX11)


画像の表示の仕方が分からない方は
https://qiita.com/akurobit/items/e26d5f43ad325cee3439
をご覧ください、多分これで出来ると思います...

概要

今回説明する方法は、ピクセルシェーダーで不要なピクセルを削除するというものです。

こんな感じで角度θより小さい角度のピクセルは残す、大きければピクセルを削除するようにします。
xは角度がθより小さいので残す、zはθより大きいので削除する、といった感じです。

CPU側

sprite.h
const float PI = 3.14159f;

class Sprite {
public:
    .
    .
    .
private:
    DirectX::SpriteBatch* m_spriteBatch   //SpriteBatch
    ID3D11Buffer* m_buffer = nullptr;   //定数バッファです
    float m_degree = 360.0f;   //角度です
    ID3D11Device* m_device   //構築済みとする
    ID3D11PixelShader* m_shader   //シェーダーの読み込みについてはよくわからなかったです...
};

定数バッファの作成をします。

sprite.cpp
int bufferSize = sizeof(float);
    //どんなバッファを作成するのかをせてbufferDescに設定する。
    D3D11_BUFFER_DESC bufferDesc;
    {
        ZeroMemory(&bufferDesc, sizeof(bufferDesc));                //0でクリア。
        bufferDesc.Usage = D3D11_USAGE_DEFAULT;                     //バッファで想定されている、読み込みおよび書き込み方法。
        bufferDesc.ByteWidth = (((bufferSize2 - 1) / 16) + 1) * 16; //バッファは16バイトアライメントになっている必要がある。
                                                                        //アライメントって→バッファのサイズが16の倍数ということです。
        bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;          //バッファをどのようなパイプラインにバインドするかを指定する。
                                                                        //定数バッファにバインドするので、D3D11_BIND_CONSTANT_BUFFERを指定する。
        bufferDesc.CPUAccessFlags = 0;
    }                               
    m_device->CreateBuffer(&bufferDesc, NULL, &m_buffer);

ドローする際に角度を定数バッファとしてGPUに送ります。
DirectX::SpriteBatchではBegin関数で定数バッファをGPUに送るやシェーダーの設定などを書きます。

sprite.cpp
Draw()
{
    //1フレームごとに角度を-1します
    m_degree -= 1.0f; 


    m_spriteBatch>Begin(
    DirectX::SpriteSortMode_BackToFront,
                        nullptr,
                        nullptr,
                        nullptr,
                        nullptr,
                        [=]
        {
            //角度をラジアン単位に変換します
            float angle = (m_degree * PI) / 180.0f;
            //角度用の定数バッファを更新します
            m_device->UpdateSubresource(
                                    m_buffer,
                                    0,
                                    nullptr,
                                    &angle,
                                    0,
                                    0);

            //角度用の定数バッファを更新します
            m_device->PSSetConstantBuffers(1, 1, &m_buffer);
            //ピクセルシェーダーを設定します
            m_device->PSSetShader(m_shader, nullptr, 0);
        }
    );
    //以下は通常と同じ
     .
     .
     .

}

シェーダー

sprite.fx
//角度
float Angle : register(t1);
//カラーテクスチャ
Texture2D<float4> Texture : register(t0);
//サンプラー
sampler TextureSampler : register(s0);

//ピクセルシェーダー
//引き数はこれで固定です、多分
float4 PSMain(
    float4 color : COLOR0,
    float2 texCoord : TEXCOORD0) : SV_Target0
{
    float PI = 3.14159f;
    //こっからなんかおかしいかもしれません
    float2 Center = {0.5f,0.5f};
    float2 Up = { 0.5f,1.0f };
    float2 Vector1 = {0.0f,-1.0f};
    float2 Vector2 = texCoord - Center;
    Vector1 = normalize(Vector1);
    Vector2 = normalize(Vector2);
    float Deg = acos(dot(Vector1, Vector2));
    Deg = abs(Deg);
    //中心からピクセルの座標へのベクトルと中心から上方向へのベクトルの内積を求め
    //逆コサインをとり、設定した角度より小さければ表示、大きければピクセルを破棄する
    if (Vector2.x < Vector1.x) {
        Deg = PI + (PI - Deg);
    }
    if (Deg >= Angle) {
        //ピクセルを破棄する
        clip(-1);
    }
    float4 Color = Texture.Sample(TextureSampler, texCoord);
    return Color;
}