Advertisement

How to move a directx11 camera via the view matrix?

Started by October 30, 2016 01:02 AM
2 comments, last by DaSutt 8 years, 1 month ago

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

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

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

Advertisement

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.

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.

This topic is closed to new replies.

Advertisement