-
Notifications
You must be signed in to change notification settings - Fork 512
EffectFactory
DirectXTK | Effects |
---|
This is a helper object primarily used by the Model loader implementations to provide sharing of material instances of Effects and textures. This can be used standalone as well, and allows access to any existing ‘materials’ definitions already created.
It uses a simple case-sensitive string-based (wide-character) map for finding effect and texture instances that have already been created by the factory, which avoid duplication of texture and effect resources in complex models and scenes.
classDiagram
class IEffectFactory{
<<Interface>>
+CreateEffect()
+CreateTexture()
}
class EffectFactory
EffectFactory --> IEffectFactory
class PBREffectFactory
PBREffectFactory --> IEffectFactory
class DGSLEffectFactory
DGSLEffectFactory --> IEffectFactory
#include <Effects.h>
The EffectFactory, DGSLEffectFactory, and PBREffectFactory constructor require a Direct3D 11 device.
std::unique_ptr<EffectFactory> fxFactory;
fxFactory = std::make_unique<EffectFactory>( device );
-or-
std::unique_ptr<DGSLEffectFactory> fxFactory;
fxFactory = std::make_unique<DGSLEffectFactory>( device );
-or-
std::unique_ptr<PBREffectFactory> fxFactory;
fxFactory = std::make_unique<PBREffectFactory>( device );
For exception safety, it is recommended you make use of the C++ RAII pattern and use a std::unique_ptr
or std::shared_ptr
Fill out the EffectInfo
structure, then call CreateEffect to obtain an Effects instance. If the info.name string is provided then any already created effect from the factory that has the same name will be returned as a shared instance rather than a new instance created. If there is a name match, then all the other parameters in the EffectInfo
are ignored.
Otherwise a new effect is created from the provided EffectInfo parameters, and CreateTexture is called automatically if the info.diffuseTexture, info.specularTexture, info.normalTexture , and/or info.emissiveTexture strings are provided. Remember that the use of a texture or info.perVertexColor will result in a varying the input layout requirements for the resulting Effect.
EffectFactory::EffectInfo info;
info.name = L"default";
info.alpha = 1.f;
info.ambientColor = XMFLOAT3( 0.2f, 0.2f, 0.2f);
info.diffuseColor = XMFLOAT3( 0.8f, 0.8f, 0.8f );
auto effect = fxFactory->CreateEffect( info, deviceContext );
The standard factory will create instances of BasicEffect.
- If info.enableSkinning is true, it returns a SkinnedEffect instance.
- If info.enableDualTexture is true, it returns a DualTextureEffect instance.
- If info.enableNormalMaps is true, then it returns a NormalMapEffect instance.
- If info.enableSkinning and info.enableNormalMaps are true, then it returns a SkinnedNormalMapEffect instance.
These are kept in distinct 'sharing' lists since they have different input layout requirements.
NormalMapEffect
orSkinnedNormalMapEffect
are only created if the material defines a normal map texture, info.enableNormalMaps is set, and EnableNormalMapEffect is true (the default).
The DGSLEffectFactory extends the standard EffectFactory with support for the Visual Studio Shader Designer (DGSL) system used by .CMO
files. It creates instances of DGSLEffect or SkinnedDGSLEffect. It also supports sharing the pixel shader instances required for DGSL shaders through the CreatePixelShader method.
DGSLEffectFactory::DGSLEffectInfo info;
info.name = L"default";
info.alpha = 1.f;
info.ambientColor = XMFLOAT3( 0.2f, 0.2f, 0.2f);
info.diffuseColor = XMFLOAT3( 0.8f, 0.8f, 0.8f );
info.pixelShader = L"lambert.dgsl.cso";
auto effect = fxFactory->CreateDGSLEffect( info, deviceContext );
Because Visual Studio Shader Designer (DGSL) .DGSL.CSO
files only support Feature Level 10.0+, the DGSLEffectFactory automatically uses a .CSO
of the same name instead which is assumed to be a manually created fall-back shader compiled for Feature Level 9.x. This is the same technique as is used by the Visual Studio 3D Starter Kit.
You can use the DGSLEffectFactory with
SDKMESH
models as long as they include the required TANGENT Information in their vertex decls. These models do not define DGSL pixel shaders as part of their material definition, so these models will always use the default materials (Unlit, Lambert, or Phong).
The DGSLEffect built-in supports the three default materials for all feature levels without requiring any .CSO
files: Unlit, Lambert, and Phong.
DGSLEffect instances with and without skinning are kept in distinct 'sharing' lists since they have different input layout requirements.
The PBREffectFactory replaces the standard EffectFactory. It creates instances of PBREffect, and is intended for use with the .SDKMESH
version 2 file variant which defines PBR materials. If info.enableSkinning is true, it creates instances of SkinnedPBREffect.
EffectFactory::EffectInfo info;
info.name = L"default";
info.alpha = 1.f;
info.diffuseTexture = L"pbrmaterial_basecolor.png";
// Albedo (RGB) texture & alpha texture channels
info.normalTexture = L"pbrmaterial_normal.png";
// Tangent-space normal map texture
info.specularTexture = L"pbrmaterial_occlusionRoughnessMetallic.png";
// This specular slot is actually the
// Occlusion/Roughness/Metalness (ORM) texture for PBR models
auto effect = fxFactory->CreateEffect( info, deviceContext );
You can also optionally provide an emissive channel texture as info.emissiveTexture = L"pbrmaterial_emissive.png";
Note that the resulting effects still need to have Image-Based-Lighting textures assigned which is typically done as part of rendering.
CreateTexture assumes the name given is the filename of the texture to load. If the name string provided matches an already returned texture from the factory, then the existing shader resource view is returned rather than a new texture instance being created. If the name contains the extension .dds
, then DDSTextureLoader is used to create the texture and return the shader resource view, otherwise it will attempt to use WICTextureLoader. The device context is not used by the DDSTextureLoader, only by the WICTextureLoader or can be null to skip auto-gen of mipmaps.
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> srv;
fxFactory->CreateTexture( L"stone.dds", nullptr, srv.GetAddressOf() );
The CreateTexture and CreatePixelShader methods both assume the name given is the filename. By default, this is a relative path to the current working directory (CWD). To cause the factory to look in a specific directory path, use SetDirectory.
fxFactory->SetDirectory( L".\\Assets" );
It will first look in the current working directory for the file, and then look in the specified path given in
SetDirectory
if set.
The EffectFactory, DGSLEffectFactory, and PBREffectFactory are concrete implementations of the IEffectFactory interface, and provide a default implementation and caching policy. This allows the developer to create their own custom version of the Effect Factory by deriving from IEffectFactory, which can be used with Model loaders. This could be used for alternative caching policies, locating textures in packed archives, substituting special Effects triggered material name, etc.
You can control the sharing cache with two methods that are implemented for all the built-in effect factories.
This method sets the sharing mode which defaults to true. By setting it to false, CreateEffect, CreateTexture, and CreatePixelShader calls will always return a new instance rather than returning a cached instance.
fxFactory->SetSharing( false );
This method clears the sharing cache, which might not release all the instances if they are referenced by other objects.
fxFactory->ReleaseCache();
These methods are specific to EffectFactory and are not part of the
IEffectFactory
interface.
-
EnableNormalMapEffect is used to determine if NormalMapEffect or SkinnedNormalMapEffect is used for models containing normal-map textures. This defaults to true (unless the device has a Direct3D 9.x Feature Level). If set to false, it will use BasicEffect or SkinnedEffect instead for these materials.
-
EnableForceSRGB is used to determine if textures have "force SRGB" set to true for the loaders or not. This defaults to false.
Creation of resources is fully asynchronous, so you can create many effects and textures at the same time. CreateEffect and CreateTexture take an optional immediate device context for use when loading WIC-based textures to make use of auto-generated mipmaps. Since use of a device context is not ‘free threaded’, an internal lock is used to keep multiple instances of the WIC loader from being used at the same time, but the user must still take precautions to ensure other users of the immediate context or Present do not occur while loading WIC textures and setting up auto-gen mipmaps.
Custom implementations of EffectFactory should also take care to be thread-safe.
Note: This is yet another reason we recommend using DDS
textures for all your assets.
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