-
Notifications
You must be signed in to change notification settings - Fork 411
Effects
This is a native Direct3D 12 implementation of the five built-in effects from XNA Game Studio 4, providing identical functionality and API:
- BasicEffect supports texture mapping, vertex coloring, directional lighting, and fog
- AlphaTestEffect supports per-pixel alpha testing
- DualTextureEffect supports two layer multi-texturing (for light maps or detail textures)
- EnvironmentMapEffect supports cubic environment mapping
- SkinnedEffect supports skinned animation with up to 72 bones and 1, 2, or 4 bone influences per vertex.
DirectX Tool Kit also includes the following built-in effects:
-
NormalMapEffect which extends
BasicEffect
to support normal maps and optional specular map. - PBREffect which implements a Disney-style (Roughness/Metalness workflow) Physically-Based Renderer effect using image-based lighting.
- DebugEffect which implements debugging shaders such as visualization of normals, tangents, and bi-tangents as well as supporting hemispherical ambient lighting.
DirectX Tool Kit for DirectX 12 does not support the Visual Studio Shader Designer (DGSL) content pipeline (i.e.
DGSLEffect
) that is supported by the DirectX 11 version.
See also EffectFactory, EffectTextureFactory
Related tutorials: Simple rendering, 3D shapes, Rendering a model, Using advanced shaders, Multistream rendering and instancing
#include <Effects.h>
The built-in effect constructors require a Direct3D 12 device, optional effect flags, and state description:
std::unique_ptr<BasicEffect> effect;
RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(),
m_deviceResources->GetDepthBufferFormat());
EffectPipelineStateDescription pd(
&VertexPositionNormalTexture::InputLayout,
CommonStates::Opaque,
CommonStates::DepthDefault,
CommonStates::CullNone,
rtState);
effect = std::make_unique<BasicEffect>(device,
EffectFlags::Lighting,
pd);
For exception safety, it is recommended you make use of the C++ RAII pattern and use a std::unique_ptr
or std::shared_ptr
Effects flags supported for built-in shaders:
EffectFlags::None
-
EffectFlags::Fog
: Enables fogging. -
EffectFlags::Lighting
: Enables lighting which requires a vertex normal in the input layout. -
EffectFlags::PerPixelLighting
: Enables per-pixel lighting which requires a vertex normal in the input layout. -
EffectFlags::VertexColor
: Enables use of a per-vertex color which requires a vertex color in the input layout. -
EffectFlags::Texture
: Enables use of texturing which requires texture coordinates in the input layout. -
EffectFlags::BiasedVertexNormals
: Enables support for compressed vertex normals which require*2 - 1
biasing at runtime.
These are also special-use effect flags used by some of the built-in shaders:
-
EffectFlags::Instancing
: Enable optional GPU instancing feature (See NormalMapEffect, PBREffect, and DebugEffect) -
EffectFlags::Specular
: Enable optional specular/specularMap feature (see EnvironmentMapEffect and NormalMapEffect) -
EffectFlags::Emissive
: Enable optional emissive/emissiveMap feature (see PBREffect) -
EffectFlags::Fresnel
: Enable optional Fresnel feature (see EnvironmentMapEffect) -
EffectFlags::Velocity
: Enable optional velocity feature (see PBREffect)
When you set a texture for an effect, you provide a texture descriptor and a sampler descriptor. Typically you make use of a DescriptorHeap for the texture descriptors and CommonStates for the sampler descriptors.
// Effect had to be created with EffectFlags::Texture
effect->SetTexture(resourceDescriptors->GetGpuHandle(Descriptors::MyTexture),
states->AnisotropicWrap());
effect->SetWorld(world);
effect->SetView(view);
effect->SetProjection(projection);
// Effect had to be created with EffectFlags::Lighting or ::PerPixelLighting
effect->EnableDefaultLighting();
The built-in effects default to a standard lighting and color set
- Matrices are all set to identity
- Ambient, diffuse, and emissive colors default to black
- Fully opaque (alpha set to 1)
- Specular defaults to white with a power of 16
- Default lights are set to white with no specular highlight and a default direction of
[0, -1, 0]
. All lights are disabled by default.
The EnableDefaultLighting method sets up a standard three light setup (key, fill, and back) with some ambient light and some soft specular highlights.
ID3D12DescriptorHeap* heaps[] = { resourceDescriptors->Heap(), states->Heap() };
commandList->SetDescriptorHeaps(static_cast<UINT>(std::size(heaps)), heaps);
effect->Apply(commandList);
commandList->IASetVertexBuffers(...);
commandList->IASetIndexBuffer(...);
commandList->IASetPrimitiveTopology(...);
commandList->OMSetBlendFactor(...);
commandList->OMSetStencilRef(...);
commandList->DrawIndexedInstanced(...);
Effects
Apply
method typically callsSetGraphicsRootSignature
,SetGraphicsRootDescriptorTable
,SetGraphicsRootConstantBufferView
, andSetPipelineState
.
To provide flexibility, setting the proper descriptor heaps to render with via
SetDescriptorHeaps
is left to the caller. You can create as many heaps as you wish in your application, but remember that you can have only a single texture descriptor heap and a single sampler descriptor heap active at a given time.
The built-in effects support a number of different settings, some of which are organized into more 'generic' interfaces.
- IEffect is the basic interface for all effects which sets the Pipeline State Object (PSO) to the command list.
- IEffectMatrices is the interface for setting an effects' world, view, and projection matrices. All the built-in effects support this interface.
-
IEffectLights is the interface for controlling the effects' lighting computations and settings. This is supported by BasicEffect, EnvironmentMapEffect, and SkinningEffect if
EffectFlags::Lighting
orEffectFlags::PerPixelLighting
is provided at creation. -
IEffectFog is the interface to control the effects' fog settings. This is supported by BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect, and SkinnedEffect if
EffectFlags::Fog
is provided at creation. - IEffectSkinning is the interface to control skinned animation settings. This is supported by SkinnedEffect. This includes setting the bone transform matrices, and optimizing the number of bone influences per vertex to process (1, 2, or 4; defaults to 4).
The built-in effects work equally well for both right-handed and left-handed coordinate systems. The one difference is that the fog settings start & end for left-handed coordinate systems need to be negated (i.e. SetFogStart(6)
, SetFogEnd(8)
for right-handed coordinates becomes SetFogStart(-6)
, SetFogEnd(-8)
for left-handed coordinates).
NormalMapEffect, PBREffect, and DebugEffect optionally support GPU instancing. When enabled, the vertex input layout must include a XMFLOAT3X4
(i.e. a column-major transform matrix which supports affine transformations like translation, rotation, and scaling). Typically, these values are pulled from a second Vertex Buffer with GPU instancing enabled--although the effect shaders do not actually care where the additional vertex data comes from so it can be used in other creative ways as well.
For example, this is an input layout for two Vertex Buffer streams: Slot 0 with VertexPositionNormalTexture
data provided per-vertex, and Slot 1 with XMFLOAT3X4
data provided 'per-instance':
static const D3D12_INPUT_ELEMENT_DESC s_InputElements[] =
{
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "InstMatrix", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "InstMatrix", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "InstMatrix", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
};
Because DirectX 12 Pipeline State Objects (PSOs) are immutable, all options must be provided to the effect constructor. Any change to state, input layout, or combination of options that would result in different shader being used requires creating a new effect instance.
Creation is fully asynchronous, so you can instantiate multiple effect instances at the same time on different threads. Each instance only supports drawing from one thread at a time, but you can simultaneously draw on multiple threads if you create a separate effect instance per command list.
Work Submission in Direct3D 12
When Apply
is called on an effect, it will set the states needed to render including the root signature and the Pipeline State Object (PSO).
New built-in effects in XNA Game Studio 4.0
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
- 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