-
Notifications
You must be signed in to change notification settings - Fork 512
Basic game math
Getting Started for DX11 | Getting Started for DX12 |
---|
This lesson will cover the basics of 3D transformations for graphics.
We've already used a simple camera setup in the 3D shapes lesson.
In the Game class we added variables for the projection matrix and the view matrix:
DirectX::SimpleMath::Matrix m_view;
DirectX::SimpleMath::Matrix m_proj;
In the CreateResources method, we used the backbuffer size to create a simple perspective view:
m_view = Matrix::CreateLookAt(Vector3(2.f, 2.f, 2.f),
Vector3::Zero, Vector3::UnitY);
m_proj = Matrix::CreatePerspectiveFieldOfView(XM_PI / 4.f,
float(backBufferWidth) / float(backBufferHeight), 0.1f, 10.f);
The m_proj
matrix is created as a perspective camera using an field-of-view of PI/4 radians (which is 45 degrees), the aspect ratio of the backbuffer, the near-plane distance of 0.1 and a far-plane distance of 10.
The m_view
matrix Is created as a view looking from the position (2,2,2) looking at the position (0,0,0) with an up vector of (0,1,0).
These two matrices handle transforming objects positioned in world coordinates and transforming them to view coordinates and then to screen coordinates.
The 3D shapes lesson also provides an example of positioning an object.
In the Game class we added a variable for the world matrix for our 3D shape:
DirectX::SimpleMath::Matrix m_world;
We initially set it to the identity in CreateDevice:
m_world = Matrix::Identity
Then in Update we set the matrix to a rotation about the Z-axis based on time:
float time = float(timer.GetTotalSeconds());
m_world = Matrix::CreateRotationZ(cosf(time) * 2.f);
Then later in the lesson we made it into a rotation about the Y-axes based on time:
float time = float(timer.GetTotalSeconds());
m_world = Matrix::CreateRotationY(time);
The m_world
matrix transforms the object's local (also known as model) coordinates into world coordinates.
The power of affine transformation is that you can compose them by multiplying them together. In our 3D shapes lesson, we can modify the Update: to get more interesting motion for the planet earth.
For example if you modified Update as follows
float time = float(timer.GetTotalSeconds());
Vector3 pos = Vector3::Lerp(Vector3::Zero, Vector3::One, cos(time));
m_world = Matrix::CreateRotationY(time) * Matrix::CreateTranslation(pos);
Build and run to see the earth spinning and moving away and towards the camera.
If you flipped the order of the matrix multiply, you'll get much different results:
float time = float(timer.GetTotalSeconds());
Vector3 pos = Vector3::Lerp(Vector3::Zero, Vector3::One, cos(time));
m_world = Matrix::CreateTranslation( pos ) * Matrix::CreateRotationY( time);
Build and run to see the planet earth moving in a more complex pattern.
For performance, the majority of the 3D transformations we use in rendering at computed on the GPU using vertex shaders based on the matrices we provide for world, view, and projection. There are times, however, when we want to compute a transformation on the CPU (such as doing collision detection or visibility culling). To transform a point using our variables above we should first concatenate our matrices into a single matrix that combines the transformations.
Matrix matrix = m_world * m_view * m_proj;
Vector3 point; // Our input from somewhere
Vector3 newPoint = Vector3::Transform( point, matrix );
Note: In our example we are only transforming a single point which means we are doing 3 matrix multiplies and 1 vector-matrix multiply. For a single point it might have been better to do 3 vector-matrix multiplies, but for most usage cases we are likely to transform more than just a single point. Ideally we'd use the array version of Transform to transform many points at once.
We can animate the camera's position as well as the object's. In the 3D shapes lesson, we will change Update as follows:
float time = float(timer.GetTotalSeconds());
m_world = Matrix::CreateRotationY(time);
Vector3 cameraPos = Vector3::Lerp(Vector3(2.f, 2.f, 2.f),
Vector3(2.f, 0.f, 2.f), cos(time));
m_view = Matrix::CreateLookAt(cameraPos, Vector3::Zero, Vector3::UnitY);
m_effect->SetView(m_view);
Build and run to see the camera moving up and down while still looking at the planet earth as the center of focus.
Next lesson: Collision detection
DirectX Tool Kit docs SimpleMath
Radian
Graphical projection
Essential Math for Games Programmers (GDC)
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Windows 8.1
- Xbox One
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20