忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

[Windows® API Code Pack for Microsoft® .NET Framework] C#でDirectX11をつかう その4 色つき三角形を表示

 前回表示した三角形は真っ白で色が付いていなかったので
今回は各頂点に色をつけてみます。

今回の変更は前回ほど多くありません。

using Microsoft.WindowsAPICodePack.DirectX.Direct3D;
using Microsoft.WindowsAPICodePack.DirectX.Direct3D11;
using Microsoft.WindowsAPICodePack.DirectX.Graphics;

using System.IO;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        using (Game game = new MyGame())
        {
            game.Run();
        }
    }
}

class Game : System.Windows.Forms.Form
{
    protected DeviceContext DeviceContext;
    protected SwapChain SwapChain;
    protected RenderTargetView RenderTargetView;
    
    public void Run()
    {
        D3DDevice device = initDevice();
        LoadGraphicsContent(device);
        Show();

        while (Created)
        {
            Draw();
            System.Windows.Forms.Application.DoEvents();
        }
    }

    private D3DDevice initDevice()
    {
        D3DDevice device = D3DDevice.CreateDeviceAndSwapChain(this.Handle);
        this.SwapChain = device.SwapChain;
        this.DeviceContext = device.ImmediateContext;

        using (Texture2D texture2D = SwapChain.GetBuffer<Texture2D>(0))
        {
            this.RenderTargetView = device.CreateRenderTargetView(texture2D);
            DeviceContext.OM.RenderTargets = new OutputMergerRenderTargets(new[] { RenderTargetView });
        }

        DeviceContext.RS.Viewports = new[]
        {
            new Viewport
            {
                Width = ClientSize.Width,
                Height = ClientSize.Height,
                MaxDepth = 1
            }
        };
        return device;
    }

    protected virtual void LoadGraphicsContent(D3DDevice device) { }
    protected virtual void Draw() { }

    //ジェネリクスな型Tをネイティブに変換するのは骨が折れます。
    //XNAでは別の方法を使っているようですが…
    protected D3DBuffer CreateVertexBuffer<T>(D3DDevice device, T[] vertices) where T : struct
    {
        int vertexSize = Marshal.SizeOf(typeof(T));
        System.IntPtr verticesPointer = Marshal.AllocCoTaskMem(vertices.Length * vertexSize);

        for (int i = 0; i < vertices.Length; i++)
        {
            Marshal.StructureToPtr(vertices[i], verticesPointer + vertexSize * i, false);
        }

        D3DBuffer result = device.CreateBuffer(
                new BufferDescription
                {
                    ByteWidth = (uint)(vertexSize * vertices.Length),
                    BindingOptions = BindingOptions.VertexBuffer,
                },
                new SubresourceData
                {
                    SystemMemory = verticesPointer
                }
                );

        Marshal.FreeCoTaskMem(verticesPointer);

        return result;
    }
}

struct VertexPositionColor
{
    public Vector3F Position;
    public Vector3F Color;

    public static readonly InputElementDescription[] VertexElements = new[]
    {
         new InputElementDescription
         {
             SemanticName = "SV_Position",
             Format = Format.R32G32B32Float,
         },
         new InputElementDescription
         {
             SemanticName = "COLOR",
             Format = Format.R32G32B32Float,
             AlignedByteOffset = uint.MaxValue //MaxValueにするとオフセットを自動的に決定
         }
    };
}

class MyGame : Game
{
    protected override void Draw()
    {
        this.DeviceContext.ClearRenderTargetView(RenderTargetView, new ColorRgba(0.39f, 0.58f, 0.93f, 1));
        this.DeviceContext.Draw(3, 0);
        this.SwapChain.Present(0, PresentOptions.None);
    }

    protected override void LoadGraphicsContent(D3DDevice device)
    {
        initShadersAndInputLayout(device);
        initTriangleToDraw(device);
    }

    private void initShadersAndInputLayout(D3DDevice device)
    {
        using (Stream vertexShaderBinary = File.Open("MyShader.vs", FileMode.Open))
        {
            this.DeviceContext.VS.Shader = device.CreateVertexShader(vertexShaderBinary);
            vertexShaderBinary.Position = 0;
            this.DeviceContext.IA.InputLayout = createInputLayout(device, vertexShaderBinary);
        }

        using (Stream pixelShaderBinary = System.IO.File.Open("MyShader.ps", FileMode.Open))
        {
            this.DeviceContext.PS.Shader = device.CreatePixelShader(pixelShaderBinary);
        }
    }

    private InputLayout createInputLayout(D3DDevice device, Stream vertexShaderBinary)
    {
        return device.CreateInputLayout(
            VertexPositionColor.VertexElements,
            vertexShaderBinary
            );
    }

    private void initTriangleToDraw(D3DDevice device)
    {
        VertexPositionColor[] vertices = new []
        {
            new VertexPositionColor{ Position = new Vector3F(0, 0.5f, 0), Color = new Vector3F(1, 1, 1) },
            new VertexPositionColor{ Position = new Vector3F(0.5f, 0, 0), Color = new Vector3F(0, 0, 1) },
            new VertexPositionColor{ Position = new Vector3F(-0.5f, 0, 0), Color = new Vector3F(1, 0, 0) },
        };

        D3DBuffer vertexBuffer = CreateVertexBuffer(device, vertices);

        this.DeviceContext.IA.SetVertexBuffers(
            0,
            new D3DBuffer[] { vertexBuffer },
            new uint[] { (uint)Marshal.SizeOf(typeof(VertexPositionColor)) },
            new uint[] { 0 }
            );

        this.DeviceContext.IA.PrimitiveTopology = PrimitiveTopology.TriangleList;
    }
}
前回からの変更点は
頂点データに集中しています。
色のデータを追加したのでそれに関連した変更がいくつか。

まず頂点に位置だけでなく色も持たせるため、新たに頂点を表す構造体を作ります。
そしてその変更をGPU側に教えるためInputElementDescriptionを新たに一つ(色)追加します。
そしてその三角形頂点の初期化部分に色を追加。
そこから頂点バッファを作成する部分もより柔軟にジェネリクスを使ったものに変更です。

ついでに背景色もXNAと同じものに変更します。
今までのままだと表示する三角形と色がかぶって見づらいからです。

シェーダーの方にも色を追加します。

struct VertexPositionColor
{
    float4 Position : SV_Position;
    float4 Color : COLOR;
};

VertexPositionColor MyVertexShader(VertexPositionColor input)
{
    return input;
}

float4 MyPixelShader(VertexPositionColor input) : SV_Target
{
    return input.Color;
}
 
例によってこのファイルはfxc.exeを使ってコンパイルしてください。


実行結果

結果はこうです
directX11TutorialDrawColoredTriangle.jpg

真っ白一色だった三角形に
青と赤の色がつきました。




















拍手[0回]

PR