Help home · Beginner · Intermediate · Advanced authoring · Command reference · Samples
Automatic VR skips camera post effects unless a format-2/3 layout-4 post manifest declares vr-compatible 1 after its layout and mode. This author assertion requires asymmetric inverse-projection reconstruction, eye-local inputs and histories, and hardware qualification. See Automatic PC VR. The declaration preserves all existing desktop behavior.
This guide describes how to author shader assets and HLSL for Blitz3D. It assumes you already know how to load, parameterise, attach, copy, and deploy a shader. See the intermediate guide if those workflows are new.
The recommended progression is surface mode, then post mode, and finally raw mode only when the generated surface pipeline cannot express the effect.
For format-3/layout-4 light-cookies 1 opt-in and per-light surface/raw/fog
sampling, see Light cookies. Old custom shaders retain
their rendering until explicitly opted in and recompiled.
For independent shadows from several lights, see Multiple-light shadows. The versioned extension preserves existing shader layouts and the primary legacy shadow map.
A source-backed asset consists of a .b3shader descriptor and an
HLSL source file. This minimal material declares two public parameters:
blitz3d_shader 1 layout 3 mode surface name "Orange material" source "orange.hlsl" vertex_entry "VSMain" pixel_entry "PSMain" shadow_entry "ShadowVSMain" shadows classic color "Tint" 255 130 30 255 float "Shine" 0.35
The first line is asset format 1. layout 3 selects the immutable
legacy binding layout. Format 2 and layout 4 add pass graphs and named resources
without changing layout-3 bytecode. mode is surface,
post, or raw. Paths are relative to the descriptor.
A precompiled descriptor uses vertex, pixel, and,
when needed, shadow CSO paths in place of source and
entry-point directives. Normally b3dshaderc produces that compiled
form; do not maintain it by hand.
Value declarations are assigned constant slots in declaration order. Layout 3 has sixteen value slots and eight texture stages. Layout 4 keeps those bindings and adds a sixteen-entry named texture/sampler table for material and post inputs.
| Descriptor | Blitz setter | HLSL access |
|---|---|---|
float "Roughness" .5 | ShaderFloat shader,"Roughness",.8 | B3DUserFloat(0) |
int "Mode" 0 | ShaderInt shader,"Mode",1 | B3DUserInt(1) |
vector "Wind" 1 0 0 0 | ShaderVector shader,"Wind",1,0,.2,0 | B3DUserVector(2) |
color "Tint" 255 255 255 255 | ShaderColor shader,"Tint",80,160,255 | B3DUserVector(3), converted to 0..1 |
texture "NormalMap" 1 | ShaderTexture shader,"NormalMap",map | texture1 and sampler1 |
A float or integer consumes a complete slot, just like a vector or colour. Do not infer slots from parameter names: count only non-texture declarations from zero. Names form the BlitzBasic interface; slots form the HLSL interface.
A surface shader can tell editors how to present it. The World Editor's
Material tab reads these lines to name the shader in its gallery of looks and to
give each parameter a labelled slider, colour swatch or choice. Hints never
change what the shader receives, and ShaderFloat and the other
setters ignore them.
title "Toon" description "Flat bands of light and shade, like a cartoon." category "Surfaces" material-color used float "Bands" 4 ui "Bands" label "Bands" range 1 8 step 1 tip "How many steps of light and shade." int "LightingMode" 1 ui "LightingMode" label "Lighting" choices "Classic brightness|Per light, keeps colours" texture "Texture" 0 ui "Texture" label "Colour map" role base
title, description and category each
take quoted text; the World Editor groups looks under Surfaces, Nature and
weather, or Effects. material-color used says the shader multiplies
the material's own colour, so the editor offers it; ignored says it
does not. A ui line follows the parameter it describes and holds any
of these keys:
| Key | Meaning |
|---|---|
label "text" | The control's caption. Without one, the editor splits the name at its capitals. |
range min max | The slider's range for a float or int. Typed values may go beyond it. |
step n | The slider's step; 1 moves in whole numbers. |
group "text" | A heading the setting appears under. |
advanced | The group starts closed. Needs group. |
tip "text" | One line shown when the pointer rests on the control. |
choices "a|b|c" | Names for an int's values 0, 1, 2 and so on. |
direction | A vector edited as a direction and kept at length 1. |
alpha coverage | A colour's alpha is opacity, with a slider of its own. |
role base, color, normal or data | What a texture holds. The editor moves a material's colour map to the base texture, and its normal map to the normal one, when the shader is chosen. |
hidden | Not shown, for values the engine or program sets. |
A ui line must name a parameter declared above it, once, with
keys that suit its type; a mistake is a load error with its line number. Text
cannot contain a semicolon, which starts a comment. Programs read the hints with
ShaderInfo and
MaterialShaderSchema.
Builds before these lines existed reject them as unknown directives.
Surface mode lets the engine generate transforms, GPU skinning, instancing, lighting, fog, vertex-colour handling, shadow receiving, and the standard vertex and pixel entry points. Your HLSL supplies one callback:
#include "blitz3d_surface.hlsli"
B3DSurface B3DShadeSurface(B3DSurfaceInput input)
{
B3DSurface surface = B3DDefaultSurface();
surface.color = B3DUserVector(0).rgb;
surface.alpha = B3DUserVector(0).a;
surface.normal = input.worldNormal;
surface.shininess = saturate(B3DUserFloat(1));
return surface;
}
Start with B3DDefaultSurface() so brush colour, alpha, and
shininess keep their traditional meaning, then replace only the fields your
effect owns.
B3DSurface field | Meaning |
|---|---|
color, alpha | Linear base colour and opacity. |
normal | World-space shading normal; zero uses the interpolated mesh normal. |
shininess | Classic specular amount and exponent control. |
emission | Unlit linear RGB added to the result. |
metallic, roughness, occlusion | PBR material values used when pbr is non-zero. |
alphaCutoff | Threshold used by masked drawing. |
indirect | Additional indirect linear RGB for PBR lighting. |
pbr | Non-zero selects the PBR lighting branch. |
B3DSurfaceInput supplies uv0, uv1,
vertexColor, worldPosition, worldNormal,
worldTangent, and viewPosition. Use
B3DSurfaceTextureUV(input,stage) when sampling so Blitz texture
coordinate selection and transforms are respected:
float4 texel = texture0.Sample(
sampler0, B3DSurfaceTextureUV(input,0));
surface.color *= texel.rgb;
surface.alpha *= texel.a;
For displacement, include the base layout first, write a function accepting
VertexInput, and define B3D_DISPLACE_POSITION before
including the surface wrapper:
#include "blitz3d_shader.hlsli"
float3 WavePosition(VertexInput input)
{
float wave = sin(input.position.x * 3.0f + B3DUserFloat(0));
return input.position + float3(0.0f,wave * B3DUserFloat(1),0.0f);
}
#define B3D_DISPLACE_POSITION(input) WavePosition(input)
#include "blitz3d_surface.hlsli"
The generated visible and shadow entry points then use the same object-space position. The Vertex Waves sample contains the complete callback and descriptor.
| Policy | Use it when... |
|---|---|
shadows classic | The shader does not move vertices and the standard caster shape is correct. |
shadows custom | Displacement or custom geometry must be repeated in the shadow pass. |
shadows disabled | The effect should not cast shadows, as with transparent effects and all post shaders. |
A source-backed surface shader normally uses the wrapper's
ShadowVSMain. Keep the visible and shadow displacement logic shared
to prevent shadows from separating from geometry.
Post mode includes blitz3d_post.hlsli and implements one
function:
#include "blitz3d_post.hlsli"
float4 B3DPostProcess(B3DPostInput input)
{
float grey = dot(input.sceneColor.rgb,
float3(.299f,.587f,.114f));
float amount = saturate(B3DUserFloat(0));
return float4(lerp(input.sceneColor.rgb,grey.xxx,amount),
input.sceneColor.a);
}
B3DPostInput contains sceneColor,
sceneDepth, uv, screenSize, elapsed
time, deltaTime, frameNumber,
cameraPosition, near and far planes, and the camera viewport. Scene
colour is texture stage 0 and depth is stage 1 if direct sampling is needed.
The wrapper supplies the full-screen vertex and pixel entries, confines output
to the viewport, and preserves the input image outside it. Declare
shadows disabled for post assets.
Raw mode uses your VSMain and PSMain directly.
Include blitz3d_shader.hlsli for the exact engine structures,
resources, flags, and helpers. Raw mode is appropriate for a rendering model
which cannot fit B3DSurface; it also means taking responsibility for
transforms, lighting, fog, colour, texture sampling, and output yourself.
VertexInput supplies position, normal, colour, two UV sets,
tangent, instance ID, and vertex ID. Matrices are row-major and positions use
Blitz3D's row-vector convention:
float4 world = mul(float4(input.position,1.0f),worldMatrix); float4 view = mul(world,viewMatrix); output.position = mul(view,projectionMatrix);
B3DTransformPosition is the convenient object-to-clip helper.
Raw shaders currently take the conservative one-instance draw path because
their vertex transforms are entirely user-defined. Surface shaders use the
instance-aware generated wrapper automatically.
| Register | Contents |
|---|---|
b0 | Pixel and draw flags plus classic texture-stage state. |
b1 | World, view, projection, material, fog, draw and instance data, texture transforms, eight lights, and six shadow views. |
b2 | Sixteen uint4 user slots, read with B3DUserFloat, B3DUserInt, and B3DUserVector. |
t0..t7 / s0..s7 | Classic and named textures with matching samplers. |
t8 / s8 | Engine shadow-map array and comparison sampler. |
t9 | Instance world-matrix buffer. |
t10..t12 | Skin vertices, bone palette, and per-instance palette ranges. |
Layout 4 retains the legacy table and adds frame/pass scene inputs, named
textures at t16..t31 / s16..s31, auxiliary MRT output contracts,
previous transforms/bone palettes, and inverse/jitter matrices. Include
blitz3d_surface_v4.hlsli or blitz3d_post_v4.hlsli through
the normal wrapper rather than copying structures. The runtime selects separate
root signatures for layouts 3 and 4; deployed layout-3 assets remain supported.
blitz3d_shader 2 layout 4 mode post stage scene-linear requires scene-color scene-depth scene-normals blue-noise target "ao" scale 0.5 format r8-unorm pass "evaluate" pixel "ao_ps.cso" input "scene-depth" output "ao" clear pass "composite" pixel "composite_ps.cso" input "scene-color" input "ao" output "scene-output" clear
Targets and passes are ordered and acyclic. A pass can read engine inputs,
custom texture:Name bindings, or earlier targets. Supported formats
are bounded colour/depth-friendly RT formats; scale must be positive and no
larger than the documented parser limit. The compiler rejects duplicate names,
forward references, cycles, read/write aliasing, compute passes, incompatible
stages/requirements, excessive parameters/textures/targets/passes, and layout
reflection mismatches before atomically replacing the prior package.
Post scene inputs include colour, resolved depth, normal/roughness, velocity, object mask, deterministic blue noise, history, opaque colour where appropriate, and up to sixteen named textures. Reconstruction helpers use the unjittered inverse projection/view matrices and explicit render/output sizes. Surface manifests may request opaque colour or read-only scene depth and may override blend, depth-write, cull, and shadow policy; removing the shader restores stored entity/brush state.
The IDE compiles literal source-backed shader references during Check and Run. For a direct build, use:
b3dshaderc fx\orange.b3shader b3dshaderc fx\orange.b3shader --force b3dshaderc fx\orange.b3shader --package-dir package\fx
The compiler invokes DirectX Shader Compiler for Shader Model 6, writes a compiled descriptor and CSO stages, and can copy the runtime package to a target directory. It searches the source directory and the bundled Blitz3D include directory for includes.
Do not edit generated .compiled descriptors or CSO files. Keep
source descriptors, HLSL, and project-specific includes under source control;
regenerate the compiled results. Runtime packages need the compiled descriptor,
its referenced bytecode, textures, and other runtime dependencies while
preserving relative paths.
B3DDefaultSurface() and override only the fields the effect owns.B3DSurfaceTextureUV when surface sampling should honour Blitz texture state.The shader sample gallery
contains editable surface tint, displacement, raw rim-light, and post-effect
sources. The builtin_sources folder beside those samples contains
the reviewed source versions of packaged built-ins; loading a
builtin: alias still uses packaged bytecode.
Shader asset formats 1/2 · binding layouts 3/4 · Shader Model 6 · Extended mode