0
\$\begingroup\$

Been following some tutorials online for DirectX 11. I was able to successfully get a triangle to render in screen space. But the moment I add a MVP matrix, my triangle disappears!

Looking at it in the graphical debugger that ships with VS2015, I can see my render pipeline is just skipping my pixel shader entirely, but I have no idea why!

my code: #include "stdafx.h"

#include "graphics.h"

#include "types.h"

#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>
//#include <DirectXPackedVector.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")

namespace graphics {

    IDXGISwapChain *swap_chain;
    ID3D11Device *device;
    ID3D11DeviceContext *context;
    ID3D11RenderTargetView *back_buffer;

    ID3D11Texture2D *depth_stencil_buffer;
    ID3D11DepthStencilState *depth_stencil_state;
    ID3D11DepthStencilView *depth_stencil_view;

    ID3D11VertexShader *sh_vertex;
    ID3D11PixelShader *sh_pixel;
    ID3D11Buffer *vertex_buffer;
    ID3D11Buffer *index_buffer;
    ID3D11Buffer *shader_constants;
    camera main_camera;

    ID3D11InputLayout *layout;

    struct vertex {
        float x;
        float y;
        float z;
        D3DCOLORVALUE color;
    };


    HRESULT compile_shader(LPCWSTR file, LPCSTR entry_point, LPCSTR features, ID3DBlob** program);
    void init_pipeline();
    void init_graphics();
    void build_shader_constants();
    void build_depth_stencil(unsigned int width, unsigned int height);

    void init(HWND hWnd, int width, int height) {
        DXGI_SWAP_CHAIN_DESC description;
        ZeroMemory(&description, sizeof(DXGI_SWAP_CHAIN_DESC));

        description.BufferCount = 1;
        description.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
        description.BufferDesc.Width = width;
        description.BufferDesc.Height = height;
        description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        description.OutputWindow = hWnd;
        description.SampleDesc.Count = 4;
        description.Windowed = TRUE;
        description.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

        D3D11CreateDeviceAndSwapChain(NULL,
            D3D_DRIVER_TYPE_HARDWARE,
            NULL,
            D3D11_CREATE_DEVICE_DEBUG,
            NULL,
            NULL,
            D3D11_SDK_VERSION,
            &description,
            &swap_chain,
            &device,
            NULL,
            &context);

        ID3D11Texture2D *buffer_texture;
        swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&buffer_texture);
        device->CreateRenderTargetView(buffer_texture, NULL, &back_buffer);
        buffer_texture->Release();

        context->OMSetRenderTargets(1, &back_buffer, NULL);

        D3D11_VIEWPORT viewport;
        ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

        viewport.TopLeftX = 0;
        viewport.TopLeftY = 0;
        viewport.Width = (float)width;
        viewport.Height = (float)height;
        viewport.MinDepth = 0;
        viewport.MaxDepth = 1.0;

        context->RSSetViewports(1, &viewport);

        init_pipeline();
        init_graphics();
        build_depth_stencil(width, height);

        main_camera.position = DirectX::XMFLOAT3(-1000.0f, -1000.0f, -1000.0f);
        main_camera.look_at = DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f);
        main_camera.aspect_ratio = (float)width / (float)height;
        main_camera.fov = DirectX::XM_PIDIV4;
        main_camera.near_clip = 1.f;
        main_camera.far_clip = 10000.0f;
    }

    void render() {
        float color[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
        context->ClearRenderTargetView(back_buffer, color);
        context->ClearDepthStencilView(depth_stencil_view, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0xFF);

        unsigned int stride = sizeof(vertex);
        unsigned int offset = 0;

        build_shader_constants();

        context->VSSetConstantBuffers(0, 1, &shader_constants);
        context->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset);
        context->IASetIndexBuffer(index_buffer, DXGI_FORMAT_R32_UINT, 0);
        context->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        context->Draw(3, 0);

        swap_chain->Present(0, 0);
    }

    struct vs_constants {
        DirectX::XMFLOAT4X4 model;
        DirectX::XMFLOAT4X4 view;
        DirectX::XMFLOAT4X4 projection;
    };

    DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f);

    DirectX::XMMATRIX create_view_matrix(const DirectX::XMFLOAT3 &position, const DirectX::XMFLOAT3 &look) {
        DirectX::XMVECTOR eye_position = DirectX::XMLoadFloat3(&position);
        DirectX::XMVECTOR look_at = DirectX::XMLoadFloat3(&look);

        return DirectX::XMMatrixLookAtLH(eye_position, look_at, up);
    }
    void build_shader_constants() {

        D3D11_BUFFER_DESC buffer_desc;
        buffer_desc.ByteWidth = sizeof(vs_constants);
        buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
        buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
        buffer_desc.MiscFlags = 0;
        buffer_desc.StructureByteStride = 0;

        vs_constants constants;
        DirectX::XMStoreFloat4x4(&constants.model, DirectX::XMMatrixIdentity());
        DirectX::XMStoreFloat4x4(&constants.view, DirectX::XMMatrixTranspose(create_view_matrix(main_camera.position, main_camera.look_at)));
        DirectX::XMStoreFloat4x4(&constants.projection, DirectX::XMMatrixTranspose(DirectX::XMMatrixPerspectiveFovLH(main_camera.fov, main_camera.aspect_ratio, main_camera.near_clip, main_camera.far_clip)));

        D3D11_SUBRESOURCE_DATA constant_data;
        constant_data.pSysMem = &constants;
        constant_data.SysMemPitch = 0;
        constant_data.SysMemSlicePitch = 0;

        HRESULT hr = device->CreateBuffer(&buffer_desc, &constant_data, &shader_constants);
        if (FAILED(hr)) {
            return;
        }

        context->VSSetConstantBuffers(0, 1, &shader_constants);
    }

    void release() {
        swap_chain->SetFullscreenState(FALSE, NULL);
        sh_vertex->Release();
        sh_pixel->Release();

        vertex_buffer->Release();
        index_buffer->Release();

        swap_chain->Release();
        back_buffer->Release();
        device->Release();
        context->Release();
    }

// P R I V A T E //////////////////////////////////////////////////////////////

    HRESULT compile_shader(LPCWSTR file, LPCSTR entry_point, LPCSTR features, ID3DBlob** program) {
        *program = nullptr;
        ID3DBlob *program_code = nullptr, *error;
        HRESULT hr = D3DCompileFromFile(file, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, entry_point, features, D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &program_code, &error);
        if (FAILED(hr)) {
            if (error) {
                OutputDebugStringA((char*)error->GetBufferPointer());
                error->Release();
            }
            else {
            }
            if (program_code) { program_code->Release(); }
        }
        else { OutputDebugStringA("Shader compiled successfully\n"); }
        *program = program_code;
        return hr;
    }

    void init_pipeline() {
        ID3DBlob *pg_vertex, *pg_pixel;
        compile_shader(L"shaders.shader", "VShader", "vs_4_0", &pg_vertex);
        compile_shader(L"shaders.shader", "PShader", "ps_4_0", &pg_pixel);

        device->CreateVertexShader(pg_vertex->GetBufferPointer(), pg_vertex->GetBufferSize(), NULL, &sh_vertex);
        device->CreatePixelShader(pg_pixel->GetBufferPointer(), pg_pixel->GetBufferSize(), NULL, &sh_pixel);

        context->VSSetShader(sh_vertex, NULL, NULL);
        context->PSSetShader(sh_pixel, NULL, NULL);


        D3D11_INPUT_ELEMENT_DESC ied[] = {
            {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
            {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
        };

        device->CreateInputLayout(ied, 2, pg_vertex->GetBufferPointer(), pg_vertex->GetBufferSize(), &layout);
        context->IASetInputLayout(layout);
    }

    // TODO - function that will build buffers if given a list of verts
    // and a list of indices. Perhaps this is a mesh_data structure?
    void init_graphics() {
        vertex vertices[] = {
            {0.0f, 0.5f, 0.0f, {1.0f, 0.0f, 0.0f, 1.0f} },
            {0.45f, -0.5f, 0.0f, {0.0f, 1.0f, 0.0f, 1.0f} },
            {-0.45f, -0.5f, 0.0f, {0.0f, 0.0f, 1.0f, 1.0f} }
        };

        D3D11_BUFFER_DESC vertex_buffer_description, index_buffer_description;
        ZeroMemory(&vertex_buffer_description, sizeof(vertex_buffer_description));
        ZeroMemory(&index_buffer_description, sizeof(index_buffer_description));

        vertex_buffer_description.Usage = D3D11_USAGE_DEFAULT;
        vertex_buffer_description.ByteWidth = sizeof(vertex) * 3;
        vertex_buffer_description.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        vertex_buffer_description.CPUAccessFlags = 0;

        D3D11_SUBRESOURCE_DATA vertex_data;
        vertex_data.pSysMem = vertices;
        vertex_data.SysMemPitch = 0;
        vertex_data.SysMemSlicePitch = 0;

        device->CreateBuffer(&vertex_buffer_description, &vertex_data, &vertex_buffer);

        unsigned int indices[] = { 0, 1, 2 };
        index_buffer_description.Usage = D3D11_USAGE_DEFAULT;
        index_buffer_description.ByteWidth = sizeof(unsigned int) * 3;
        index_buffer_description.BindFlags = D3D11_BIND_INDEX_BUFFER;
        index_buffer_description.CPUAccessFlags = 0;

        D3D11_SUBRESOURCE_DATA index_data;
        index_data.pSysMem = indices;
        index_data.SysMemPitch = 0;
        index_data.SysMemSlicePitch = 0;

        device->CreateBuffer(&index_buffer_description, &index_data, &index_buffer);
    }

    void build_depth_stencil(unsigned int width, unsigned int height) {
        HRESULT hr;

        D3D11_TEXTURE2D_DESC descDepth;
        descDepth.Width = width;
        descDepth.Height = 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 = device->CreateTexture2D(&descDepth, NULL, &depth_stencil_buffer);

        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
        device->CreateDepthStencilState(&dsDesc, &depth_stencil_state);

        D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
        descDSV.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
        descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
        descDSV.Texture2D.MipSlice = 0;
        hr = device->CreateDepthStencilView(depth_stencil_buffer, // Depth stencil texture
            &descDSV, // Depth stencil desc
            &depth_stencil_view);
    }
} // end namespace

and my shader:

cbuffer buffer {
    matrix model;
    matrix view;
    matrix projection;
};

struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;

    output.position = mul(position, model);
    output.position = mul(output.position, view);
    output.position = mul(output.position, projection);
    output.color = color;
    return output;
}

float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
} 

Any help is greatly appreciated!

\$\endgroup\$
1
\$\begingroup\$

Many possible reasons why something would not be rendered but if the difference is only in the matrix, here's some that I think might be most likely:

  • Camera is too far (a triangle of size 1 in distance ~1732 with 45 degree FOV might simply be too small to see)
  • You're looking at the triangle from the other side and culling is enabled (seems a bit unlikely though, since z<0 should be the right place for a viewpoint)
  • Matrix multiplication might need to be done in the other order (by transposing the matrix/swapping mul arguments, depends on whether those are row/column-major matrices)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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