using System.Windows.Forms;
using SlimDX.DXGI;
using SlimDX.Windows;
using SlimDX.Direct3D11;
using Device = SlimDX.Direct3D11.Device;
using SlimDX;
using SlimDX.D3DCompiler;
using System.Diagnostics;
using System.Threading;
public class Test:Form
{
struct VertexData
{
public Vector3 position;
public Vector3 color;
public static int SizeInBytes => System.Runtime.InteropServices.Marshal.SizeOf(typeof(VertexData));
public static InputElement[] VertexInputElements = new[]
{
new InputElement
{
SemanticName = "SV_Position",
Format = Format.R32G32B32_Float
},
new InputElement
{
SemanticName = "COLOR",
Format = Format.R32G32B32_Float,
// アドレスの自動配置
AlignedByteOffset = InputElement.AppendAligned
}
};
}
Device device;
SwapChain swapChain;
RenderTargetView renderTarget;
InputLayout vertexLayout;
Effect effect;
SlimDX.Direct3D11.Buffer vertexBuffer;
Stopwatch sw = new Stopwatch();
int fps = 30;
long frameCount = 0;
public void Run()
{
Test.CreateDeviceWithSwapChain(this, out device, out swapChain);
// 描画対象の初期化
using (var backBuffer = SlimDX.Direct3D11.Resource.FromSwapChain<Texture2D>(swapChain, 0))
{
renderTarget = new RenderTargetView(device, backBuffer);
device.ImmediateContext.OutputMerger.SetTargets(renderTarget);
}
// シェーダのコンパイル
effect = CompileShader("../../myEffect2.fx");
vertexLayout = new InputLayout(
device,
effect.GetTechniqueByIndex(0)
.GetPassByIndex(0).Description.Signature,
VertexData.VertexInputElements
);
var vertexDatas = new VertexData[]
{
new VertexData
{
position = new Vector3(0f, 0.5f, 0),
color = new Vector3(1,0,0)
},
new VertexData
{
position =new Vector3(0.5f, -0.5f, 0),
color = new Vector3(0,1,0)
},
new VertexData
{
position = new Vector3(-0.5f, -0.5f, 0),
color = new Vector3(1, 1, 1)
}
};
// 頂点バッファの作成
vertexBuffer = CreateVertexBuffer(
device,
vertexDatas
);
// ViewPort設定
device.ImmediateContext.Rasterizer.SetViewports(
new Viewport
{
Width = ClientSize.Width,
Height = ClientSize.Height
}
);
device.ImmediateContext.Rasterizer.State = RasterizerState.FromDescription(device, new RasterizerStateDescription
{
// カリングOFF
CullMode = CullMode.None,
FillMode = FillMode.Solid
});
MessagePump.Run(this, Loop);
vertexBuffer.Dispose();
effect.Dispose();
vertexLayout.Dispose();
}
private Effect CompileShader(string path)
{
using (var shader = ShaderBytecode.CompileFromFile(
path,
"fx_5_0",
ShaderFlags.None,
EffectFlags.None))
{
return new Effect(device, shader);
}
}
void Loop()
{
sw.Restart();
Draw();
// 経過ミリ秒
var elapsedMilliSec = sw.ElapsedMilliseconds;
var sleepTime = 1000 / fps - elapsedMilliSec;
if (sleepTime > 0)
{
Thread.Sleep((int)sleepTime);
}
frameCount++;
}
void Draw()
{
// 背景クリア
device.ImmediateContext.ClearRenderTargetView(
renderTarget,
new Color4(1,0.5f, 0.5f, 0.5f)
);
// ビュー変換行列
var vMatrix = Matrix.LookAtRH(
new Vector3(0, 0, 1.3f),
new Vector3(0, 0, 0),
new Vector3(0, 1f, 0)
);
// プロジェクション変換行列
var pMatrix = Matrix.PerspectiveFovRH(
(float)System.Math.PI / 2,
(float)ClientSize.Width / (float)ClientSize.Height,
// マイナス値ダメ!!
0f,
100f
);
// シェーダへVPMatrixを渡す
var vpMatrix = vMatrix * pMatrix;
effect.GetVariableByName("VPMatrix").AsMatrix().SetMatrix(vpMatrix);
// 1フレームにおける回転するオイラー角
var eulerAnglePerFrame = 75f / (float)fps;
float radian = eulerAnglePerFrame * (float)frameCount * (float)System.Math.PI / 180f;
// Z軸回転行列生成
var axis = new Vector3(0f, 1f, 0f);
Matrix rotateMatrix = Matrix.RotationAxis(axis, radian);
var matrix = effect.GetVariableByName("RotateMatrix");
matrix.AsMatrix().SetMatrix(rotateMatrix);
// 三角形描画初期化
device.ImmediateContext.InputAssembler.InputLayout = vertexLayout;
device.ImmediateContext.InputAssembler.SetVertexBuffers(
0, new VertexBufferBinding(
vertexBuffer, VertexData.SizeInBytes, 0)
);
device.ImmediateContext.InputAssembler.PrimitiveTopology
= PrimitiveTopology.TriangleList;
// 三角形描画
effect.GetTechniqueByIndex(0).GetPassByIndex(0).Apply(device.ImmediateContext);
device.ImmediateContext.Draw(3, 0);
swapChain.Present(0, PresentFlags.None);
}
SlimDX.Direct3D11.Buffer CreateVertexBuffer(
Device device,
System.Array vertices
)
{
using (DataStream vertexStream
= new DataStream(vertices, true, true))
{
return new SlimDX.Direct3D11.Buffer(
device,
vertexStream,
new BufferDescription()
{
// バッファのサイズ
SizeInBytes = (int)vertexStream.Length,
// バッファの種類
BindFlags = BindFlags.VertexBuffer
});
}
}
/// <summary>
/// デバイスとSwapChainを作成
/// </summary>
static public SlimDX.Result CreateDeviceWithSwapChain(
Form form,
out SlimDX.Direct3D11.Device device,
out SwapChain swapChain
)
{
return Device.CreateWithSwapChain(
// Direct3Dの機能を持つデバイス(GPU)を使用する
DriverType.Hardware,
// デバイスに特別なふるまいをさせるときは設定するが、基本はNone
DeviceCreationFlags.None,
// SwapChainの詳細設定
new SwapChainDescription()
{
// 2:ダブルバッファでティアリングを回避
BufferCount = 1,
// 表示するウィンドウ
OutputHandle = form.Handle,
// falseにするとフルスクリーン
IsWindowed = true,
// SwapChainのマルチサンプル方法設定
SampleDescription = new SampleDescription()
{
Count = 1,
Quality = 0
},
// ウィンドウの大きさやリフレッシュレートに関する設定
ModeDescription = new ModeDescription()
{
// ウィンドウの幅
Width = form.ClientSize.Width,
// ウィンドウの高さ
Height = form.ClientSize.Height,
// リフレッシュレート60Hz
RefreshRate = new SlimDX.Rational(60, 1),
// ウィンドウのフォーマット
// https://msdn.microsoft.com/ja-jp/library/ee416140(v=vs.85).aspx
Format = Format.R8G8B8A8_UNorm
},
// 描画対象の使用方法
// ウィンドウにただ表示するだけなので、RenderTargetOutputをセット
Usage = Usage.RenderTargetOutput
},
out device,
out swapChain
);
}
}