I'm toying with DirectX 11 and am trying to render a simple cube, but I can't seem to get anything to show (except the clear color, which is a good sign I suppose...)
Everything seems to be working, every calls into D3D I make succeeds.
When I inspect my vertex buffers/index buffers/etc using VS2012, they show me the right data.
However, when I inspect the Input Assembler stage, when I should be seeing a cube, I see.. nothing. So I guess it's not a shader problem at least...
I joined a .vslog that can be opened with VS2012 and shows the different D3D calls I make and makes it possible to see the content of the different D3D objects. I imagine the problem lies in my vertex buffer/index buffer/input layout because it happens at the input assembler stage, but I just can't see the problem :(
Any idea?
Here's the .vsglog file: http://www.mediafire.com/?q3q77mlnuopj3g0
Here's the project file: http://www.mediafire.com/?sz4rc9qx31lmnw7
Here's the code without any error checking or cleanup:
// RenderTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <fstream>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <DirectXMath.h>
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "dxgi.lib")
using namespace DirectX;
int g_Width = 800;
int g_Height = 600;
HWND g_HWND;
IDXGISwapChain* g_pSwapChain;
ID3D11Device* g_pDevice;
ID3D11DeviceContext* g_pDeviceContext;
ID3D11RenderTargetView* g_pBackBuffer;
ID3D11Buffer* g_pVertexBuffer;
ID3D11Buffer* g_pIndexBuffer;
ID3D11Buffer* g_pConstantBuffer;
ID3D11Texture2D* g_pDepthStencilBuffer;
ID3D11DepthStencilState* g_pDepthStencilState;
ID3D11DepthStencilView* g_pDepthStencilView;
ID3D11InputLayout* g_pInputLayout;
ID3D11VertexShader* g_pVertexShader;
ID3D11PixelShader* g_pPixelShader;
char* g_pVSContent;
size_t g_VSSize;
char* g_pPSContent;
size_t g_PSSize;
#define HR(c) (void) ((!!(SUCCEEDED(c))) || \
(1 != _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #c)) || \
(__debugbreak(), 0))
struct MatrixBuffer
{
XMMATRIX WorldMatrix;
XMMATRIX ViewMatrix;
XMMATRIX ProjectionMatrix;
};
void CreateAWindow(void);
void CreateInputLayout(void);
void CreateIndexBuffer(void);
void CreateVertexBuffer(void);
void CreateConstantBuffer(void);
void CreateVertexShader(void);
void CreatePixelShader(void);
void CreateDepthStencilBuffer(void);
void LoadShadersContent(void);
int _tmain(int argc, _TCHAR* argv[])
{
CreateAWindow();
DXGI_SWAP_CHAIN_DESC scd = {};
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = g_HWND;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
HR(D3D11CreateDeviceAndSwapChain(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_DEBUG,
nullptr,
0,
D3D11_SDK_VERSION,
&scd,
&g_pSwapChain,
&g_pDevice,
nullptr,
&g_pDeviceContext));
ID3D11Texture2D *pBackBufferTexture;
HR(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBufferTexture));
HR(g_pDevice->CreateRenderTargetView(pBackBufferTexture, nullptr, &g_pBackBuffer));
pBackBufferTexture->Release();
CreateDepthStencilBuffer();
D3D11_VIEWPORT viewport = {};
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = (FLOAT)g_Width;
viewport.Height = (FLOAT)g_Height;
g_pDeviceContext->RSSetViewports(1, &viewport);
g_pDeviceContext->OMSetDepthStencilState(g_pDepthStencilState, 1);
g_pDeviceContext->OMSetRenderTargets(1, &g_pBackBuffer, g_pDepthStencilView);
CreatePixelShader();
CreateVertexShader();
CreateVertexBuffer();
CreateIndexBuffer();
CreateConstantBuffer();
CreateInputLayout();
g_pDeviceContext->PSSetShader(g_pPixelShader, nullptr, 0);
g_pDeviceContext->VSSetShader(g_pVertexShader, nullptr, 0);
g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
unsigned int zero = 0;
unsigned int stride = 12;
g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &zero);
g_pDeviceContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
g_pDeviceContext->IASetInputLayout(g_pInputLayout);
g_pDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D11RasterizerState * g_pRasterState;
D3D11_RASTERIZER_DESC rasterizerState;
rasterizerState.FillMode = D3D11_FILL_SOLID;
rasterizerState.CullMode = D3D11_CULL_NONE;
rasterizerState.FrontCounterClockwise = true;
rasterizerState.DepthBias = false;
rasterizerState.DepthBiasClamp = 0;
rasterizerState.SlopeScaledDepthBias = 0;
rasterizerState.DepthClipEnable = false;
rasterizerState.ScissorEnable = false;
rasterizerState.MultisampleEnable = false;
rasterizerState.AntialiasedLineEnable = false;
HR(g_pDevice->CreateRasterizerState( &rasterizerState, &g_pRasterState));
g_pDeviceContext->RSSetState(g_pRasterState);
MSG msg = {};
while (msg.message != WM_QUIT)
{
// wait for the next message in the queue, store the result in 'msg'
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)> 0)
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
g_pDeviceContext->ClearRenderTargetView(g_pBackBuffer, clearColor);
g_pDeviceContext->DrawIndexed(36, 0, 0);
g_pSwapChain->Present(0, 0);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
void CreateAWindow(void)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = _T("TestClass");
RegisterClassEx(&wc);
auto style = WS_OVERLAPPEDWINDOW;
RECT windowRect = {0};
windowRect.right = g_Width;
windowRect.bottom = g_Height;
AdjustWindowRect(&windowRect, style, FALSE);
auto x = (GetSystemMetrics(SM_CXSCREEN) - g_Width) / 2;
auto y = (GetSystemMetrics(SM_CYSCREEN) - g_Height) / 2;
g_HWND = CreateWindowEx(0,
_T("TestClass"), // name of the window class
_T("Test"), // title of the window
style, // window style
x, // TODO: x-position of the window
y, // TODO: y-position of the window
windowRect.right - windowRect.left, // g_Width of the window
windowRect.bottom - windowRect.top, // g_Height of the window
nullptr, // we have no parent window, NULL
nullptr, // we aren't using menus, NULL
GetModuleHandle(nullptr), // application handle
nullptr);
ShowWindow(g_HWND, SW_SHOWDEFAULT);
}
void LoadShadersContent(void)
{
if (g_pVSContent)
return;
std::ifstream isVS("SimpleVertexShader.cso", std::ios::binary);
isVS.seekg(0, std::ios_base::end);
g_VSSize = (size_t)isVS.tellg();
g_pVSContent = new char[g_VSSize];
isVS.seekg(0, std::ios_base::beg);
isVS.read(g_pVSContent, g_VSSize);
isVS.close();
std::ifstream isPS("SimplePixelShader.cso", std::ios::binary);
isPS.seekg(0, std::ios_base::end);
g_PSSize = (size_t)isPS.tellg();
g_pPSContent = new char[g_PSSize];
isPS.seekg(0, std::ios_base::beg);
isPS.read(g_pPSContent, g_PSSize);
isPS.close();
}
void CreatePixelShader(void)
{
LoadShadersContent();
HR(g_pDevice->CreatePixelShader(g_pPSContent, g_PSSize, nullptr, &g_pPixelShader));
}
void CreateVertexShader(void)
{
LoadShadersContent();
HR(g_pDevice->CreateVertexShader(g_pVSContent, g_VSSize, nullptr, &g_pVertexShader));
}
void CreateConstantBuffer(void)
{
MatrixBuffer constants = {};
constants.ProjectionMatrix = XMMatrixPerspectiveFovLH(XM_PIDIV4, (float)g_Width / g_Height, 1.0f, 1000.0f);
constants.ViewMatrix = XMMatrixTranslation(0.0f, 0.0f, -1.0f);
constants.WorldMatrix = XMMatrixIdentity();
D3D11_BUFFER_DESC desc = {};
desc.ByteWidth = sizeof(MatrixBuffer);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = &constants;
HR(g_pDevice->CreateBuffer(&desc, &data, &g_pConstantBuffer));
}
void CreateVertexBuffer(void)
{
XMFLOAT3 vertices[8];
//Top
vertices[0] = XMFLOAT3(-0.5f, 1.0f, -0.5f);
vertices[1] = XMFLOAT3(-0.5f, 1.0f, 0.5f);
vertices[2] = XMFLOAT3(0.5f, 1.0f, 0.5f);
vertices[3] = XMFLOAT3(0.5f, 1.0f, -0.5f);
//Bottom
vertices[4] = XMFLOAT3(-0.5f, 0.0f, -0.5f);
vertices[5] = XMFLOAT3(-0.5f, 0.0f, 0.5f);
vertices[6] = XMFLOAT3(0.5f, 0.0f, 0.5f);
vertices[7] = XMFLOAT3(0.5f, 0.0f, -0.5f);
// Vertex buffer
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(vertices);
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data, sizeof(D3D11_SUBRESOURCE_DATA));
data.pSysMem = &vertices;
HR(g_pDevice->CreateBuffer(&desc, &data, &g_pVertexBuffer));
}
void CreateIndexBuffer(void)
{
int indices[36];
// Top
indices[0] = 0; indices[1] = 1; indices[2] = 2;
indices[3] = 0; indices[4] = 2; indices[5] = 3;
// Bottom
indices[6] = 4; indices[7] = 5; indices[8] = 6;
indices[9] = 4; indices[10] = 6; indices[11] = 7;
// Left
indices[12] = 4; indices[13] = 5; indices[14] = 1;
indices[15] = 4; indices[16] = 1; indices[17] = 0;
// Right
indices[18] = 6; indices[19] = 7; indices[20] = 3;
indices[21] = 6; indices[22] = 3; indices[23] = 2;
// Front
indices[24] = 4; indices[25] = 0; indices[26] = 3;
indices[27] = 4; indices[28] = 3; indices[29] = 7;
// Back
indices[30] = 6; indices[31] = 2; indices[32] = 1;
indices[33] = 6; indices[34] = 1; indices[35] = 5;
D3D11_BUFFER_DESC desc = {};
desc.ByteWidth = sizeof(indices);
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data, sizeof(D3D11_SUBRESOURCE_DATA));
data.pSysMem = &indices;
HR(g_pDevice->CreateBuffer(&desc, &data, &g_pIndexBuffer));
}
void CreateInputLayout(void)
{
LoadShadersContent();
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "SV_POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
HR(g_pDevice->CreateInputLayout(ied, 1, g_pVSContent, g_VSSize, &g_pInputLayout));
}
void CreateDepthStencilBuffer(void)
{
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = g_Width;
descDepth.Height = g_Height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
HR(g_pDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencilBuffer));
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create depth stencil state
g_pDevice->CreateDepthStencilState(&dsDesc, &g_pDepthStencilState);
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
descDSV.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
HRESULT hr;
HR(hr = g_pDevice->CreateDepthStencilView(g_pDepthStencilBuffer, // Depth stencil texture
&descDSV, // Depth stencil desc
&g_pDepthStencilView));
}
The Vertex Shader:
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
};
struct VS_INPUT
{
float4 position : SV_POSITION;
};
struct PS_INPUT
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
PS_INPUT main(VS_INPUT input)
{
PS_INPUT output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the input color for the pixel shader to use.
output.color = float4(0.2f, 0.2f, 0.2f, 1.0f);
return output;
}
And finally, the pixel shader:
struct PS_INPUT
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
float4 main(PS_INPUT input) : SV_TARGET
{
return input.color;
}
POSITION
semantic - which is technically a D3D9 semantic. You can still use it in D3D10+, but I've seen it mess things up a few times before. Try usingSV_POSITION
instead (both in the input layout and vertex shader input declaration) and see if that helps. \$\endgroup\$XMMatrixPerspectiveFovXH
's first parameter is the vertical FOV in radians , not degrees, so try something like Pi/4 there (DirectX::XM_PIDIV4
) and see if that helps. \$\endgroup\$