Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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;
}
share|improve this question
    
You may find you get a more useful response if you post some code! –  Goz Mar 5 '13 at 12:15
    
In your input layout, you use the 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 using SV_POSITION instead (both in the input layout and vertex shader input declaration) and see if that helps. –  melak47 Mar 5 '13 at 14:02
    
@Goz I thought about it, but there's so many code spread across so many classes that I doubt it would be more useful than the .vsglog file :/ –  Kevin Mar 5 '13 at 16:45
    
@melak47: no go, but thanks for the info! –  Kevin Mar 5 '13 at 16:54
1  
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. –  melak47 Mar 6 '13 at 5:23
show 10 more comments

2 Answers

up vote 3 down vote accepted
+100

From a quick flick through the major problem I see is in your SetVertexBuffers call:

g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &zero, &zero);

Basically you are setting the vertex buffer stride to 0. Your stride is actually 12 bytes.

UINT stride = 12;
g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &zero);

This is something the debug runtime ought to report to you if you create your device and swap chain with the correct flag:

HR(D3D11CreateDeviceAndSwapChain(NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        D3D11_CREATE_DEVICE_DEBUG,
        NULL,
        0,
        D3D11_SDK_VERSION,
        &scd,
        &g_pSwapChain,
        &g_pDevice,
        NULL,
        &g_pDeviceContext));

Use it to save yourself loads of time tracking down bugs.

Its all worth bearing in mind that rendering a cube without a depth buffer will cause polygons to overlap each other in weird ways. You should definitely create and bind a DepthStencilView ...

Edit: Looking again its possible your view matrix is actually looking away from the object (I can't be 100% on that as I haven't gone through all the maths).

Try using XMMatrixLookAtLH instead.

constants.ViewMatrix = XMMatrixLookAtLH( XMVector( 0, 0, -50.0f ), XMVector( 0.0f, 0.0f, 0.0f ), XMVector( 0.0f, 1.0f, 0.0f ) );
share|improve this answer
    
I tried with the debug flag, but it doesn't warn me about the stride. Fixing the stride does show me the cube in the debug view, but not on screen. It's like the pixel shader doesn't run :( i.imgur.com/g0ZTyiD.png –  Kevin Mar 6 '13 at 17:02
    
@Kevin: Edited my answer. –  Goz Mar 6 '13 at 19:59
    
I'm not home so I can't try, but I don't think it is the problem - in the image, you can see the cube after the vertex shader ran and it's there, a bit far away, in the middle of the screen :( –  Kevin Mar 6 '13 at 22:59
    
@kevin: Move the camera closer to the cube? –  Goz Mar 6 '13 at 23:33
    
I don't think it's too far, you can see it in the vertex shader so it should be visible on screen –  Kevin Mar 7 '13 at 1:54
show 13 more comments

You're not clearing your depth buffer, so every pixel gets rejected when you try to draw your cube.

In your message loop, clear the depth stencil view as such:

g_pDeviceContext->ClearRenderTargetView(g_pBackBuffer, clearColor);
g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0xFF);

The 1.0f indicates that you're clearing the depth buffer with the maximum value. Since you have your depth comparison test set to D3D11_COMPARISON_LESS, the cube's fragments will pass through unharmed.

Unfortunately you have a new problem - you'll see a gray stripe across the top of your screen instead of your cube from the proper perspective. I'm guessing your constant buffer isn't being properly referenced by your shader. Replacing the "bottom" vertices' Y coordinates with -1.0 extends the gray stripe to the bottom of the screen, which means your vertex values are passing through your vertex shader totally unmodified (clip space extends from -1.0 to 1.0 on the X and Y axes). I'd take a look at the shader but you only supplied compiled binaries. Hopefully this gives you a place to start.

On a related note, I don't think you're setting up your view matrix correctly. Unless you're taking a math shortcut, I think you're misunderstanding what the view matrix is (the inverse of your camera's transformation matrix). Replace this:

constants.ViewMatrix = XMMatrixTranslation(0.0f, 0.0f, -1.0f);

with something like this:

DirectX::FXMVECTOR eyePos = { 0.0f, 0.0f, -1.0f };
DirectX::FXMVECTOR focusPos = { 0.0f, 0.0f, 0.0f };
DirectX::FXMVECTOR up = { 0.0f, 1.0f, 0.0f };
constants.ViewMatrix = XMMatrixLookAtLH( eyePos, focusPos, up );

But since your shader isn't using the constant buffer, no changes I'm making to any of the constant buffer's values are having any effect. Intel GPA shows that your constant buffer is making it onto the GPU, so I think your shader just isn't using the data.

share|improve this answer
    
Why are you saying I'm not using the constant buffer? ie: output.position = mul(output.position, viewMatrix) uses the viewMatrix from the constant buffer –  Kevin Mar 9 '13 at 5:10
    
It was just a guess since none of the matrices looked like they were getting applied; sounds like you figured out that the data needed to be transposed, which makes sense too. –  Daniel Rowe Mar 9 '13 at 5:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.