.wshader file holds a GLSL surface function and the uniforms it wants, and the engine wraps it in its own forward lighting (clustered lights, cascaded and point shadows, skybox reflections, SSAO, fog, the G-buffer outputs) at run time. You write what the surface looks like; the renderer lights it exactly like the built-in material.
- Shader files live in the project’s content folder like any asset (
Game/Shaders/*.wshader); the content browser imports them on sight. - A Material picks a shader in its Shader slot. Every
uniformthe shader declares becomes a parameter of that material, edited in the Material Editor and saved in the.wmat. Several materials can share one shader with different values, like Unreal material instances. - The Shader Editor (double-click a shader tile, or Edit next to a material’s Shader slot) edits the code in place, compiles on Ctrl+Enter, and shows the driver’s errors. Editing the file in an external editor works too: the editor polls
.wshaderfiles every half second and recompiles what changed. Materials update live. The window title shows*while the shader has changes that aren’t in its file: Save (Ctrl+S) compiles and writes it; Save All (Ctrl+Shift+S) writes it too, compiling text typed since the last Compile first; Reload From Disk throws both away and rebuilds the shader from the file. - A shader that fails to build keeps its last good build; a shader that never built renders its materials with the default surface. Meshes never disappear while you fix a typo.
The surface function
surface runs once per fragment. It receives:
and fills:
Always available inside the function:
DefaultSurface(i, o)- the built-in material: samples the Material Editor’s albedo / metallic / roughness / normal / AO / emissive slots and factors intoo. Call it first and adjust, or ignore it and build every output yourself.SampleNormalMap(uv, tbn)- the Material Editor’s normal map through a tangent frame.material.*- the raw slots (material.albedoetc. samplers,material.metallicFactor,material.roughnessFactor,material.emissiveFactor) and thehasNormalMap/hasMetallicMap/ … flags.time- seconds since the application started.camPos,camFront,screenDimensions,zNear,zFar,fogColor,fogDensity,fogStart, and the lighting functions ofshaders/material/pbr_common.glsl(CookTorrance,ShadowCalculation, …) if you want them.
#version 450 core + shaders/material/pbr_common.glsl + your file + shaders/material/pbr_main.glsl; the Shader Editor’s Show composed GLSL shows exactly what the driver compiles. Your file becomes GLSL source string 100, so a driver error 100(12) (NVIDIA) or ERROR: 100:12 (AMD / Intel) is line 12 of your .wshader.
Parameters
A parameter is oneuniform declaration on its own line:
The initializer is the parameter’s default (
vec4(1.0), vec3(0.2, 0.5, 1.0), 2.0, true). Hints: color, range(a, b), hide (keeps it out of the editor). Values are stored in the .wmat by name, so renaming a uniform in the shader resets that parameter, and a parameter a material stored for a uniform the shader no longer declares is kept in the file until the material is saved with that uniform back.
Uniform names must not collide with the engine’s (time, material, camPos, debugMode, the shadow / fog / ssao / environment* uniforms in pbr_common.glsl), and functions must not redefine its helpers (DefaultSurface, EnvironmentSpecularWeight, SpecularOcclusion, SampleEnvironment, …) or constants (PI, MIN_ROUGHNESS); the compiler reports a redefinition if they do. The editor’s view modes (see Editor view modes) add more engine names to avoid: the DEBUG_* constants and the helpers debugHue, debugShade, debugWireColor, debugLitOverlay, clusterTileBorder, clusterSliceLine, lightComplexityColor and lightCoverageColor. A GLSL material shows the view modes like the default one does: the debug views replace its colours before surface() runs, and Lit Wireframe and Cluster Grid draw over it, unlit materials included.
What a GLSL material can’t do (yet)
- No vertex stage. Vertex displacement would have to be mirrored in the depth pre-pass and both shadow passes, which draw with the engine’s vertex shaders. Everything happens in the fragment surface function.
- Opaque only.
alphais accepted and ignored; there is no blending or alpha clip in the forward pass (an alpha-clipped surface would still write its full depth in the pre-pass). - Asset previews (content-browser thumbnails) use the built-in surface, so a shader-driven look shows in the viewport, not on the tile.
- Includes:
#include "file"is resolved relative toengine/WizmRender/shaders, so a.wshadercan pull in a shared file placed there; there is no project-level include path.
Files
Both applications create one
material_shader_library pointed at the shader folder and attach it to the forward renderer (cluster_renderer::attach_material_library) and the asset manager (asset_manager::set_material_shader_library) before the project loads; the forward pass then uploads its per-frame uniforms to every program the library holds.