Effects System
Implementation status: At snapshot c1c316b9, the five XNA 4.0 stock effects BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect and SkinnedEffect are implemented natively in C++. They are not translated from XNA's shipped shader bytecode; each is a real reimplementation, with per-renderer shader programs behind it. CNA also exposes a public SpriteEffect class (XNA 4.0 keeps its sprite effect internal to SpriteBatch), but at this snapshot it is inert: its OnApply() returns before setting anything and SpriteBatch never uses it (CNA-BUG-006). CNA additionally ships four always-compiled non-XNA effects — PbrEffect, SkinnedPbrEffect, ShaderEffect and ColorMatrixEffect — and, in the optional CNA_CNAEXT extensions, a few more (see Beyond XNA).
Compiled XNA effects are implemented with a renderer boundary. Effect(GraphicsDevice&, bytes) and the XNB EffectReader work on 11 of the 14 renderer identities (9 implementation families): FNA3D always, and eight more families behind default-OFF CNA_*_COMPILED_EFFECTS build options. A default configure reports GraphicsCapability::CompiledEffects true on FNA3D only. There is still no runtime HLSL, DXBC or MGFX path — .fx source is compiled at build time by cna-content through an external fxc. See Compiled XNA effects.
Source-breaking change since alpha.1: the integer subscript of EffectPassCollection, EffectTechniqueCollection, EffectParameterCollection and EffectAnnotationCollection now returns a pointer (null when out of range, as in XNA) instead of a reference. Write getPassesProperty()[0]->Apply(), not getPassesProperty()[0].Apply(). Range-for over a collection still yields references.
Overview
CNA implements the XNA 4.0 effects model inside the Microsoft::Xna::Framework::Graphics namespace. An effect is a shader program combined with its parameter set and render state. You configure an effect through its typed properties (setWorldProperty(), setTextureProperty(), …), then apply a pass with effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply() (or the CNAEXT shortcut effect->Apply()) before drawing primitives. CNA's C++ spelling of XNA's C# properties is getXProperty() / setXProperty(); there is no CurrentTechnique member and no SetWorld()-style setter.
All stock effects implement one or more effect interfaces (IEffectMatrices, IEffectFog, IEffectLights) so that higher-level drawing code can treat effects polymorphically. Parameters can also be accessed directly through EffectParameter objects exposed on the effect.
CNA has distinct custom-effect paths, summarised in the table below. XNA/FNA Direct3D 9 Effect Framework binaries load through the XNA Effect bytecode constructor or XNB EffectReader on qualified renderers. CNAEXT ShaderEffect accepts renderer-oriented source such as GLSL, WGSL, HLSL or SPIR-V words. Support for one never implies support for the other: the first is gated by GraphicsCapability::CompiledEffects, the second by CustomEffects plus ExecutesShaderEffectSourceEXT().
Four effect paths at a glance
Which path you use decides which renderers can run your code and which capability you should query first.
| Path | API | Input | Query before use | Renderers |
|---|---|---|---|---|
| Stock effects | BasicEffect, AlphaTestEffect, … |
none — built into each renderer | ThreeD (2D-only renderers throw) |
every 3D renderer |
| Compiled XNA effect | Effect(device, bytes), XNB EffectReader |
Effect Framework 9.1 binary (.fxb, XNA 4 wrapper, XNB Effect) |
CompiledEffects |
11 of 14 identities — see below |
Source ShaderEffect |
ShaderEffect(device, vertSrc, fragSrc) (CNAEXT) |
renderer-native text: GLSL, WGSL, HLSL, or SPIR-V words | CustomEffects and ExecutesShaderEffectSourceEXT() |
see Custom ShaderEffect |
| Shader package / CNAEXT extensions | ShaderEffect(device, ShaderPackageEXT), CNA::Graphics::* (needs CNA_CNAEXT=ON) |
multi-language packages selected per live device | SupportsShaderLanguageEXT(language, stage) |
EasyGL, VULKAN, WEBGPU, SDL_GPU (libshaderc builds) |
Stock effects at a glance
Five XNA 4.0 stock effects, each implemented natively in C++ rather than translated from XNA's shipped shader bytecode, plus a public SpriteEffect that XNA keeps internal and that is inert at this snapshot. The set of these six is unchanged since alpha.1 and their public API changed only additively: CNAEXT shadow-receiver state on BasicEffect and SkinnedEffect, and on BasicEffect also XNA's own parameter collection (Texture, DiffuseColor, …), its technique name BasicEffect and getVertexColorEnabledProperty()/setVertexColorEnabledProperty() accessors; the five that draw geometry can also be loaded from XNB through built-in readers that need no compiled-effect capability.
| Effect | Key capability | Implements | Status |
|---|---|---|---|
BasicEffect |
Ambient/diffuse/specular lighting, up to 3 directional lights, per-vertex or per-pixel lighting, texture mapping, vertex colour, fog | IEffectMatrices, IEffectFog, IEffectLights (plus CNAEXT IShadowReceiverEXT) | Implemented |
AlphaTestEffect |
Alpha threshold discard (greater/less/equal/etc.), single texture | IEffectMatrices, IEffectFog | Implemented |
DualTextureEffect |
Blends two textures (two UV sets) with fog | IEffectMatrices, IEffectFog | Implemented |
EnvironmentMapEffect |
Cube-map environment reflection and Fresnel, three directional lights, fog | IEffectMatrices, IEffectFog, IEffectLights | Implemented |
SkinnedEffect |
Skeletal animation via a GPU bone palette (up to 72 bones), 1, 2 or 4 skinning weights, fog | IEffectMatrices, IEffectFog, IEffectLights (plus CNAEXT IShadowReceiverEXT) | Implemented |
SpriteEffect |
2D sprite effect. XNA 4.0 keeps its equivalent internal to SpriteBatch; CNA exposes a public class, and CNA's SpriteBatch does not use it |
none — a plain Effect, not IEffectMatrices |
Class only; applying it sets nothing |
BasicEffect
BasicEffect is the general-purpose 3D effect. It supports per-vertex and per-pixel lighting (setPreferPerPixelLightingProperty(true)) with up to three independent directional lights, a single diffuse texture, per-vertex color, and distance fog. Lighting is controlled via the IEffectLights interface — call EnableDefaultLighting() to activate XNA's standard three-light rig in a single call. Construction takes a GraphicsDevice&; the effect is a real 3D effect, so on a 2D-only renderer drawing with it throws.
// C++23 example
auto effect = std::make_shared<BasicEffect>(graphicsDevice);
effect->setWorldProperty(Matrix::getIdentityProperty());
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
effect->EnableDefaultLighting();
effect->setTextureEnabledProperty(true);
effect->setTextureProperty(myTexture); // Texture2D*
for (auto& pass : effect->getCurrentTechniqueProperty()->getPassesProperty()) {
pass.Apply();
graphicsDevice.DrawIndexedPrimitives(
PrimitiveType::TriangleList,
0, // baseVertex
0, // minVertexIndex
vertexCount, // numVertices
0, // startIndex
indexCount / 3); // primitiveCount
}
AlphaTestEffect
AlphaTestEffect renders a single textured surface and discards fragments whose alpha does not satisfy a configurable comparison against a reference value. Supported comparisons are Always, Never, Equal, NotEqual, Less, LessEqual, Greater, and GreaterEqual. The reference is an integer 0–255 that is normalised by 255 with a half-step threshold, as in XNA/FNA (Greater at reference 127 keeps alpha 128–255). This effect is useful for vegetation, fences, and other cut-out geometry where alpha blending would cause sorting problems.
auto effect = std::make_shared<AlphaTestEffect>(graphicsDevice);
effect->setWorldProperty(transform);
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
effect->setTextureProperty(treeBarkTexture);
effect->setAlphaFunctionProperty(CompareFunction::Greater);
effect->setReferenceAlphaProperty(128); // keep fragments with alpha above about 0.5
effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
DualTextureEffect
DualTextureEffect samples two textures in the same draw call and multiplies them together. A common use case is lightmap baking: the first texture holds the base colour and the second holds a pre-baked lightmap. Like XNA's effect it reads two UV sets — TEXCOORD0 for the first texture and TEXCOORD1 for the second — so the vertex format needs both (XNA refuses a single-UV draw; CNA does not check, and the second texture reads (0, 0) on most renderers but the first set’s coordinates on VULKAN — see CNA-GAP-033). It also doubles the first texture's RGB, exactly as XNA does, so an all-grey (0.5) lightmap is the identity. An unbound texture samples opaque black.
auto effect = std::make_shared<DualTextureEffect>(graphicsDevice);
effect->setWorldProperty(Matrix::getIdentityProperty());
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
effect->setTextureProperty(diffuseTexture);
effect->setTexture2Property(lightmapTexture);
effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
EnvironmentMapEffect
EnvironmentMapEffect adds a cube-map environment reflection on top of a diffuse texture. The amount of reflection versus base colour is controlled by the environment map amount (default 1.0) and an optional Fresnel factor — an exponent (default 1.0, and 0 disables Fresnel) that makes reflections stronger at glancing angles; the Fresnel weight is computed per vertex and clamped, as in D3D9. The effect implements the full IEffectLights interface: up to three directional lights contribute Lambert terms, and the specular contribution is EnvironmentMapSpecular multiplied by the cube map's alpha channel (default zero), not a Phong highlight. Fog is also supported.
auto effect = std::make_shared<EnvironmentMapEffect>(graphicsDevice);
effect->setWorldProperty(sphereTransform);
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
effect->setTextureProperty(diffuseTexture);
effect->setEnvironmentMapProperty(skyboxCube); // TextureCube*
effect->setEnvironmentMapAmountProperty(0.8f);
effect->setFresnelFactorProperty(1.0f);
effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
SkinnedEffect
SkinnedEffect is the standard effect for skeletal (skinned) mesh animation. Bone matrices are uploaded to the GPU as a bone palette of at most SkinnedEffect::MaxBones (72) matrices. Each vertex can reference 1, 2, or 4 bones through the weights-per-vertex property; any other value throws ArgumentOutOfRangeException. The effect also supports the full lighting model (three directional lights) and fog.
auto effect = std::make_shared<SkinnedEffect>(graphicsDevice);
effect->setWorldProperty(Matrix::getIdentityProperty());
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
effect->EnableDefaultLighting();
effect->setWeightsPerVertexProperty(4);
effect->SetBoneTransforms(boneMatrices); // const std::vector<Matrix>&, 1..72 entries
effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
SpriteEffect
SpriteEffect is the 2D sprite effect. XNA 4.0 has no public class of this name (its SpriteBatch keeps the equivalent effect internal); CNA exposes one. In CNA, SpriteBatch never creates or uses it (sprites go through each renderer's own sprite path). Its OnApply() is written to set up an orthographic projection over the viewport, but because the effect has no MatrixTransform parameter it returns at its first statement, so applying it currently sets nothing (see Known Issues). It derives from Effect directly and does not implement IEffectMatrices. Application code does not normally instantiate SpriteEffect directly; it is exposed in the public API for completeness.
Beyond XNA: PbrEffect, SkinnedPbrEffect, ShaderEffect and more
Four effect classes that are always compiled into the library have no XNA 4.0 counterpart. They are tagged CNAEXT in the headers, which means a compile-time purity check can be switched on to make using them an error — useful if your goal is a strictly XNA-compatible codebase.
| Effect | What it adds |
|---|---|
PbrEffect |
Physically based rendering (metallic-roughness with base colour, normal, metallic-roughness, emissive and occlusion maps, plus KHR_materials_specular-style factors) — a lighting model XNA 4.0 predates entirely. Direct glTF loading assigns it to metallic-roughness materials, so dynamic_cast<BasicEffect*> loops skip glTF parts. |
SkinnedPbrEffect |
The same PBR model applied to skinned (skeletally animated) geometry, up to 72 bones. |
ShaderEffect |
Renderer-native shader source through CNAEXT; separate from XNA compiled Effect compatibility. The (device, vertSrc, fragSrc) constructor is always compiled; the ShaderCodeEXT and ShaderPackageEXT constructors need CNA_CNAEXT=ON. |
ColorMatrixEffect |
A CPU RGBA colour matrix for SpriteBatch, executed on the SOFTWARE renderer only. |
PBR support is broad but not universal: DIRECTX9, DIRECTX11, the three EasyGL identities, SDL_GPU, VULKAN, WEBGPU and METAL (9 identities, seven implementation families) implement the full model, both KHR_materials_specular maps and vertex-colour PBR included; SOFTWARE draws a reduced CPU cross-check (base colour multiplied by diffuse); FNA3D refuses PBR draws by name. Shadow sampling and image-based lighting (IShadowReceiverEXT, setImageBasedLightEXT) are honoured only by the three EasyGL identities, VULKAN, SDL_GPU and WEBGPU; elsewhere the state is accepted and ignored (an unshadowed image, no error). The shadow map and the environment textures are rendered by the application; see Tutorial 114 and Tutorial 59.
CNAEXT effects (CNA_CNAEXT=ON)
The optional CNAEXT extensions (modules/graphics-ext, 11 public headers) add a few effect-shaped classes. They are off by default and built by no CI workflow; see CNAEXT extensions.
| Class | What it is |
|---|---|
CRTEffect, DepthEffect | Derive from ShaderEffect; a screen-space CRT look, and colour-depth or palette reduction with optional ordered dithering. |
AsciiPostProcessEffect | Not an Effect: a portable CPU implementation that reads the source texture back and redraws it through SpriteBatch. |
Compiled XNA effects
Effect(GraphicsDevice&, bytecode) accepts the XNA/FNA Direct3D 9 Effect Framework binary format (commonly stored as .fxb), including the wrapper emitted by the XNA 4 compiler. The real XNB EffectReader reads the same payload through ContentManager, preserves the asset name and wraps every failure — including the “this renderer cannot do it” case — in ContentLoadException. The direct and XNB routes produce the same reflected effect graph. This is a real implementation, not a stub: on a capable renderer the constructor builds and reflects the full graph.
| Input | Status at this snapshot |
|---|---|
XNA/FNA D3D9 Effect Framework binary (.fxb) | Accepted on capable builds |
| Compiled Effect payload inside an XNB | Accepted through EffectReader |
HLSL .fx source at run time | Not accepted; CNA embeds no HLSL compiler |
HLSL .fx source at build time | Compiled by cna-content through an external legacy fxc |
.fxb imported by cna-content | No compiler needed |
MonoGame MGFX / .mgfxo | Different container; rejected explicitly |
| DXBC or arbitrary GLSL/SPIR-V/Metal source | Not guessed as Effect Framework bytecode; use the toolchain/API that owns that format |
The loader enforces a 64 MiB payload limit and validates structure before constructing renderer resources. It reflects techniques, passes, parameters, annotations, arrays and structures; parameter values and textures can be set, pass render/sampler state is applied, cloning preserves runtime state, and compiled effects can participate in SpriteBatch and 3D draws.
What throws, and when
Malformed input is judged before the renderer is consulted, so the same bytes give the same ArgumentException on every renderer; only a structurally valid binary on an incapable renderer reaches the capability check.
| Condition | Exception |
|---|---|
| Empty byte array, more than 64 MiB, or no structurally valid Effect Framework header | System::ArgumentException |
First four bytes are MGFX | System::NotSupportedException |
Valid binary, but CompiledEffects is false on the active renderer | System::NotSupportedException |
| Renderer advertised the capability but failed to create the runtime | System::NotSupportedException |
| Shader-translation or render-state failures inside the runtime (for example an unrepresentable sampler addressing mode) | std::runtime_error |
Any of the above while loading through XNB EffectReader | ContentLoadException wrapping the original |
Renderer support is opt-in and queryable
Compiled-effect support is 11 of the 14 identities in 9 implementation families. FNA3D has it always; every other option defaults to OFF because it pulls the pinned FNA3D/MojoShader translation machinery into a renderer that does not otherwise need it. Enabling an option for one family is not a universal capability promise: each option lives in the renderer's own configure branch, and a default configure reports CompiledEffects true on FNA3D only (13 of 14 identities false).
| Renderer family | Build requirement |
|---|---|
FNA3D | Always on: supported in the normal FNA3D build through FNA3D/MojoShader. |
EasyGL identities (OPENGLES3, OPENGL33, WEBGL2) | -DCNA_EASYGL_COMPILED_EFFECTS=ON (default OFF); one option enables all three identities. On macOS’s OpenGL 4.1 core context the effects are translated through MojoShader’s GLSL ES 3.00 route, chosen by a probe compile. |
SDL_GPU | -DCNA_SDL_GPU_COMPILED_EFFECTS=ON (default OFF). |
VULKAN | -DCNA_VULKAN_COMPILED_EFFECTS=ON (default OFF). |
WEBGPU | -DCNA_WEBGPU_COMPILED_EFFECTS=ON (default OFF); buildable on every target, including Emscripten, where CNA translates the SPIR-V output to WGSL. |
DIRECTX9, DIRECTX11 | -DCNA_DIRECTX9_COMPILED_EFFECTS=ON, -DCNA_DIRECTX11_COMPILED_EFFECTS=ON (default OFF; Windows builds). |
SOFTWARE | -DCNA_SOFTWARE_COMPILED_EFFECTS=ON (default OFF): a CPU shader interpreter; needs Python 3 at build time. |
METAL | -DCNA_METAL_COMPILED_EFFECTS=ON (default OFF): MojoShader’s SPIR-V output translated to MSL in process by SPIRV-Cross (both fetched at configure time), for 3D draws and SpriteBatch. Measured on a physical Mac mini M4: 43 Metal tests and 1,237 effect and SpriteBatch tests under Metal’s validation layers. |
HEADLESS, STUB and the 2D-only SDL_RENDERER | Unsupported; the capability reports false and construction throws NotSupportedException. |
if (!device.SupportsCapability(CNA::GraphicsCapability::CompiledEffects)) {
// Choose a stock effect or another renderer/build configuration.
}
auto effect = getContentProperty().Load<std::shared_ptr<Effect>>("Effects/Bloom");
effect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
The finer-grained query is RendererFeature::CompiledXnaEffects in the RendererCapabilityProfile returned by GraphicsDevice::GetRendererCapabilityProfileEXT().
Producing a compiled effect at build time
XNA samples ship .fx source; what CNA loads is the compiled container the XNA content build produced. CNA's cna-content tool (built with the library) covers both routes: a .fxb is imported as-is, and a .fx is compiled by an external, legacy fxc at profile fx_2_0 and written as an Effect .xnb. CNA does not vendor or embed a compiler. The .fx route needs --format xnb (a .cnb cannot carry an Effect), and it has not been checked against a genuine Microsoft fxc — CNA's own documentation says so. The full walkthrough is Tutorial 150.
cna-content build Content -o build/Content --format xnb \
--fx-compiler /path/to/fxc.exe --fx-compiler-launcher wine
Do not call this universal .fx support. CNA loads already-compiled Effect Framework bytecode on 11 of 14 renderer identities. At run time it still does not compile .fx source or parse MGFX, and even at build time the .fx route depends on an external legacy compiler you supply.
Renderer coverage
Effect support is a property of the active renderer and its build options. CNA exposes 14 renderer identities over 12 implementation families, and coverage differs sharply across them; in a multi-renderer build query the actual device rather than the compile-time default. See Renderers for the full inventory. The table lists which of the XNA stock effects, the CNAEXT PBR pair and a source ShaderEffect each renderer can draw. Shader-program and blob counts are deliberately not published: they change with every shader edit and depend on what is counted.
| Renderer | Effect coverage | Notes |
|---|---|---|
EasyGL (OPENGLES3, OPENGL33, WEBGL2) |
All six stock effects, PBR, ShaderEffect (GLSL) | The most mature renderer family and the reference for effect behaviour; both per-vertex and per-pixel lighting. Shadow and IBL sampling honoured. Compiled effects opt-in. |
VULKAN |
All six stock effects, PBR, ShaderEffect (SPIR-V words) | A source ShaderEffect takes SPIR-V, not GLSL text. Shadow and IBL sampling honoured. Compiled effects opt-in. |
SDL_GPU |
All six stock effects, PBR | Vulkan natively; SDL_gpu’s Direct3D 12 and Metal drivers through SDL_shadercross (CNA_SDL_GPU_SHADERCROSS, default on for Windows and Apple). A source ShaderEffect exists only in builds that found libshaderc (Linux/Android) or with SPIR-V words; an instanced ShaderEffect draw is queued with its instance count, but per-instance vertex streams are not bound to a custom effect. Compiled effects opt-in. |
WEBGPU |
All six stock effects, PBR, ShaderEffect (WGSL) | Runs all stock effects with MRT, occlusion queries and stencil. Shadow and IBL sampling honoured. Compiled effects opt-in. |
DIRECTX9 |
All six stock effects, PBR | Windows-only. The stock effects run XNA's own .fx sources, which is why the oracle corpus (tools/xna-oracle/) diffs this renderer against real XNA 4.0 output; its recorded run, under Wine + DXVK, matches all 39 scenes at tolerance 0. It declares no capability overrides (it inherits the permissive defaults) and no shadow/IBL sampling. Compiled effects opt-in (its native path hands the original D3D9 token streams to the device). |
DIRECTX11 |
All six stock effects, PBR, ShaderEffect (HLSL) | Windows-only. No shadow or IBL sampling, no compute. Compiled effects opt-in. |
FNA3D |
Six stock effects; compiled effects always | Stock effects are FNA's own compiled binaries. PBR draws are refused by name, and CustomEffects is false: FNA3D's only shader entry point takes a compiled Effect Framework binary, so it runs any .fxb but no ShaderEffect source. |
METAL |
Stock effects, full PBR; SpriteBatch MSL effects; compiled effects opt-in | macOS and iOS/iPadOS. A ShaderEffect takes Metal Shading Language and runs only in SpriteBatch (a 3D draw with one throws); compiled XNA effects need -DCNA_METAL_COMPILED_EFFECTS=ON. It cannot be built on Linux; its evidence is a local run on a physical Mac mini M4 (CNA’s full test tree and ctest -L Metal 261/261 under Metal’s validation layers). |
SOFTWARE |
Stock effects, reduced PBR | CPU rasteriser. A ShaderEffect is accepted but its source is never executed (CustomEffects false). ColorMatrixEffect runs here. Compiled effects opt-in (CPU interpreter). |
HEADLESS, STUB |
No pixels | HEADLESS validates and traces draws and accepts a ShaderEffect without executing it; STUB turns every 3D call into a silent no-op. |
SDL_RENDERER |
2D only | 2D-only by design: no programmable 3D effect pipeline, and 3D calls throw (the default Unsupported3DGraphicsCallBehavior::Throw; WarnAndStub is opt-in). SpriteBatch works. |
How SupportsCapability() answers. GraphicsCapability has 19 members. GraphicsDevice derives CompiledEffects, both float-render-target entries, HalfFloatTextureLinearFiltering, ComputeShaders and IndirectDraw from dedicated renderer hooks whose default is false, and combines MultipleRenderTargets with the graphics-profile limit (the default Reach profile allows one render target). Only the remaining members fall through to the renderer's own switch, whose shared default is true; of the 14 identities only DIRECTX9 inherits that permissive default wholesale. The detailed, per-feature report is GraphicsDevice::GetRendererCapabilityProfileEXT() (32 features, 22 limits; Tutorial 133).
Effect interfaces
IEffectMatrices
Implemented by every stock 3D effect, by PbrEffect/SkinnedPbrEffect and by ShaderEffect. (SpriteEffect is a plain Effect and does not implement it.) Provides the three standard transformation matrices used to project geometry from object space to clip space. Each is a getXProperty() / setXProperty(const Matrix&) pair.
| Property | Type | Description |
|---|---|---|
World (getWorldProperty(), setWorldProperty()) | Matrix | Object-to-world transform (model matrix) |
View (getViewProperty(), setViewProperty()) | Matrix | World-to-camera transform |
Projection (getProjectionProperty(), setProjectionProperty()) | Matrix | Camera-to-clip transform (perspective or orthographic) |
IEffectFog
Implemented by all stock effects that render geometry in world space. Fog is computed per vertex from view-space depth (matching XNA/FNA) and blended linearly between FogStart and FogEnd. Call setFogEnabledProperty(false) to disable the computation entirely.
| Property | Type | Description |
|---|---|---|
FogEnabled (getFogEnabledProperty(), setFogEnabledProperty()) | bool | Enables or disables distance fog |
FogStart (getFogStartProperty(), setFogStartProperty()) | float | Camera distance at which fog begins |
FogEnd (getFogEndProperty(), setFogEndProperty()) | float | Camera distance at which fog is fully opaque |
FogColor (getFogColorProperty(), setFogColorProperty()) | Vector3 | RGB colour of the fog |
A quad receding from the camera with fog enabled: the linear blend between FogStart and FogEnd is interpolated across the surface. This is genuine Microsoft XNA 4.0 runtime output from CNA's oracle corpus (tools/xna-oracle/), which CNA's DIRECTX9 renderer is diffed against at --tolerance 0 (captured under Wine + DXVK on Linux). See Verification.
IEffectLights
Implemented by BasicEffect, EnvironmentMapEffect, SkinnedEffect, PbrEffect and SkinnedPbrEffect. Exposes an ambient light and three independent directional lights. Call EnableDefaultLighting() to configure XNA's standard three-light rig in one call.
| Member | Type | Description |
|---|---|---|
AmbientLightColor (getAmbientLightColorProperty(), setAmbientLightColorProperty()) | Vector3 | RGB colour of the scene ambient light |
DirectionalLight0 (getDirectionalLight0Property()) | DirectionalLight& | First directional light |
DirectionalLight1 (getDirectionalLight1Property()) | DirectionalLight& | Second directional light |
DirectionalLight2 (getDirectionalLight2Property()) | DirectionalLight& | Third directional light |
LightingEnabled (getLightingEnabledProperty(), setLightingEnabledProperty()) | bool | Turns the lighting model on or off |
EnableDefaultLighting() | void | Configures a standard three-light rig |
Each DirectionalLight exposes accessor pairs for:
Direction(getDirectionProperty()/setDirectionProperty()) —Vector3, the direction the light travels (XNA's convention; the default key light points along(-0.53, -0.57, -0.63))DiffuseColor—Vector3RGB diffuse contributionSpecularColor—Vector3RGB specular contributionEnabled—boolenables or disables this light
EffectParameter
All effect parameters are accessible through the collection returned by effect->getParametersProperty() as EffectParameter objects. Look one up by name with getParametersProperty()["Name"], which returns an EffectParameter* (null when absent); the integer subscript also returns a pointer (null when out of range). There is no template GetValue<T>(): reads use typed getters and writes use the overloaded SetValue(), mirroring XNA 4.0.
Supported types for GetValueXxx / SetValue:
bool,int,float,std::string— scalar values (on a compiled effect's parameter,SetValue(std::string)throwsInvalidCastExceptionunless the parameter is a string; on other parameters it simply stores the string)Vector2,Vector3,Vector4,Quaternion— float vectorsMatrix— 4×4 matrix (GetValueMatrix(),SetValue(const Matrix&), plus theTransposevariants)std::vector<T>of each of the above — arrays (GetValueMatrixArray(count), used for example by a bone palette)Texture2D*,Texture3D*,TextureCube*— sampler bindings
// Look up a parameter by name and set it directly
EffectParameter* param = effect->getParametersProperty()["DiffuseColor"];
if (param != nullptr)
param->SetValue(Vector4(1.0f, 0.5f, 0.0f, 1.0f));
// Read back a matrix
Matrix world = effect->getParametersProperty()["World"]->GetValueMatrix();
Prefer the typed properties on stock effects (e.g. effect->setWorldProperty(...)) over raw EffectParameter access. On stock effects the parameters are mostly outputs: the effect writes them from its own property fields when it is applied, so a manual SetValue on a stock parameter such as DiffuseColor may be overwritten or unused. EffectParameter is the real interface for compiled effects, whose parameters are genuine reflected storage (parameters, array elements, struct members, annotations) uploaded at EffectPass::Apply() when dirty.
Custom ShaderEffect
When the stock effects do not meet your needs, ShaderEffect lets you supply your own shader source. Its constructor takes three arguments — the device and the two shader sources as source text, not paths. Note that ShaderEffect is a CNA extension, not part of XNA 4.0 — it is tagged CNAEXT. The constructor does not throw on a compile failure: check IsEffectValid(), and read GetCompileErrorEXT() or GetShaderDiagnosticsEXT() for the reason.
CNAEXT ShaderEffect(GraphicsDevice& device,
const std::string& vertSrc,
const std::string& fragSrc);
Renderer requirement: the source dialect depends on the renderer. It is desktop GLSL on OPENGL33, GLSL ES 3.00 on OPENGLES3 and WEBGL2, SPIR-V words on VULKAN and SDL_GPU, WGSL on WEBGPU, HLSL on DIRECTX9/11, and Metal Shading Language on METAL (SpriteBatch effects only). FNA3D and SOFTWARE report CustomEffects false; HEADLESS accepts and ignores the source; SDL_GPU reports it only in builds with libshaderc. The 2D-only SDL_RENDERER cannot run a custom ShaderEffect at all. The full matrix, and how to ask the live device, is on Shader Effects.
Alternatively, a .cnj Effect descriptor lets ContentManager read the sources for you. It has exactly two shader fields, vertex and fragment, each naming a shader source file relative to the content root (not to the descriptor's own folder); missing either raises a ContentLoadException. (The same reader also accepts BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect and SkinnedEffect descriptors.)
{
"cnjVersion": 1,
"type": "Effect",
"vertex": "effects/my_effect.vert",
"fragment": "effects/my_effect.frag"
}
Load it as Effect — that, not ShaderEffect, is the type the reader is registered for — then downcast. Uniforms are set by name through the SetUniformXxx family; there is no Parameters collection on ShaderEffect.
auto fxBase = getContentProperty().Load<std::shared_ptr<Effect>>("effects/my_effect");
auto* myEffect = dynamic_cast<ShaderEffect*>(fxBase.get());
// Applying first is the portable habit. (On the GL renderers each setter also
// makes its own program current, but do not rely on that on other renderers.)
myEffect->getCurrentTechniqueProperty()->getPassesProperty()[0]->Apply();
float wvpColumnMajor[16];
wvp.ToColumnMajor(wvpColumnMajor);
myEffect->SetUniformMat4("WorldViewProj", wvpColumnMajor);
myEffect->SetUniformVec4("Tint", 1.0f, 0.8f, 0.6f, 1.0f);
graphicsDevice.DrawPrimitives(PrimitiveType::TriangleList, 0, triangleCount);
For the Vulkan renderer, the source a source-string constructor takes is SPIR-V words rather than GLSL text (a .cnj descriptor names the pre-compiled .spv files). A ShaderEffect's scalar uniforms on Vulkan live in a fixed 128-byte push-constant block, and DeclareUniformBlockEXT() describes std140 uniform blocks.
See ShaderEffect and Tutorial 52: Writing Custom Shaders for the full treatment, and Tutorial 128 for the compiled-effect path.
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- Compiled XNA effects: admission, reflection, passes and renderer runtimes — What happens to Direct3D 9 Effect Framework bytecode in CNA: admission order and preflight bounds, the reflected object graph, parameter upload, pass-state publication, cloning, the XNB EffectReader and per-renderer translation.
- Effect object model: techniques, passes, parameters and the draw packet — What a CNA Effect contains in its stock, compiled and ShaderEffect forms: collections, pass application, Clone and Dispose, stock parameter tables versus XNA, EffectParameter storage and GpuDrawParams.
- Four shader routes: stock semantics, D3D9 stock sources, compiled effects and ShaderEffect — How CNA answers XNA's .fx: renderer-owned stock effects, DIRECTX9's recompiled Microsoft sources, compiled Effect Framework bytecode on qualified renderers, and the renderer-specific ShaderEffect contract.
- The XNA stock effects: exact semantics, worked uses and verification history — BasicEffect, AlphaTestEffect, DualTextureEffect, EnvironmentMapEffect and SkinnedEffect in CNA: defaults, formulas, ordering traps, per-vertex versus per-pixel lighting, worked uses and the defect patterns behind the current code.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-BUG-006: SpriteEffect caches a MatrixTransform parameter that never exists, so OnApply() never sets the sprite projection — SpriteEffect looks up a MatrixTransform parameter its base Effect never creates, so Parameters["MatrixTransform"] is null and OnApply() returns before computing the orthographic projection and half-pixel offset.
- CNA-BUG-261: Comments and docs say GpuDrawParams::specularEnabled is read by no renderer and DIRECTX9's specular variants are blocked, but D3D9EffectDraw and Fna3dDraw read it — IGraphicsRenderer.hpp says no renderer reads GpuDrawParams::specularEnabled, and two DirectX9 headers and docs/directx9-renderer.md call the specular and per-pixel-lighting variants unreachable, although DIRECTX9 and FNA
- CNA-GAP-033: CNA has no counterpart of XNA's MissingVertexShaderInput draw check, and renderers resolve a stock-effect draw that lacks an input differently — XNA refuses a draw whose vertex declaration lacks a semantic the shader reads; CNA has no device-level check, so EasyGL feeds neutral values, WEBGPU substitutes, SDL_GPU and FNA3D throw NotSupportedException and VULKAN a