Skip to content

Simple rendering

Chuck Walbourn edited this page Jan 29, 2020 · 55 revisions

Here we learn how to render a triangle and a grid in 3D.

Setup

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.

Background

In order to do a draw operation with Direct3D 12, we need to provide the following objects and settings:

  • A vertex buffer containing the vertices of the elements to draw.
  • A root signature which defines how the CPU and GPU shader programs share data.
  • A pipeline state object which defines all state, the vertex input layout, and the compiled shader programs.
  • A primitive topology setting that indicates how to interpret the individual vertices (as a point, a line, a triangle, etc.)

For this lesson, the BasicEffect object will provide the root signature and pipeline state object, VertexPositionColor will provide the input layout, and PrimitiveBatch will provide the vertex buffer and primitive topology.

Drawing a triangle

In the Game.h file, add the following variables to the bottom of the Game class's private declarations (right after the m_graphicsMemory variable you already added as part of setup):

std::unique_ptr<DirectX::BasicEffect> m_effect;
std::unique_ptr<DirectX::PrimitiveBatch<DirectX::VertexPositionColor>> m_batch;

In Game.cpp, add to the TODO of CreateDevice after where you have created m_graphicsMemory:

m_batch = std::make_unique<PrimitiveBatch<VertexPositionColor>>(m_d3dDevice.Get());

RenderTargetState rtState(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_D32_FLOAT);

EffectPipelineStateDescription pd(
    &VertexPositionColor::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthDefault,
    CommonStates::CullNone,
    rtState);

m_effect = std::make_unique<BasicEffect>(m_d3dDevice.Get(), EffectFlags::VertexColor, pd);

In Game.cpp, add to the TODO of OnDeviceLost:

m_effect.reset();
m_batch.reset();

In Game.cpp, add to the TODO of Render:

m_effect->Apply(m_commandList.Get());

m_batch->Begin(m_commandList.Get());

VertexPositionColor v1(Vector3(0.f, 0.5f, 0.5f), Colors::Yellow);
VertexPositionColor v2(Vector3(0.5f, -0.5f, 0.5f), Colors::Yellow);
VertexPositionColor v3(Vector3(-0.5f, -0.5f, 0.5f), Colors::Yellow);

m_batch->DrawTriangle(v1, v2, v3);

m_batch->End();

Build and run to see a simple yellow triangle rendered in 2D.

Screenshot of triangle

Pixel vs. normalized coordinates

The image above is drawn using coordinates that are independent of the screen resolution and range from -1 to +1. Resizing the window will result in the same image scaled to the new window. If instead you want to draw using screen pixel coordinates (which match the coordinate system used by SpriteBatch), then:

In Game.cpp, add to the TODO of CreateResources:

Matrix proj = Matrix::CreateScale( 2.f/float(backBufferWidth),
   -2.f/float(backBufferHeight), 1.f)
   * Matrix::CreateTranslation( -1.f, 1.f, 0.f );
m_effect->SetProjection(proj);

The projection matrix can also be created with Matrix::CreateOrthographicOffCenter(0.f, float(backBufferWidth), float(backBufferHeight), 0.f, 0.f, 1.f);

In Game.cpp, modify the TODO of Render:

m_effect->Apply(m_commandList.Get());

m_batch->Begin(m_commandList.Get());

VertexPositionColor v1(Vector3(400.f, 150.f, 0.f), Colors::Yellow);
VertexPositionColor v2(Vector3(600.f, 450.f, 0.f), Colors::Yellow);
VertexPositionColor v3(Vector3(200.f, 450.f, 0.f), Colors::Yellow);

m_batch->DrawTriangle(v1, v2, v3);

m_batch->End();

Build and run to get the same image, but if you resize the window the triangle will not change in the second version.

Technical notes

  • The BasicEffect family of shader classes uses shader code built in to the DirectXTK.lib as static data so there's no need to compile shaders at runtime or to load data files from disk.
  • Internally, both SpriteBatch and PrimitiveBatch make use of a dynamic rather than static vertex buffer object.
  • We are not using textures in our shaders for this lesson, so we don't need to set a descriptor heap.
  • In Direct3D 12, all shader and state choices must be made when the pipeline state object is created. If you want to use different states or a different render target format you need to create a new IEffect instance.

State Objects

The use of CullNone for our rasterizer state above allows triangles and quads--which in Direct3D are just two triangles--to be drawn with arbitrary winding order. If you modify CreateDevice above as follows:

EffectPipelineStateDescription pd(
    &VertexPositionColor::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthDefault,
    CommonStates::CullClockwise,
    rtState);

Then build & run you run you will see nothing drawn because the triangle winding order was specified in clockwise order. If you changed it again to:

EffectPipelineStateDescription pd(
    &VertexPositionColor::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthDefault,
    CommonStates::CullCounterClockwise,
    rtState);

Then build & run you will see the triangle reappear.

For 'closed' objects, you typically use backface culling to speed up rendering which can quickly reject triangles that are not facing the viewer and avoids the need to run the pixel shader for those pixels.

The culling mode does not affect points or lines.

More to explore

  • PrimitiveBatch is ideally suited for drawing debug displays such as visualizing bounding volumes, collision data, etc. For more on this, see DebugDraw.

Drawing with textures

UNDER CONSTRUCTION

Next lesson: Line drawing and anti-aliasing

Further reading

DirectX Tool Kit docs CommonStates, Effects, EffectPipelineStateDescription, PrimitiveBatch, RenderTargetState, VertexTypes

For Use

  • Universal Windows Platform apps
  • Windows desktop apps
  • Windows 11
  • Windows 10
  • Xbox One
  • Xbox Series X|S

Architecture

  • x86
  • x64
  • ARM64

For Development

  • Visual Studio 2022
  • Visual Studio 2019 (16.11)
  • clang/LLVM v12 - v18
  • MinGW 12.2, 13.2
  • CMake 3.20

Related Projects

DirectX Tool Kit for DirectX 11

DirectXMesh

DirectXTex

DirectXMath

Tools

Test Suite

Model Viewer

Content Exporter

DxCapsViewer

See also

DirectX Landing Page

Clone this wiki locally