-
Notifications
You must be signed in to change notification settings - Fork 409
3D shapes
This lesson draws simple shapes in 3D.
First create a new project using the instructions from the first two lessons: The basic game loop and Adding the DirectX Tool Kit which we will use for this lesson.
In the previous lesson, we generated geometry with code using PrimitiveBatch to draw simple shapes. Here we make use of GeometricPrimitive which procedurally generates shapes like spheres, cubes, etc. These 3D shapes are more efficient to render because they make use of indexed primitives, and because they make use of a static rather than dynamic vertex buffer and index buffer.
In the Game.h file, add the following variables to the bottom of the Game class's private declarations (right after where you added m_graphicsMemory
as part of the setup):
DirectX::SimpleMath::Matrix m_world;
DirectX::SimpleMath::Matrix m_view;
DirectX::SimpleMath::Matrix m_proj;
std::unique_ptr<DirectX::GeometricPrimitive> m_shape;
std::unique_ptr<DirectX::BasicEffect> m_effect;
In Game.cpp, add to the TODO of CreateDevice after where you have created m_graphicsMemory
:
RenderTargetState rtState(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_D32_FLOAT);
EffectPipelineStateDescription pd(
&GeometricPrimitive::VertexType::InputLayout,
CommonStates::Opaque,
CommonStates::DepthDefault,
CommonStates::CullNone,
rtState);
m_effect = std::make_unique<BasicEffect>(m_d3dDevice.Get(), EffectFlags::Lighting, pd);
m_effect->EnableDefaultLighting();
m_shape = GeometricPrimitive::CreateSphere();
m_world = Matrix::Identity;
In Game.cpp, add to the TODO of CreateResources:
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);
In Game.cpp, add to the TODO of OnDeviceLost:
m_shape.reset();
m_effect.reset();
In Game.cpp, add to the TODO of Render:
m_effect->SetMatrices(m_world, m_view, m_proj);
m_effect->Apply(m_commandList.Get());
m_shape->Draw(m_commandList.Get());
In Game.cpp, add to the TODO of Update:
float time = float(timer.GetTotalSeconds());
m_world = Matrix::CreateRotationZ(cosf(time) * 2.f);
Build and run, and you'll see a white lit sphere.
In Game.cpp modify the TODO of CreateDevice:
m_shape = GeometricPrimitive::CreateTorus(m_d3dContext.Get());
Build and run to see a torus instead of a sphere.
You can try out other shapes like a cube, cone, cylinder, dodecahedron, or the classic teapot.
m_shape = GeometricPrimitive::CreateCube(m_d3dContext.Get());
m_shape = GeometricPrimitive::CreateCone(m_d3dContext.Get());
m_shape = GeometricPrimitive::CreateCylinder(m_d3dContext.Get());
m_shape = GeometricPrimitive::CreateDodecahedron(m_d3dContext.Get());
m_shape = GeometricPrimitive::CreateTeapot(m_d3dContext.Get());
Start by saving earth.bmp into your new project's directory, and then from the top menu select Project / Add Existing Item.... Select "earth.bmp" and click "OK".
In the Game.h file, add the following variable to the bottom of the Game class's private declarations:
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_texture;
In Game.cpp, add to the TODO of CreateDevice:
DX::ThrowIfFailed(
CreateWICTextureFromFile(m_d3dDevice.Get(), L"earth.bmp", nullptr,
m_texture.ReleaseAndGetAddressOf()));
In Game.cpp, add to the TODO of OnDeviceLost:
m_texture.Reset();
In Game.cpp modify the TODO of CreateDevice:
m_shape = GeometricPrimitive::CreateSphere(m_d3dContext.Get());
In Game.cpp, modify to the TODO of Render:
m_shape->Draw(m_world, m_view, m_proj, Colors::White, m_texture.Get());
In Game.cpp, modify to the TODO of Update:
float time = float(timer.GetTotalSeconds());
m_world = Matrix::CreateRotationY(time);
Build and you'll see planet earth spinning.
By default the geometric primitive renderer uses a simple BasicEffect with default lighting settings. To get more control over the rendering, you can use your own effect.
In the Game.h file, add the following variables to the bottom of the Game class's private declarations:
std::unique_ptr<DirectX::BasicEffect> m_effect;
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
In Game.cpp modify the TODO of CreateDevice:
m_effect = std::make_unique<BasicEffect>(m_d3dDevice.Get());
m_effect->SetTextureEnabled(true);
m_effect->SetPerPixelLighting(true);
m_effect->SetLightingEnabled(true);
m_effect->SetLightEnabled(0, true);
m_effect->SetLightDiffuseColor(0, Colors::White);
m_effect->SetLightDirection(0, -Vector3::UnitZ);
m_shape = GeometricPrimitive::CreateSphere(m_d3dContext.Get());
m_shape->CreateInputLayout(m_effect.get(),
m_inputLayout.ReleaseAndGetAddressOf());
DX::ThrowIfFailed(
CreateWICTextureFromFile(m_d3dDevice.Get(), L"earth.bmp", nullptr,
m_texture.ReleaseAndGetAddressOf()));
m_effect->SetTexture(m_texture.Get());
m_world = Matrix::Identity;
In Game.cpp, add to the TODO of CreateResources:
m_effect->SetView(m_view);
m_effect->SetProjection(m_proj);
In Game.cpp, add to the TODO of OnDeviceLost:
m_effect.reset();
m_inputLayout.Reset();
In Game.cpp, modify to the TODO of Render:
m_effect->SetWorld(m_world);
m_shape->Draw(m_effect.get(), m_inputLayout.Get());
Build and run to see earth with more 'space-like' lighting.
Next lesson: Rendering a model
DirectX Tool Kit docs Effects, GeometricPrimitive
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 [email protected] with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Xbox One
- Xbox Series X|S
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20