Here is the code of Program.cs.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using SlimDX;
using SlimDX.D3DCompiler;
using SlimDX.Direct3D11;
using Buffer = SlimDX.Direct3D11.Buffer; // I added this line to fix ambiguity between SlimDX.Direct3D11.Buffer and System.Buffer. This tells it to use the SlimDX Buffer class rather than the one in the System namespace when I reference the type Buffer.
using SlimDX.DXGI;
using SlimDX.Windows;
using Device = SlimDX.Direct3D11.Device;
using Resource = SlimDX.Direct3D11.Resource;
//--------------------------------------------------------------------------------------
// NOTE:
//--------------------------------------------------------------------------------------
// I modified this program and its shaders.fx file to help with debugging a bug that
// I was having a hell of a time solving. See the note at the top of the shaders.fx
// file for info on changes I made to that file.
//--------------------------------------------------------------------------------------
namespace Test_1
{
struct SimpleVertex
{
Vector3 Position;
Vector3 Normal;
Vector4 Color;
public SimpleVertex(Vector3 position, Vector3 normal, Vector4 color)
{
Position = position;
Normal = normal;
Color = color;
}
};
struct ConstantBuffer
{
public Matrix mWorld;
public Matrix mView;
public Matrix mProjection;
public Vector4[] vLightDir;
public Vector4[] vLightColor;
public Vector4 vOutputColor;
public ConstantBuffer(Matrix world, Matrix view, Matrix projection)
{
mWorld = world;
mView = view;
mProjection = projection;
vLightDir = new Vector4[2];
vLightColor = new Vector4[2];
vOutputColor = new Vector4();
}
};
static class Program
{
static float rotationY = 0.785f; // Y Rotation in radians per second (0.785 radians = 45 degrees)
static int startTime;
static int curTime;
static RenderForm form;
static Buffer constantBuffer;
static Buffer indexBuffer;
static Buffer vertexBuffer;
static DataStream constants;
static DataStream indices;
static DataStream vertices;
static DepthStencilView depthStencilView;
static Device device;
static DeviceContext context;
static InputLayout layout;
static PixelShader pixelShader;
static PixelShader pixelShaderSolid;
static PixelShader pixelShaderColor;
static RenderTargetView renderTarget;
static ShaderSignature inputSignature;
static SwapChain swapChain;
static Texture2D depthStencil;
static VertexShader vertexShader;
static Viewport viewport;
static Matrix matrix_World;
static Matrix matrix_View;
static Matrix matrix_Projection;
static void Main()
{
form = new RenderForm("OMG a Window!!");
var description = new SwapChainDescription()
{
BufferCount = 2,
Usage = Usage.RenderTargetOutput,
OutputHandle = form.Handle,
IsWindowed = true,
ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm),
SampleDescription = new SampleDescription(1, 0),
Flags = SwapChainFlags.AllowModeSwitch,
SwapEffect = SwapEffect.Discard
};
Device.CreateWithSwapChain(DriverType.Hardware,
DeviceCreationFlags.Debug,
description,
out device,
out swapChain);
// create a view of our render target, which is the backbuffer of the swap chain we just created
using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0))
{
renderTarget = new RenderTargetView(device, resource);
};
// Create the depth stencil texture
Texture2DDescription depthStencilDesc = new Texture2DDescription();
depthStencilDesc.Width = form.ClientSize.Width;
depthStencilDesc.Height = form.ClientSize.Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = Format.D24_UNorm_S8_UInt;
depthStencilDesc.SampleDescription = new SampleDescription(1, 0);
depthStencilDesc.Usage = ResourceUsage.Default;
depthStencilDesc.BindFlags = BindFlags.DepthStencil;
depthStencilDesc.CpuAccessFlags = CpuAccessFlags.None;
depthStencilDesc.OptionFlags = ResourceOptionFlags.None;
depthStencil = new Texture2D(device, depthStencilDesc);
// Create the Depth Stencil View
DepthStencilViewDescription depthStencilViewDesc = new DepthStencilViewDescription();
depthStencilViewDesc.Format = depthStencilDesc.Format;
depthStencilViewDesc.Dimension = DepthStencilViewDimension.Texture2D;
depthStencilViewDesc.MipSlice = 0;
depthStencilView = new DepthStencilView(device, depthStencil, depthStencilViewDesc);
// setting a viewport is required if you want to actually see anything
context = device.ImmediateContext;
viewport = new Viewport(0.0f,
0.0f,
form.ClientSize.Width,
form.ClientSize.Height,
0.0f,
1.0f);
context.OutputMerger.SetTargets(depthStencilView, renderTarget);
context.Rasterizer.SetViewports(viewport);
// Setup our shaders
InitShaders();
// Setup our vertex data
InitVertexData();
// Setup our matrices
InitMatrices();
// Set the shaders
context.VertexShader.Set(vertexShader);
context.PixelShader.Set(pixelShader);
// Prevent DXGI handling of Alt+Enter, which doesn't work properly with Winforms
using (var factory = swapChain.GetParent<Factory>())
{
factory.SetWindowAssociation(form.Handle,
WindowAssociationFlags.IgnoreAltEnter);
};
// Handle Alt+Enter ourselves
form.KeyDown += (o, e) =>
{
if (e.Alt && e.KeyCode == Keys.Enter)
{
swapChain.IsFullScreen = !swapChain.IsFullScreen;
}
};
// Handle form size changes
form.UserResized += (o, e) =>
{
renderTarget.Dispose();
depthStencil.Dispose();
depthStencilView.Dispose();
swapChain.ResizeBuffers(2,
0,
0,
Format.R8G8B8A8_UNorm,
SwapChainFlags.AllowModeSwitch);
using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0))
{
renderTarget = new RenderTargetView(device, resource);
}
depthStencilDesc.Width = form.ClientSize.Width;
depthStencilDesc.Height = form.ClientSize.Height;
depthStencil = new Texture2D(device, depthStencilDesc);
depthStencilView = new DepthStencilView(device, depthStencil, depthStencilViewDesc);
context.OutputMerger.SetTargets(depthStencilView, renderTarget);
context.Rasterizer.SetViewports(new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height, 0.0f, 1.0f));
};
startTime = Environment.TickCount;
MessagePump.Run(form, RenderFrame);
// Clean up all resources
// anything we missed will show up in the IDE's debug output
vertices.Close();
vertexBuffer.Dispose();
layout.Dispose();
inputSignature.Dispose();
vertexShader.Dispose();
pixelShader.Dispose();
renderTarget.Dispose();
swapChain.Dispose();
device.Dispose();
indexBuffer.Dispose();
indices.Dispose();
constantBuffer.Dispose();
constants.Dispose();
depthStencil.Dispose();
depthStencilView.Dispose();
pixelShaderSolid.Dispose();
pixelShaderColor.Dispose();
}
static void InitShaders()
{
// load and compile the vertex shader
string vsCompileError = "Vertex Shader Compile Error!!!";
using (var bytecode = ShaderBytecode.CompileFromFile("shaders.fx", "VS", "vs_4_0", ShaderFlags.EnableStrictness | ShaderFlags.Debug, EffectFlags.None, null, null, out vsCompileError))
{
inputSignature = ShaderSignature.GetInputSignature(bytecode);
vertexShader = new VertexShader(device, bytecode);
}
// load and compile the pixel shader
string psCompileError = "Pixel Shader Compile Error!!!";
using (var bytecode = ShaderBytecode.CompileFromFile("shaders.fx", "PS", "ps_4_0", ShaderFlags.EnableStrictness | ShaderFlags.Debug, EffectFlags.None, null, null, out psCompileError))
{
pixelShader = new PixelShader(device, bytecode);
}
// load and compile the solid pixel shader
psCompileError = "Solid Pixel Shader Compile Error!!!";
using (var bytecode = ShaderBytecode.CompileFromFile("shaders.fx", "PSSolid", "ps_4_0", ShaderFlags.EnableStrictness | ShaderFlags.Debug, EffectFlags.None, null, null, out psCompileError))
{
pixelShaderSolid = new PixelShader(device, bytecode);
}
// load and compile the color pixel shader
psCompileError = "Color Pixel Shader Compile Error!!!";
using (var bytecode = ShaderBytecode.CompileFromFile("shaders.fx", "PSColor", "ps_4_0", ShaderFlags.EnableStrictness | ShaderFlags.Debug, EffectFlags.None, null, null, out psCompileError))
{
pixelShaderColor = new PixelShader(device, bytecode);
}
}
static void InitMatrices()
{
// world matrix
matrix_World = Matrix.Identity;
// view matrix
Vector3 vEye = new Vector3(0.0f, 4.0f, -10.0f);
Vector3 vLookAt = new Vector3(0.0f, 1.0f, 0.0f);
Vector3 vUp = new Vector3(0.0f, 1.0f, 0.0f);
matrix_View = Matrix.LookAtLH(vEye,
vLookAt,
vUp);
// projection matrix
matrix_Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, // Vertical Field of View
(float)form.ClientSize.Width / (float)form.ClientSize.Height, // Aspect Ratio
0.01f, // Near Z
100.0f); // Far Z
// Write the matrices we just generated into the DataStream
ConstantBuffer cb = new ConstantBuffer(Matrix.Transpose(matrix_World),
Matrix.Transpose(matrix_View),
Matrix.Transpose(matrix_Projection));
constants = new DataStream(Marshal.SizeOf(cb), true, true);
constants.Write<ConstantBuffer>(cb);
constants.Position = 0;
// Create the constant buffer
constantBuffer = new Buffer(device,
constants,
(int)constants.Length,
ResourceUsage.Default,
BindFlags.ConstantBuffer,
CpuAccessFlags.None,
ResourceOptionFlags.None,
0);
context.UpdateSubresource(new DataBox(0, 0, constants),
constantBuffer,
0);
context.VertexShader.SetConstantBuffer(constantBuffer, 0);
}
static void InitVertexData()
{
// Create test vertex data, making sure to rewind the stream afterward.
vertices = new DataStream(Marshal.SizeOf(new SimpleVertex(Vector3.Zero, Vector3.Zero, Vector4.Zero)) * 24, true, true);
SimpleVertex[] tempVertexArray =
{
new SimpleVertex(new Vector3(-1.0f, 1.0f, -1.0f), new Vector3( 0.0f, 1.0f, 0.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, -1.0f), new Vector3( 0.0f, 1.0f, 0.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, 1.0f), new Vector3( 0.0f, 1.0f, 0.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, 1.0f, 1.0f), new Vector3( 0.0f, 1.0f, 0.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, 1.0f), new Vector3( 0.0f, -1.0f, 0.0f), new Vector4(1.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, 1.0f), new Vector3( 0.0f, -1.0f, 0.0f), new Vector4(0.0f, 0.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector4(0.0f, 0.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, -1.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, 1.0f, -1.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, 1.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, 1.0f), new Vector3( 1.0f, 0.0f, 0.0f), new Vector4(1.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, -1.0f), new Vector3( 1.0f, 0.0f, 0.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, -1.0f), new Vector3( 1.0f, 0.0f, 0.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, 1.0f), new Vector3( 1.0f, 0.0f, 0.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, -1.0f), new Vector3( 0.0f, 0.0f, -1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, -1.0f), new Vector3( 0.0f, 0.0f, -1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, -1.0f), new Vector3( 0.0f, 0.0f, -1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, 1.0f, -1.0f), new Vector3( 0.0f, 0.0f, -1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, -1.0f, 1.0f), new Vector3( 0.0f, 0.0f, 1.0f), new Vector4(0.0f, 0.0f, 0.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, -1.0f, 1.0f), new Vector3( 0.0f, 0.0f, 1.0f), new Vector4(1.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3( 1.0f, 1.0f, 1.0f), new Vector3( 0.0f, 0.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f)),
new SimpleVertex(new Vector3(-1.0f, 1.0f, 1.0f), new Vector3( 0.0f, 0.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f)),
};
foreach (SimpleVertex vertex in tempVertexArray)
{
vertices.Write(vertex);
}
vertices.Position = 0;
// create the vertex layout and vertex buffer
var elements = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, SlimDX.Direct3D11.InputClassification.PerVertexData, 0),
new InputElement("NORMAL", 0, Format.R32G32B32_Float, 12, 0, SlimDX.Direct3D11.InputClassification.PerVertexData, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 24, 0, SlimDX.Direct3D11.InputClassification.PerVertexData, 0)};
layout = new InputLayout(device,
inputSignature,
elements);
vertexBuffer = new Buffer(device,
vertices,
(int)vertices.Length,
ResourceUsage.Default,
BindFlags.VertexBuffer,
CpuAccessFlags.None,
ResourceOptionFlags.None,
0);
// Setup the test index data, making sure to rewind the stream afterward.
UInt16[] indicesList = { 3, 1, 0,
2, 1, 3,
6, 4, 5,
7, 4, 6,
11, 9, 8,
10, 9, 11,
14, 12, 13,
15, 12, 14,
19, 17, 16,
18, 17, 19,
22, 20, 21,
23, 20, 22
};
// As you can see in the indices list above, we have 36 values total, each of which
// is a UInt16 value (or 2-byte short integer)
indices = new DataStream(36 * 2, true, true);
foreach (UInt16 index in indicesList)
{
indices.Write(index);
}
indices.Position = 0;
// Now create the index buffer.
indexBuffer = new Buffer(device,
indices,
(int)indices.Length,
ResourceUsage.Default,
BindFlags.IndexBuffer,
CpuAccessFlags.None,
ResourceOptionFlags.None,
0);
// Configure the Input Assembler portion of the graphics pipeline with the vertex data.
context.InputAssembler.InputLayout = layout;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
context.InputAssembler.SetVertexBuffers(0,
new VertexBufferBinding(vertexBuffer, 40, 0));
context.InputAssembler.SetIndexBuffer(indexBuffer,
Format.R16_UInt,
0);
}
static void RenderFrame()
{
curTime = Environment.TickCount;
float t = (curTime - startTime) / 1000.0f; // Calculate elapsed time since start in seconds
// 1st Cube: Rotate around the origin.
matrix_World = Matrix.RotationY(t * rotationY);
// Setup our lighting parameters
Vector4[] vLightDirs =
{
new Vector4(-0.577f, 0.577f, -0.577f, 1.0f),
new Vector4(0.0f, 0.0f, -1.0f, 1.0f)
};
Vector4[] vLightColors =
{
new Vector4(0.5f, 0.5f, 0.5f, 1.0f),
new Vector4(0.5f, 0.0f, 0.0f, 1.0f)
};
// Rotate the second light around the origin
Matrix mRotate = Matrix.RotationY(-2.0f * t);
Vector4 vLightDir = vLightDirs[1];
vLightDir = Vector4.Transform(vLightDir, mRotate);
vLightDirs[1] = vLightDir;
// Clear the render target to a soothing blue
context.ClearRenderTargetView(renderTarget,
new Color4(0.0f, 0.125f, 0.3f, 1.0f));
// Clear the Depth buffer to 1.0 (max depth)
context.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);
// Update the constant buffer variables
ConstantBuffer cb = new ConstantBuffer(Matrix.Transpose(matrix_World),
Matrix.Transpose(matrix_View),
Matrix.Transpose(matrix_Projection));
cb.vLightDir[0] = vLightDirs[0];
cb.vLightDir[1] = vLightDirs[1];
cb.vLightColor[0] = vLightColors[0];
cb.vLightColor[1] = vLightColors[1];
cb.vOutputColor = new Vector4(0, 0, 0, 0);
constants.Position = 0;
constants.Write<ConstantBuffer>(cb);
constants.Position = 0;
// Give GPU updated matrices data.
context.UpdateSubresource(new DataBox(0, 0, constants),
constantBuffer,
0);
// Render the cube
context.VertexShader.Set(vertexShader);
context.VertexShader.SetConstantBuffer(constantBuffer, 0);
context.PixelShader.Set(pixelShaderColor);
context.PixelShader.SetConstantBuffer(constantBuffer, 0);
context.DrawIndexed(36,
0,
0);
/*
// Render each light
for (int m = 0; m < 2; m++)
{
Matrix mLight = Matrix.Translation(5.0f * new Vector3(vLightDirs[m].X, vLightDirs[m].Y, vLightDirs[m].Z));
Matrix mLightScale = Matrix.Scaling(0.2f, 0.2f, 0.2f);
mLight = mLightScale * mLight;
// Update the world variable to reflect the current light
cb.mWorld = Matrix.Transpose(mLight);
cb.vOutputColor = vLightColors[m];
constants.Position = 0;
constants.Write<ConstantBuffer>(cb);
constants.Position = 0;
context.UpdateSubresource(new DataBox(0, 0, constants),
constantBuffer,
0);
context.PixelShader.Set(pixelShaderSolid);
context.DrawIndexed(36,
0,
0);
}
*/
// Present the frame we just rendered.
swapChain.Present(0,
PresentFlags.None);
}
}
}
And here is the code of the shaders.fx file which contains the shaders:
//--------------------------------------------------------------------------------------
// File: Tutorial06.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// NOTE:
//--------------------------------------------------------------------------------------
// I modified this file by adding color to the VS_INPUT and PS_INPUT structs.
// I also added the Pixel Shader from the DirectX11 SDK tutorial 5 program and named
// it as PSColor. I also added one line in the Vertex Shader to return the vertex
// color in the output so the pixel shader has access to the color.
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
float4 vLightDir[2];
float4 vLightColor[2];
float4 vOutputColor;
}
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float3 Norm : NORMAL;
float4 Color: COLOR;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float3 Norm : TEXCOORD0;
float4 Color: COLOR;
};
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, World );
// I added this line.
output.Color = input.Color;
return output;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
float4 finalColor = 0;
//do NdotL lighting for 2 lights
for(int i=0; i<2; i++)
{
finalColor += saturate( dot( (float3)vLightDir,input.Norm) * vLightColor );
}
finalColor.a = 1;
return finalColor;
}
//--------------------------------------------------------------------------------------
// PSSolid - render a solid color
//--------------------------------------------------------------------------------------
float4 PSSolid( PS_INPUT input) : SV_Target
{
return vOutputColor;
}
//--------------------------------------------------------------------------------------
// PSColor - render using vertex colors
//--------------------------------------------------------------------------------------
float4 PSColor( PS_INPUT input) : SV_Target
{
return input.Color;
}
As you can see, I added the Pixel Shader from tutorial 5 (renamed to PSColor) to the bottom of the shaders.fx file and added a color attribute to the shader input data. I then changed the render code to use this shader instead of the PSSolid pixel shader. And lastly I added the color data from tutorial 5 into the vertex list of this program. I can see where one face ends and the next begins now, but what I'm seeing I can't make any sense out of. The code to render the lights is commented out to see what difference that made. I need to get it to draw a cube for now like it is supposed to. Then I'll go back and uncomment that code to enable the lights again.
Any help would be greatly appreciated. I'm totally stumped here. Thanks