Sign in to follow this  

How to move a directx11 camera via the view matrix?

This topic is 409 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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;
}

Edited by TommyThree

Share this post


Link to post
Share on other sites

What if you change all the camera (pos, dir, amount) to (amount, dir, pos)?

 

XMVectorMultiplyAdd(position, right, amount) => XMVectorMultiplyAdd(amount, right, position)

 

One of the many things I tried.  :(   Didn't work.

Share this post


Link to post
Share on other sites
Nothing happens because the constant buffer is not updated. By updating const_per_frame you only change the value in CPU memory. To have the change on the GPU you can use updateSubresource or map/unmap the constant buffer.
If you want to debug stuff like this your self I suggest using renderdoc.

Share this post


Link to post
Share on other sites

This topic is 409 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this