diff --git a/BufferStructs.h b/BufferStructs.h
index a7bda48..a8951ce 100644
--- a/BufferStructs.h
+++ b/BufferStructs.h
@@ -5,5 +5,5 @@
struct VertexShaderExternalData
{
DirectX::XMFLOAT4 colorTint;
- DirectX::XMFLOAT3 offset;
+ DirectX::XMFLOAT4X4 world;
};
diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj
index eafecb3..e3338d0 100644
--- a/DX11Starter.vcxproj
+++ b/DX11Starter.vcxproj
@@ -124,17 +124,21 @@
+
+
+
+
diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters
index a9a657e..0ee7d77 100644
--- a/DX11Starter.vcxproj.filters
+++ b/DX11Starter.vcxproj.filters
@@ -33,6 +33,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -53,6 +59,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/Entity.cpp b/Entity.cpp
new file mode 100644
index 0000000..0d3835a
--- /dev/null
+++ b/Entity.cpp
@@ -0,0 +1,16 @@
+#include "Entity.h"
+
+Entity::Entity(std::shared_ptr _mesh)
+{
+ mesh = _mesh;
+}
+
+Transform* Entity::GetTransform()
+{
+ return &transform;
+}
+
+std::shared_ptr Entity::GetMesh()
+{
+ return mesh;
+}
diff --git a/Entity.h b/Entity.h
new file mode 100644
index 0000000..ea780c9
--- /dev/null
+++ b/Entity.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Mesh.h"
+#include "Transform.h"
+#include
+
+class Entity
+{
+public:
+ Entity(std::shared_ptr _mesh);
+
+ Transform* GetTransform();
+ std::shared_ptr GetMesh();
+
+private:
+ Transform transform;
+ std::shared_ptr mesh;
+};
diff --git a/Game.cpp b/Game.cpp
index 4d2b457..ed088cf 100644
--- a/Game.cpp
+++ b/Game.cpp
@@ -197,6 +197,18 @@ void Game::CreateBasicGeometry()
std::make_shared(verts2, 04, ind2, 06, device, context),
std::make_shared(verts3, 06, ind3, 12, device, context),
};
+
+ entities = {
+ std::make_shared(shapes[0]),
+ std::make_shared(shapes[0]),
+ std::make_shared(shapes[0]),
+ std::make_shared(shapes[1]),
+ std::make_shared(shapes[1]),
+ std::make_shared(shapes[1]),
+ std::make_shared(shapes[2]),
+ std::make_shared(shapes[2]),
+ std::make_shared(shapes[2]),
+ };
}
@@ -218,6 +230,27 @@ void Game::Update(float deltaTime, float totalTime)
// Example input checking: Quit if the escape key is pressed
if (Input::GetInstance().KeyDown(VK_ESCAPE))
Quit();
+
+ 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()->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);
+ }
+ // 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);
+ }
+ // 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);
+ }
+ }
}
// --------------------------------------------------------
@@ -225,26 +258,8 @@ void Game::Update(float deltaTime, float totalTime)
// --------------------------------------------------------
void Game::Draw(float deltaTime, float totalTime)
{
- // create constant buffer
- VertexShaderExternalData vsData;
- vsData.colorTint = XMFLOAT4(1.0f, 0.5f, 0.5f, 1.0f);
- vsData.offset = XMFLOAT3(0.25f, 0.0f, 0.0f);
-
- // copy constant buffer to resource
- D3D11_MAPPED_SUBRESOURCE mappedBuffer = {};
- context->Map(constantBufferVS.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedBuffer);
- memcpy(mappedBuffer.pData, &vsData, sizeof(vsData));
- context->Unmap(constantBufferVS.Get(), 0);
-
- // bind constant buffer
- context->VSSetConstantBuffers(
- 0, // which slot (register) to bind buffer to?
- 1, // how many are we activating? can do multiple at once?
- constantBufferVS.GetAddressOf() // Array of buffers (or address of one)
- );
-
// Background color (Cornflower Blue in this case) for clearing
- const float color[4] = { 0.4f, 0.6f, 0.75f, 0.0f };
+ static const float color[4] = { 0.4f, 0.6f, 0.75f, 0.0f };
// Clear the render target and depth buffer (erases what's on the screen)
// - Do this ONCE PER FRAME
@@ -256,25 +271,41 @@ void Game::Draw(float deltaTime, float totalTime)
1.0f,
0);
-
- // Set the vertex and pixel shaders to use for the next Draw() command
- // - These don't technically need to be set every frame
- // - Once you start applying different shaders to different objects,
- // you'll need to swap the current shaders before each draw
- context->VSSetShader(vertexShader.Get(), 0, 0);
- context->PSSetShader(pixelShader.Get(), 0, 0);
-
-
- // Ensure the pipeline knows how to interpret the data (numbers)
- // from the vertex buffer.
- // - If all of your 3D models use the exact same vertex layout,
- // this could simply be done once in Init()
- // - However, this isn't always the case (but might be for this course)
- context->IASetInputLayout(inputLayout.Get());
-
- for (int i = 0; i < shapes.size(); ++i)
+ for (auto entity : entities)
{
- shapes[i]->Draw();
+ // create constant buffer
+ VertexShaderExternalData vsData;
+ vsData.colorTint = XMFLOAT4(1.0f, 0.5f, 0.5f, 1.0f);
+ vsData.world = entity->GetTransform()->GetWorldMatrix();
+
+ // copy constant buffer to resource
+ D3D11_MAPPED_SUBRESOURCE mappedBuffer = {};
+ context->Map(constantBufferVS.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedBuffer);
+ memcpy(mappedBuffer.pData, &vsData, sizeof(vsData));
+ context->Unmap(constantBufferVS.Get(), 0);
+
+ // bind constant buffer
+ context->VSSetConstantBuffers(
+ 0, // which slot (register) to bind buffer to?
+ 1, // how many are we activating? can do multiple at once?
+ constantBufferVS.GetAddressOf() // Array of buffers (or address of one)
+ );
+
+ // Set the vertex and pixel shaders to use for the next Draw() command
+ // - These don't technically need to be set every frame
+ // - Once you start applying different shaders to different objects,
+ // you'll need to swap the current shaders before each draw
+ context->VSSetShader(vertexShader.Get(), 0, 0);
+ context->PSSetShader(pixelShader.Get(), 0, 0);
+
+ // Ensure the pipeline knows how to interpret the data (numbers)
+ // from the vertex buffer.
+ // - If all of your 3D models use the exact same vertex layout,
+ // this could simply be done once in Init()
+ // - However, this isn't always the case (but might be for this course)
+ context->IASetInputLayout(inputLayout.Get());
+
+ entity->GetMesh()->Draw();
}
// Present the back buffer to the user
diff --git a/Game.h b/Game.h
index f18370b..0aa6992 100644
--- a/Game.h
+++ b/Game.h
@@ -2,6 +2,7 @@
#include "DXCore.h"
#include "Mesh.h"
+#include "Entity.h"
#include
#include // Used for ComPtr - a smart pointer for COM objects
#include
@@ -43,6 +44,8 @@ private:
// Temporary A2 shapes
std::vector> shapes;
+ // Temporary A3 entities;
+ std::vector> entities;
Microsoft::WRL::ComPtr constantBufferVS;
};
diff --git a/Transform.cpp b/Transform.cpp
new file mode 100644
index 0000000..c4fc1d0
--- /dev/null
+++ b/Transform.cpp
@@ -0,0 +1,96 @@
+#include "Transform.h"
+
+using namespace DirectX;
+
+Transform::Transform()
+{
+ SetPosition(0, 0, 0);
+ SetRotation(0, 0, 0);
+ SetScale(1, 1, 1);
+
+ XMStoreFloat4x4(&worldMatrix, XMMatrixIdentity());
+ XMStoreFloat4x4(&worldMatrixInverseTranspose, XMMatrixIdentity());
+ worldMatrixChanged = false;
+}
+
+DirectX::XMFLOAT3 Transform::GetPosition() { return position; }
+DirectX::XMFLOAT3 Transform::GetEulerAngles() { return eulerAngles; }
+DirectX::XMFLOAT3 Transform::GetPitchYawRoll() { return eulerAngles; }
+DirectX::XMFLOAT3 Transform::GetScale() { return scale; }
+
+DirectX::XMFLOAT4X4 Transform::GetWorldMatrix()
+{
+ if (worldMatrixChanged)
+ {
+ UpdateWorldMatrix();
+ worldMatrixChanged = false;
+ }
+ return worldMatrix;
+}
+
+DirectX::XMFLOAT4X4 Transform::GetWorldMatrixInverseTranspose()
+{
+ if (worldMatrixChanged)
+ {
+ UpdateWorldMatrix();
+ worldMatrixChanged = false;
+ }
+ return worldMatrixInverseTranspose;
+}
+
+// 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)
+{
+ XMVECTOR newPosition = XMVectorSet(_x, _y, _z, 0);
+ XMStoreFloat3(&position, newPosition);
+ worldMatrixChanged = true;
+}
+
+void Transform::SetRotation(float _pitch, float _yaw, float _roll)
+{
+ XMVECTOR newRotation = XMVectorSet(_pitch, _yaw, _roll, 0);
+ XMStoreFloat3(&eulerAngles, newRotation);
+ worldMatrixChanged = true;
+}
+
+void Transform::SetScale(float _x, float _y, float _z)
+{
+ XMVECTOR newScale = XMVectorSet(_x, _y, _z, 0);
+ XMStoreFloat3(&scale, newScale);
+ worldMatrixChanged = true;
+}
+
+void Transform::TranslateAbsolute(float _x, float _y, float _z)
+{
+ XMVECTOR newPosition = XMLoadFloat3(&position);
+ XMVECTOR offset = XMVectorSet(_x, _y, _z, 0);
+ XMStoreFloat3(&position, newPosition + offset);
+ worldMatrixChanged = true;
+}
+
+void Transform::Rotate(float _pitch, float _yaw, float _roll)
+{
+ XMVECTOR newRotation = XMLoadFloat3(&position);
+ XMVECTOR offset = XMVectorSet(_pitch, _yaw, _roll, 0);
+ XMStoreFloat3(&eulerAngles, newRotation + offset);
+ worldMatrixChanged = true;
+}
+
+void Transform::Scale(float _x, float _y, float _z)
+{
+ XMVECTOR newScale = XMLoadFloat3(&position);
+ XMVECTOR offset = XMVectorSet(_x, _y, _z, 0);
+ XMStoreFloat3(&scale, newScale + offset);
+ worldMatrixChanged = true;
+}
+
+void Transform::UpdateWorldMatrix()
+{
+ XMMATRIX matrixPosition = XMMatrixTranslation(position.x, position.y, position.z);
+ XMMATRIX matrixRotation = XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z);
+ XMMATRIX matrixScale = XMMatrixScaling(scale.x, scale.y, scale.z);
+
+ XMStoreFloat4x4(&worldMatrix, matrixScale * matrixRotation * matrixPosition);
+ XMStoreFloat4x4(&worldMatrixInverseTranspose, XMMatrixInverse(0, XMMatrixTranspose(XMLoadFloat4x4(&worldMatrix))));
+}
diff --git a/Transform.h b/Transform.h
new file mode 100644
index 0000000..fa98c4d
--- /dev/null
+++ b/Transform.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+
+class Transform
+{
+public:
+ Transform();
+
+ DirectX::XMFLOAT3 GetPosition();
+ DirectX::XMFLOAT3 GetEulerAngles();
+ DirectX::XMFLOAT3 GetPitchYawRoll(); // an alternative name for euler angles in case preferred
+ DirectX::XMFLOAT3 GetScale();
+ DirectX::XMFLOAT4X4 GetWorldMatrix();
+ DirectX::XMFLOAT4X4 GetWorldMatrixInverseTranspose();
+
+ 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 Rotate(float _pitch, float _yaw, float _roll);
+ void Scale(float _x, float _y, float _z);
+
+private:
+ DirectX::XMFLOAT3 position;
+ DirectX::XMFLOAT3 eulerAngles;
+ DirectX::XMFLOAT3 scale;
+ DirectX::XMFLOAT4X4 worldMatrix;
+ DirectX::XMFLOAT4X4 worldMatrixInverseTranspose;
+ bool worldMatrixChanged;
+
+ void UpdateWorldMatrix();
+};
diff --git a/VertexShader.hlsl b/VertexShader.hlsl
index 5c13cc8..17d8b36 100644
--- a/VertexShader.hlsl
+++ b/VertexShader.hlsl
@@ -1,7 +1,7 @@
cbuffer ExternalData : register(b0)
{
float4 colorTint;
- float3 offset;
+ matrix world;
}
// Struct representing a single vertex worth of data
@@ -56,7 +56,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 = float4(input.localPosition + offset, 1.0f);
+ output.screenPosition = mul(world, float4(input.localPosition, 1.0f));
// Pass the color through
// - The values will be interpolated per-pixel by the rasterizer