Merge pull request #4 from xLightling/a5_camera

A5: Camera
This commit is contained in:
Lightling 2022-02-13 15:20:50 -05:00 committed by GitHub
commit 55b882af52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 260 additions and 22 deletions

View file

@ -6,4 +6,6 @@ struct VertexShaderExternalData
{
DirectX::XMFLOAT4 colorTint;
DirectX::XMFLOAT4X4 world;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};

131
Camera.cpp Normal file
View file

@ -0,0 +1,131 @@
#include "Camera.h"
#include "Input.h"
using namespace DirectX;
Camera::Camera(float _x, float _y, float _z, float _aspect, float _fov, float _near, float _far)
{
transform.SetPosition(_x, _y, _z);
aspect = _aspect;
fovYRadians = XMConvertToRadians(_fov);
clipNear = _near;
clipFar = _far;
UpdateViewMatrix();
UpdateProjectionMatrix();
}
Camera::~Camera()
{
}
void Camera::Update(float _dt)
{
ReadInput(_dt);
ClampRotation();
UpdateViewMatrix();
}
void Camera::UpdateViewMatrix()
{
XMFLOAT3 worldUp = XMFLOAT3(0, 1, 0);
XMFLOAT3 position = transform.GetPosition();
XMFLOAT3 forward = transform.GetForward();
XMMATRIX view = XMMatrixLookToLH(XMLoadFloat3(&position), XMLoadFloat3(&forward), XMLoadFloat3(&worldUp));
XMStoreFloat4x4(&viewMatrix, view);
}
void Camera::UpdateProjectionMatrix()
{
XMMATRIX projection = XMMatrixPerspectiveFovLH(fovYRadians, aspect, clipNear, clipFar);
XMStoreFloat4x4(&projectionMatrix, projection);
}
Transform* Camera::GetTransform()
{
return &transform;
}
DirectX::XMFLOAT4X4 Camera::GetViewMatrix()
{
return viewMatrix;
}
DirectX::XMFLOAT4X4 Camera::GetProjectionMatrix()
{
return projectionMatrix;
}
void Camera::SetAspect(float _aspect)
{
aspect = _aspect;
UpdateProjectionMatrix();
}
void Camera::SetFOV(float _fov)
{
fovYRadians = XMConvertToRadians(_fov);
UpdateProjectionMatrix();
}
void Camera::SetNearClip(float _near)
{
clipNear = _near;
UpdateProjectionMatrix();
}
void Camera::SetFarClip(float _far)
{
clipFar = _far;
UpdateProjectionMatrix();
}
void Camera::ReadInput(float _dt)
{
Input& input = Input::GetInstance();
float modify = 1.0f;
float moveLong = 0;
float moveLat = 0;
float moveVert = 0;
if (input.KeyDown('W')) moveLong += 1.0f;
if (input.KeyDown('S')) moveLong -= 1.0f;
if (input.KeyDown('D')) moveLat += 1.0f;
if (input.KeyDown('A')) moveLat -= 1.0f;
if (input.KeyDown('E')) moveVert += 1.0f;
if (input.KeyDown('Q')) moveVert -= 1.0f;
if (input.KeyDown(VK_SHIFT)) modify *= 2.0f;
if (input.KeyDown(VK_CONTROL)) modify /= 2.0f;
transform.TranslateRelative(moveLat * _dt * modify, 0, moveLong * _dt * modify);
transform.TranslateAbsolute(0, moveVert * _dt * modify, 0);
if (input.MouseLeftDown())
{
float cursorX = (float)input.GetMouseXDelta();
float cursorY = (float)input.GetMouseYDelta();
static const float mouseSpeed = 0.1f;
transform.Rotate(cursorY * _dt * mouseSpeed, cursorX * _dt * mouseSpeed, 0);
}
float rotateX = 0;
float rotateY = 0;
if (input.KeyDown('C')) rotateX += 1.0f;
if (input.KeyDown('Z')) rotateX -= 1.0f;
if (input.KeyDown('F')) rotateY += 1.0f;
if (input.KeyDown('R')) rotateY -= 1.0f;
transform.Rotate(rotateY * _dt, rotateX * _dt, 0);
}
void Camera::ClampRotation()
{
static const float rotationLimit = XM_PIDIV2 - XM_1DIV2PI;
XMFLOAT3 eulerAngles = transform.GetEulerAngles();
if (eulerAngles.x > rotationLimit) transform.SetRotation(rotationLimit, eulerAngles.y, eulerAngles.z);
if (eulerAngles.x < -rotationLimit) transform.SetRotation(-rotationLimit, eulerAngles.y, eulerAngles.z);
}

38
Camera.h Normal file
View file

@ -0,0 +1,38 @@
#pragma once
#include "Transform.h"
#include <memory>
class Camera
{
public:
Camera(float _x, float _y, float _z, float _aspect, float _fov, float _near, float _far);
~Camera();
void Update(float _dt);
void UpdateViewMatrix();
void UpdateProjectionMatrix();
Transform* GetTransform();
DirectX::XMFLOAT4X4 GetViewMatrix();
DirectX::XMFLOAT4X4 GetProjectionMatrix();
void SetAspect(float _aspect);
void SetFOV(float _fov);
void SetNearClip(float _near);
void SetFarClip(float _far);
private:
float aspect;
float fovYRadians;
float clipNear;
float clipFar;
DirectX::XMFLOAT4X4 viewMatrix;
DirectX::XMFLOAT4X4 projectionMatrix;
Transform transform;
void ReadInput(float _dt);
void ClampRotation();
};

View file

@ -123,6 +123,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Camera.cpp" />
<ClCompile Include="DXCore.cpp" />
<ClCompile Include="Entity.cpp" />
<ClCompile Include="Game.cpp" />
@ -133,6 +134,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="BufferStructs.h" />
<ClInclude Include="Camera.h" />
<ClInclude Include="DXCore.h" />
<ClInclude Include="Entity.h" />
<ClInclude Include="Game.h" />

View file

@ -39,6 +39,9 @@
<ClCompile Include="Entity.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Vertex.h">
@ -65,6 +68,9 @@
<ClInclude Include="Entity.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Camera.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<FxCompile Include="PixelShader.hlsl">

View file

@ -6,6 +6,7 @@
// Needed for a helper function to read compiled shader files from the hard drive
#pragma comment(lib, "d3dcompiler.lib")
#include <d3dcompiler.h>
#include <iostream>
// For the DirectX Math library
using namespace DirectX;
@ -32,6 +33,7 @@ Game::Game(HINSTANCE hInstance)
CreateConsoleWindow(500, 120, 32, 120);
printf("Console window created successfully. Feel free to printf() here.\n");
#endif
camera = std::make_shared<Camera>(0.0f, 0.0f, -1.0f, (float)width / height, 70, 0.01f, 1000.0f);
}
// --------------------------------------------------------
@ -168,11 +170,12 @@ void Game::CreateBasicGeometry()
XMFLOAT4 white = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
Vertex verts1[] = {
{ XMFLOAT3(+0.50f, +0.75f, +0.00f), red },
{ XMFLOAT3(+0.75f, +0.25f, +0.00f), blue },
{ XMFLOAT3(+0.25f, +0.25f, +0.00f), green },
{ XMFLOAT3(+0.00f, +0.00f, +0.25f), white },
{ XMFLOAT3(-0.25f, -0.25f, -0.25f), red },
{ XMFLOAT3(+0.00f, +0.25f, -0.25f), green },
{ XMFLOAT3(+0.25f, -0.25f, -0.25f), blue },
};
unsigned int ind1[] = { 0, 1, 2 };
unsigned int ind1[] = { 0,1,2 , 0,2,3 , 0,3,1 , 3,2,1 };
Vertex verts2[] = {
{ XMFLOAT3(-0.75f, +0.50f, +0.00f), red },
@ -180,22 +183,22 @@ void Game::CreateBasicGeometry()
{ XMFLOAT3(-0.50f, +0.20f, +0.00f), red },
{ XMFLOAT3(-0.75f, +0.20f, +0.00f), blue },
};
unsigned int ind2[] = { 0, 1, 2, 0, 2, 3 };
unsigned int ind2[] = { 0,1,2, 0,2,3 , 3,2,0 , 2,1,0 };
Vertex verts3[] = {
{ XMFLOAT3(+0.00f, +0.30f, +0.00f), white },
{ XMFLOAT3(+0.15f, +0.15f, +0.00f), black },
{ XMFLOAT3(+0.15f, -0.15f, +0.00f), white },
{ XMFLOAT3(+0.00f, -0.30f, +0.00f), black },
{ XMFLOAT3(-0.15f, -0.15f, +0.00f), white },
{ XMFLOAT3(-0.15f, +0.15f, +0.00f), black },
{ XMFLOAT3(+0.00f, +0.30f, +0.15f), white },
{ XMFLOAT3(+0.30f, +0.15f, +0.00f), black },
{ XMFLOAT3(+0.30f, -0.15f, +0.00f), white },
{ XMFLOAT3(+0.00f, -0.30f, +0.15f), black },
{ XMFLOAT3(-0.30f, -0.15f, +0.00f), white },
{ XMFLOAT3(-0.30f, +0.15f, +0.00f), black },
};
unsigned int ind3[] = { 0,1,5 , 1,2,5 , 2,3,4 , 2,4,5 };
unsigned int ind3[] = { 0,1,5 , 1,2,5 , 2,3,4 , 2,4,5 , 5,4,2 , 4,3,2 , 5,2,1 , 5,1,0 };
shapes = {
std::make_shared<Mesh>(verts1, 03, ind1, 03, device, context),
std::make_shared<Mesh>(verts2, 04, ind2, 06, device, context),
std::make_shared<Mesh>(verts3, 06, ind3, 12, device, context),
std::make_shared<Mesh>(verts1, 4, ind1, 12, device, context),
std::make_shared<Mesh>(verts2, 4, ind2, 12, device, context),
std::make_shared<Mesh>(verts3, 6, ind3, 24, device, context),
};
entities = {
@ -220,6 +223,9 @@ void Game::OnResize()
{
// Handle base-level DX resize stuff
DXCore::OnResize();
// Ensure camera has its projection matrix updated when window size changes
camera->SetAspect((float)width / height);
}
// --------------------------------------------------------
@ -231,24 +237,26 @@ void Game::Update(float deltaTime, float totalTime)
if (Input::GetInstance().KeyDown(VK_ESCAPE))
Quit();
camera->Update(deltaTime);
for (int i = 0; i < entities.size(); ++i)
{
entities[i]->GetTransform()->SetScale(0.1f * (i + 1), 0.1f * (i + 1), 0.1f * (i + 1));
entities[i]->GetTransform()->SetScale(0.2f * (i + 1), 0.2f * (i + 1), 0.2f * (i + 1));
entities[i]->GetTransform()->SetRotation(0.1f * (i + 1) * sin(totalTime), 0.1f * (i + 1) * sin(totalTime), 0.1f * (i + 1) * sin(totalTime));
// this range uses shapes[0] for testing
if (i < 3)
{
entities[i]->GetTransform()->SetPosition(tan((double)totalTime * ((double)i + (double)1)) * 0.1f, 0, 0);
entities[i]->GetTransform()->SetPosition(tan((double)totalTime * ((double)i + (double)1)) * 0.1f, sin(totalTime) * 0.1f, (double)i * 0.1f);
}
// this range uses shapes[1] for testing
else if (i < 6)
{
entities[i]->GetTransform()->SetPosition(sin((double)totalTime * ((double)i + (double)1)) * 0.1f, 0, 0);
entities[i]->GetTransform()->SetPosition(sin((double)totalTime * ((double)i + (double)1)) * 0.1f, cos(totalTime) * 0.1f, (double)i * 0.1f);
}
// this range uses shapes[2] for testing
else
{
entities[i]->GetTransform()->SetPosition(sin((double)totalTime * ((double)i + (double)1)) * cos(totalTime) * 0.1f, 0, 0);
entities[i]->GetTransform()->SetPosition(sin((double)totalTime * ((double)i + (double)1)) * cos(totalTime) * 0.1f, 0, (double)i * 0.1f);
}
}
}
@ -277,6 +285,8 @@ void Game::Draw(float deltaTime, float totalTime)
VertexShaderExternalData vsData;
vsData.colorTint = XMFLOAT4(1.0f, 0.5f, 0.5f, 1.0f);
vsData.world = entity->GetTransform()->GetWorldMatrix();
vsData.view = camera->GetViewMatrix();
vsData.projection = camera->GetProjectionMatrix();
// copy constant buffer to resource
D3D11_MAPPED_SUBRESOURCE mappedBuffer = {};

5
Game.h
View file

@ -1,6 +1,7 @@
#pragma once
#include "DXCore.h"
#include "Camera.h"
#include "Mesh.h"
#include "Entity.h"
#include <DirectXMath.h>
@ -44,8 +45,10 @@ private:
// Temporary A2 shapes
std::vector<std::shared_ptr<Mesh>> shapes;
// Temporary A3 entities;
// Temporary A4 entities;
std::vector<std::shared_ptr<Entity>> entities;
// A5 Camera
std::shared_ptr<Camera> camera;
Microsoft::WRL::ComPtr<ID3D11Buffer> constantBufferVS;
};

View file

@ -38,6 +38,21 @@ DirectX::XMFLOAT4X4 Transform::GetWorldMatrixInverseTranspose()
return worldMatrixInverseTranspose;
}
DirectX::XMFLOAT3 Transform::GetRight()
{
return right;
}
DirectX::XMFLOAT3 Transform::GetUp()
{
return up;
}
DirectX::XMFLOAT3 Transform::GetForward()
{
return forward;
}
// XMVECTOR & XMStoreFloat compiles down to something faster than position += x,y,z because it happens all at once
void Transform::SetPosition(float _x, float _y, float _z)
@ -52,6 +67,7 @@ void Transform::SetRotation(float _pitch, float _yaw, float _roll)
XMVECTOR newRotation = XMVectorSet(_pitch, _yaw, _roll, 0);
XMStoreFloat3(&eulerAngles, newRotation);
worldMatrixChanged = true;
UpdateDirections();
}
void Transform::SetScale(float _x, float _y, float _z)
@ -69,12 +85,22 @@ void Transform::TranslateAbsolute(float _x, float _y, float _z)
worldMatrixChanged = true;
}
void Transform::TranslateRelative(float _x, float _y, float _z)
{
XMVECTOR moveVector = XMVectorSet(_x, _y, _z, 0);
XMVECTOR rotateVector = XMVector3Rotate(moveVector, XMQuaternionRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
XMVECTOR newPosition = XMLoadFloat3(&position) + rotateVector;
XMStoreFloat3(&position, newPosition);
worldMatrixChanged = true;
}
void Transform::Rotate(float _pitch, float _yaw, float _roll)
{
XMVECTOR newRotation = XMLoadFloat3(&position);
XMVECTOR newRotation = XMLoadFloat3(&eulerAngles);
XMVECTOR offset = XMVectorSet(_pitch, _yaw, _roll, 0);
XMStoreFloat3(&eulerAngles, newRotation + offset);
worldMatrixChanged = true;
UpdateDirections();
}
void Transform::Scale(float _x, float _y, float _z)
@ -94,3 +120,10 @@ void Transform::UpdateWorldMatrix()
XMStoreFloat4x4(&worldMatrix, matrixScale * matrixRotation * matrixPosition);
XMStoreFloat4x4(&worldMatrixInverseTranspose, XMMatrixInverse(0, XMMatrixTranspose(XMLoadFloat4x4(&worldMatrix))));
}
void Transform::UpdateDirections()
{
XMStoreFloat3(&right, XMVector3Rotate(XMVectorSet(1, 0, 0, 0), XMQuaternionRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z)));
XMStoreFloat3(&up, XMVector3Rotate(XMVectorSet(0, 1, 0, 0), XMQuaternionRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z)));
XMStoreFloat3(&forward, XMVector3Rotate(XMVectorSet(0, 0, 1, 0), XMQuaternionRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z)));
}

View file

@ -13,12 +13,16 @@ public:
DirectX::XMFLOAT3 GetScale();
DirectX::XMFLOAT4X4 GetWorldMatrix();
DirectX::XMFLOAT4X4 GetWorldMatrixInverseTranspose();
DirectX::XMFLOAT3 GetRight();
DirectX::XMFLOAT3 GetUp();
DirectX::XMFLOAT3 GetForward();
void SetPosition(float _x, float _y, float _z);
void SetRotation(float _pitch, float _yaw, float _roll);
void SetScale(float _x, float _y, float _z);
void TranslateAbsolute(float _x, float _y, float _z);
void TranslateRelative(float _x, float _y, float _z);
void Rotate(float _pitch, float _yaw, float _roll);
void Scale(float _x, float _y, float _z);
@ -29,6 +33,10 @@ private:
DirectX::XMFLOAT4X4 worldMatrix;
DirectX::XMFLOAT4X4 worldMatrixInverseTranspose;
bool worldMatrixChanged;
DirectX::XMFLOAT3 right;
DirectX::XMFLOAT3 up;
DirectX::XMFLOAT3 forward;
void UpdateWorldMatrix();
void UpdateDirections();
};

View file

@ -2,6 +2,8 @@ cbuffer ExternalData : register(b0)
{
float4 colorTint;
matrix world;
matrix view;
matrix projection;
}
// Struct representing a single vertex worth of data
@ -48,6 +50,9 @@ VertexToPixel main( VertexShaderInput input )
// Set up output struct
VertexToPixel output;
// Convert vertex to world view projection
matrix worldViewProjection = mul(mul(projection, view), world);
// Here we're essentially passing the input position directly through to the next
// stage (rasterizer), though it needs to be a 4-component vector now.
// - To be considered within the bounds of the screen, the X and Y components
@ -56,7 +61,7 @@ VertexToPixel main( VertexShaderInput input )
// - Each of these components is then automatically divided by the W component,
// which we're leaving at 1.0 for now (this is more useful when dealing with
// a perspective projection matrix, which we'll get to in the future).
output.screenPosition = mul(world, float4(input.localPosition, 1.0f));
output.screenPosition = mul(worldViewProjection, float4(input.localPosition, 1.0f));
// Pass the color through
// - The values will be interpolated per-pixel by the rasterizer