I have a triangle drawn on my screen and I'm trying to change the position of my view matrix so it moves back and forth, left to right like a camera. I update the view matrix inside the render function. I use the update function to get my key presses to add or subtract a bit from the position vector thats used for the view matrix. The problem is the camera doesn't move forward/backward/left/right when I press the keys. The only way I can move the camera is by setting the initial value in the constructor for my camera class. The camera starts at -50 units along the z axis through the constructor but it won't move when I press the keys as the app is running. I would expect the triangle to get bigger as I move closer to it but it just stays still. I don't get it.
#include <d3d11.h>
#include <assert.h>
#include <DirectXMath.h>
#include <d3dx11effect.h>
#include <d3dcompiler.h>
#include <DirectXColors.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
using namespace DirectX;
/*
********************************************************************************************************
*
* WINDOW STUFF
*
********************************************************************************************************
*/
HWND main_window;
HINSTANCE hInst;
int window_width = 800;
int window_height = 600;
LARGE_INTEGER curr_time;
LARGE_INTEGER prev_time;
LARGE_INTEGER frequency;
float delta_time = 0;
/*
********************************************************************************************************
*
* DIRECTX STUFF
*
********************************************************************************************************
*/
ID3D11Device* device;
ID3D11DeviceContext* immediate_context;
IDXGISwapChain* swap_chain;
ID3D11RenderTargetView* render_target_view;
ID3D11DepthStencilView* depth_stencil_view;
ID3D11Texture2D* depth_stencil_buffer;
ID3D11InputLayout* input_layout;
ID3DX11Effect* effect;
ID3DX11EffectTechnique* technique;
ID3D11Buffer* tri_vertex_buffer;
ID3D11VertexShader* vertex_shader;
ID3D11PixelShader* pixel_shader;
D3D_FEATURE_LEVEL feature_level;
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
D3D11_TEXTURE2D_DESC texture_desc;
D3D11_VIEWPORT view_port;
struct cb_per_frame
{
XMMATRIX world_view_proj;
};
ID3D11Buffer* const_per_frame_buffer;
cb_per_frame const_per_frame;
struct vertex
{
XMFLOAT4 Pos;
XMFLOAT4 Color;
};
D3D11_INPUT_ELEMENT_DESC input_desc[] =
{
{ "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 },
};
vertex tri_verts[] =
{
XMFLOAT4(0.0f, 0.5f, 2.5f, 1.0f),
XMFLOAT4(0.5f, 0.0f, 0.3f, 0.0f),
XMFLOAT4(0.5f, -0.5f, 2.5f, 1.0f),
XMFLOAT4(0.8f, 0.3f, 0.5f, 0.0f),
XMFLOAT4(-0.5f, -0.5f, 2.5f, 1.0f),
XMFLOAT4(1.0f, 0.5f, 0.6f, 0.0f),
};
/*
********************************************************************************************************
*
* CLASS DECLARATIONS
*
********************************************************************************************************
*/
class camera
{
public:
XMFLOAT3 position_vector;
XMFLOAT3 right_vector;
XMFLOAT3 up_vector;
XMFLOAT3 look_vector;
XMFLOAT4X4 view_matrix;
XMFLOAT4X4 projection_matrix;
XMFLOAT4X4 world_matrix;
XMMATRIX world_view_proj;
camera();
void walk(float);
void strafe(float);
void update_view_matrix();
void set_perspective_matrix(float, float, float, float);
//void add_to_position(XMFLOAT3 &);
XMMATRIX get_world_view_proj();
};
camera my_camera;
/*
********************************************************************************************************
*
* FORWARD FUNCTION DECLARATIONS
*
********************************************************************************************************
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
bool InitDirectX();
void time_tick();
void set_buffers();
void render();
void create_shaders_and_input_layout();
void update();
float get_aspect_ratio();
void create_effect();
/*
********************************************************************************************************
*
* MAIN FUNCTION
*
********************************************************************************************************
*/
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"A Window";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
hInst = hInstance;
main_window = CreateWindow(
L"A Window",
L"Win32 Engine",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
window_width, window_height,
NULL,
NULL,
hInstance,
NULL
);
if (!main_window)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
ShowWindow(main_window,
nCmdShow);
UpdateWindow(main_window);
InitDirectX();
set_buffers();
create_shaders_and_input_layout();
create_effect();
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
time_tick();
update();
render();
}
}
return (int)msg.wParam;
}
/*
********************************************************************************************************
*
* WINDOWS MESSAGE HANDLING
*
********************************************************************************************************
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
/*
********************************************************************************************************
*
* INIT DIRECTX
*
********************************************************************************************************
*/
bool InitDirectX()
{
HRESULT hr = D3D11CreateDevice(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
0,
D3D11_SDK_VERSION,
&device,
&feature_level,
&immediate_context);
if (FAILED(hr))
{
MessageBox(0, L"Create Device failed.", L"Error", MB_OK);
return false;
}
if (feature_level != D3D_FEATURE_LEVEL_11_0)
{
MessageBox(0, L"D3D11 not supported.", L"Error", MB_OK);
return false;
}
swap_chain_desc.BufferDesc.Width = window_width;
swap_chain_desc.BufferDesc.Height = window_height;
swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.BufferCount = 1;
swap_chain_desc.OutputWindow = main_window;
swap_chain_desc.Windowed = true;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swap_chain_desc.Flags = 0;
IDXGIDevice * pDXGIDevice = nullptr;
hr = device->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
if (FAILED(hr))
{
MessageBox(0, L"QueryInterface() failed.", L"Error", MB_OK);
}
IDXGIAdapter * pDXGIAdapter = nullptr;
hr = pDXGIDevice->GetAdapter(&pDXGIAdapter);
if (FAILED(hr))
{
MessageBox(0, L"GetAdapter failed", L"Error", MB_OK);
}
IDXGIFactory * pIDXGIFactory = nullptr;
pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&pIDXGIFactory);
pIDXGIFactory->CreateSwapChain(device, &swap_chain_desc, &swap_chain);
pDXGIDevice->Release();
pDXGIAdapter->Release();
pIDXGIFactory->Release();
ID3D11Texture2D* back_buffer;
hr = swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&back_buffer));
if (FAILED(hr))
{
MessageBox(0, L"GetBuffer() failed.", L"Error", MB_OK);
}
hr = device->CreateRenderTargetView(back_buffer, NULL, &render_target_view);
if (FAILED(hr))
{
MessageBox(0, L"CreateRenderTargetView() failed", L"Error", MB_OK);
}
back_buffer->Release();
ZeroMemory(&texture_desc, sizeof(texture_desc));
texture_desc.Width = window_width;
texture_desc.Height = window_height;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0;
hr = device->CreateTexture2D(&texture_desc, NULL, &depth_stencil_buffer);
if (FAILED(hr))
{
MessageBox(0, L"CreateTexture2d() failed.", L"Error", MB_OK);
}
D3D11_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc;
ZeroMemory(&depth_stencil_view_desc, sizeof(depth_stencil_view_desc));
depth_stencil_view_desc.Format = texture_desc.Format;
depth_stencil_view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depth_stencil_view_desc.Texture2D.MipSlice = 0;
hr = device->CreateDepthStencilView(depth_stencil_buffer, &depth_stencil_view_desc, &depth_stencil_view);
if (FAILED(hr))
{
MessageBox(0, L"CreateDepthStencilView() failed.", L"Error", MB_OK);
}
immediate_context->OMSetRenderTargets(1, &render_target_view, depth_stencil_view);
view_port.TopLeftX = 0;
view_port.TopLeftY = 0;
view_port.Width = static_cast<float>(window_width);
view_port.Height = static_cast<float>(window_height);
view_port.MinDepth = 0.0f;
view_port.MaxDepth = 1.0f;
immediate_context->RSSetViewports(1, &view_port);
}
/*
********************************************************************************************************
*
* SET BUFFERS
*
********************************************************************************************************
*/
void set_buffers()
{
D3D11_BUFFER_DESC vertex_buffer_desc;
vertex_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
vertex_buffer_desc.ByteWidth = sizeof(vertex) * 3;
vertex_buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertex_buffer_desc.CPUAccessFlags = 0;
vertex_buffer_desc.MiscFlags = 0;
vertex_buffer_desc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vertex_init_data;
ZeroMemory(&vertex_init_data, sizeof(vertex_init_data));
vertex_init_data.pSysMem = tri_verts;
HRESULT hr = device->CreateBuffer(&vertex_buffer_desc, &vertex_init_data, &tri_vertex_buffer);
if (FAILED(hr))
{
MessageBox(NULL, L"Create Vertex Buffer Failed", L"Error", MB_OK);
}
UINT stride = sizeof(vertex);
UINT offset = 0;
immediate_context->IASetVertexBuffers(0, 1, &tri_vertex_buffer, &stride, &offset);
const_per_frame.world_view_proj = XMMatrixTranspose(my_camera.get_world_view_proj());
D3D11_BUFFER_DESC constant_buffer_desc;
ZeroMemory(&constant_buffer_desc, sizeof(D3D11_BUFFER_DESC));
constant_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
constant_buffer_desc.ByteWidth = sizeof(cb_per_frame);
constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constant_buffer_desc.CPUAccessFlags = 0;
constant_buffer_desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA const_buf_init_data;
const_buf_init_data.pSysMem = &const_per_frame;
const_buf_init_data.SysMemPitch = 0;
const_buf_init_data.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&constant_buffer_desc, &const_buf_init_data, &const_per_frame_buffer);
if (FAILED(hr))
{
MessageBox(NULL, L"Failed to create constant buffer", L"Error", MB_OK);
}
//immediate_context->VSSetConstantBuffers(0, 1, &const_per_frame_buffer);
}
/*
********************************************************************************************************
*
* CREATE SHADERS + INPUT LAYOUT
*
********************************************************************************************************
*/
void create_shaders_and_input_layout()
{
ID3DBlob* vs_blob = NULL;
ID3DBlob* error_blob = NULL;
HRESULT hr = D3DCompileFromFile(L"my_shader.fx", NULL, NULL, "VS", "vs_5_0", NULL, 0, &vs_blob, &error_blob);
if (FAILED(hr))
{
MessageBox(NULL,
L"The FX file (VS) cannot be compiled.Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
return;
}
hr = device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), NULL, &vertex_shader);
if (FAILED(hr))
{
MessageBox(NULL, L"Cannot create vertex shader", L"Error", MB_OK);
return;
}
ID3DBlob* ps_error_blob;
ID3DBlob* ps_blob;
hr = D3DCompileFromFile(L"my_shader.fx", NULL, NULL, "PS", "ps_5_0", NULL, 0, &ps_blob, &ps_error_blob);
if (FAILED(hr))
{
MessageBox(NULL,
L"The FX file (PS) cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
return;
}
hr = device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), NULL, &pixel_shader);
if (FAILED(hr))
{
MessageBox(NULL, L"Cannot create Pixel shader", L"Error", MB_OK);
}
UINT num_elements = ARRAYSIZE(input_desc);
hr = device->CreateInputLayout(input_desc, num_elements, vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(),
&input_layout);
if (FAILED(hr))
{
MessageBox(NULL, L"Create Input Layout Failed", L"Error", MB_OK);
return;
}
immediate_context->IASetInputLayout(input_layout);
immediate_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
/*
********************************************************************************************************
*
* RENDERING STUFF
*
********************************************************************************************************
*/
void render()
{
my_camera.update_view_matrix();
const_per_frame.world_view_proj = XMMatrixInverse(0, XMMatrixTranspose(my_camera.get_world_view_proj()));
immediate_context->VSSetShader(vertex_shader, NULL, 0);
immediate_context->PSSetShader(pixel_shader, NULL, 0);
immediate_context->VSSetConstantBuffers(0, 1, &const_per_frame_buffer);
immediate_context->ClearRenderTargetView(render_target_view, Colors::MidnightBlue);
immediate_context->ClearDepthStencilView(depth_stencil_view, D3D11_CLEAR_DEPTH, 1.0f, 0);
immediate_context->Draw(3, 0);
swap_chain->Present(0, 0);
}
/*
********************************************************************************************************
*
* CHECK FOR INPUT (UPDATE)
*
********************************************************************************************************
*/
void update()
{
if (GetAsyncKeyState('W') & 0x8000)
{
my_camera.walk(0.03f);
//my_camera.add_to_position(XMFLOAT3(0.0f, 0.0f, 0.03f));
}
if (GetAsyncKeyState('A') & 0x8000)
{
my_camera.strafe(-0.03f);
}
if (GetAsyncKeyState('S') & 0x8000)
{
my_camera.walk(-0.03f);
}
if (GetAsyncKeyState('D') & 0x8000)
{
my_camera.strafe(0.03f);
}
}
/*
********************************************************************************************************
*
* TIME TICK
*
********************************************************************************************************
*/
void time_tick()
{
QueryPerformanceCounter(&curr_time);
if (frequency.QuadPart == NULL)
QueryPerformanceFrequency(&frequency);
if (prev_time.QuadPart == NULL)
prev_time.QuadPart = 0;
delta_time = (curr_time.QuadPart - prev_time.QuadPart) / frequency.QuadPart;
prev_time = curr_time;
}
/*
********************************************************************************************************
*
* ASPECT RATIO
*
********************************************************************************************************
*/
float get_aspect_ratio()
{
return (float)window_width / window_height;
}
/*
********************************************************************************************************
*
* EFFECTS
*
********************************************************************************************************
*/
void create_effect()
{
ID3DBlob* effect_blob;
ID3DBlob* error_blob;
HRESULT hr = D3DCompileFromFile(L"my_shader.fx", NULL, NULL, 0, "fx_5_0", 0, 0, &effect_blob, &error_blob);
if (FAILED(hr))
{
MessageBox(NULL, L"D3DCompileFromFile failed", L"Error", MB_OK);
}
hr = D3DX11CreateEffectFromMemory(effect_blob->GetBufferPointer(), effect_blob->GetBufferSize(), 0, device, &effect);
if (FAILED(hr))
MessageBox(NULL, L"CreateEffectFromMemory failed", L"Error", MB_OK);
}
/*
********************************************************************************************************
*
* CAMERA CLASS
*
********************************************************************************************************
*/
camera::camera()
: position_vector(0.0f, 0.0f, -50.5f),
right_vector(1.0f, 0.0f, 0.0f),
up_vector(0.0f, 1.0f, 0.0f),
look_vector(0.0f, 0.0f, 1.0f)
{
XMMATRIX identity = XMMatrixIdentity();
XMStoreFloat4x4(&world_matrix, identity);
set_perspective_matrix(0.25*XM_PI, get_aspect_ratio(), 1.0f, 1000.0f);
update_view_matrix();
}
void camera::set_perspective_matrix(float fov, float aspect_ratio, float near_z, float far_z)
{
XMMATRIX perspective = XMMatrixPerspectiveFovLH(fov, aspect_ratio, near_z, far_z);
XMStoreFloat4x4(&projection_matrix, perspective);
}
void camera::update_view_matrix()
{
XMVECTOR right = XMLoadFloat3(&right_vector);
XMVECTOR up = XMLoadFloat3(&up_vector);
XMVECTOR look = XMLoadFloat3(&look_vector);
XMVECTOR position = XMLoadFloat3(&position_vector);
look = XMVector3Normalize(look);
up = XMVector3Normalize(XMVector3Cross(look, right));
right = XMVector3Cross(up, look);
XMStoreFloat3(&right_vector, right);
XMStoreFloat3(&up_vector, up);
XMStoreFloat3(&look_vector, look);
XMMATRIX view = XMMatrixLookAtLH(position, look, up);
XMStoreFloat4x4(&view_matrix, view);
}
void camera::walk(float move_amount)
{
XMVECTOR amount = XMVectorReplicate(move_amount);
XMVECTOR look = XMLoadFloat3(&look_vector);
XMVECTOR position = XMLoadFloat3(&position_vector);
XMStoreFloat3(&position_vector, XMVectorMultiplyAdd(position, look, amount));
}
void camera::strafe(float move_amount)
{
XMVECTOR amount = XMVectorReplicate(move_amount);
XMVECTOR right = XMLoadFloat3(&right_vector);
XMVECTOR position = XMLoadFloat3(&position_vector);
XMStoreFloat3(&position_vector, XMVectorMultiplyAdd(position, right, amount));
}
XMMATRIX camera::get_world_view_proj()
{
XMMATRIX world = XMLoadFloat4x4(&world_matrix);
XMMATRIX view = XMLoadFloat4x4(&view_matrix);
XMMATRIX proj = XMLoadFloat4x4(&projection_matrix);
return world*view*proj;
}
/*void camera::add_to_position(XMFLOAT3& amount_to_move)
{
XMVECTOR amount = XMLoadFloat3(&amount_to_move);
XMVECTOR pos = XMLoadFloat3(&position_vector);
pos += amount;
XMStoreFloat3(&position_vector, pos);
} */
Here is my shader:
cbuffer cb_per_frame
{
float4x4 world_view_proj;
};
struct vertex_in
{
float4 PosL : POSITION;
float4 Color : COLOR;
};
struct vertex_out
{
float4 PosH : SV_POSITION;
float4 Color : COLOR;
};
vertex_out VS(vertex_in v_in)
{
vertex_out v_out = (vertex_out)0;
v_out.PosH = mul(v_in.PosL, world_view_proj);
v_out.Color = v_in.Color;
return v_out;
}
float4 PS(vertex_out v_in) : SV_Target
{
return v_in.Color;
}