Repository navigation
Shader Graph
SparkEngine includes a node-based shader graph compiler that translates visual material graphs into HLSL shader code. Artists and technical designers build materials by connecting nodes in the editor, and the compiler generates optimized vertex and pixel shaders.
Source: SparkEngine/Source/Graphics/ShaderGraph/ShaderGraphCompiler.h
Namespace: Spark::Graphics
Tests: Tests/TestShaderGraphCompiler.cpp (5 test cases)
The shader graph system bridges the gap between visual material editing and GPU shader code. The editor (see SparkEditor) provides a node canvas where users connect input, math, and utility nodes to output nodes. The ShaderGraphCompiler traverses this graph and emits valid HLSL.
┌─────────────────────────────────────────────────────────┐
│ SparkEditor │
│ ┌────────────┐ ┌─────────┐ ┌───────────────────┐ │
│ │TextureSample│──│ Multiply │──│ SurfaceOutput │ │
│ └────────────┘ └─────────┘ │ .albedo │ │
│ ┌────────────┐ ┌─────────┐ │ .normal │ │
│ │ WorldNormal│──│ Normalize│──│ .roughness │ │
│ └────────────┘ └─────────┘ │ .metalness │ │
│ └───────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ShaderGraphCompiler::Compile() │
│ 1. Find output node │
│ 2. Topological sort (backward from output) │
│ 3. Emit HLSL variable declarations │
│ 4. Wire outputs to PBR struct │
├─────────────────────────────────────────────────────────┤
│ Generated HLSL │
│ vertex shader + pixel shader │
└─────────────────────────────────────────────────────────┘
The ShaderNodeType enum defines 35+ node types across four categories.
Provide data from the rendering context.
| Node | ID | Output | Description |
|---|---|---|---|
TextureSample |
0 | float4 |
Sample a texture at UV coordinates |
ConstantFloat |
1 | float |
Scalar constant value |
ConstantVec2 |
2 | float2 |
2D vector constant |
ConstantVec3 |
3 | float3 |
3D vector constant |
ConstantVec4 |
4 | float4 |
4D vector constant |
ConstantColor |
5 | float4 |
Color picker constant (RGBA) |
Time |
6 | float |
Elapsed time for animation |
UVCoords |
7 | float2 |
Mesh UV coordinates |
WorldPosition |
8 | float3 |
Fragment world position |
WorldNormal |
9 | float3 |
Interpolated world normal |
CameraVector |
10 | float3 |
Camera-to-fragment direction |
Perform mathematical operations on inputs.
| Node | ID | Inputs | Output | HLSL |
|---|---|---|---|---|
Add |
50 | A, B | A + B | a + b |
Subtract |
51 | A, B | A - B | a - b |
Multiply |
52 | A, B | A * B | a * b |
Divide |
53 | A, B | A / B | a / b |
DotProduct |
54 | A, B | float |
dot(a, b) |
CrossProduct |
55 | A, B | float3 |
cross(a, b) |
Normalize |
56 | V | unit V | normalize(v) |
Length |
57 | V | float |
length(v) |
Distance |
58 | A, B | float |
distance(a, b) |
Power |
59 | Base, Exp | Base^Exp | pow(base, exp) |
Sqrt |
60 | V | sqrt(V) | sqrt(v) |
Sin |
61 | V | sin(V) | sin(v) |
Cos |
62 | V | cos(V) | cos(v) |
Tan |
63 | V | tan(V) | tan(v) |
Lerp |
64 | A, B, T | lerp | lerp(a, b, t) |
Clamp |
65 | V, Min, Max | clamped | clamp(v, min, max) |
Saturate |
66 | V | [0,1] | saturate(v) |
Higher-level operations.
| Node | ID | Description |
|---|---|---|
Fresnel |
100 | Fresnel term from view angle and normal |
Noise |
101 | Procedural noise generation |
SplitVector |
105 | Split float3/4 into individual components |
CombineVector |
106 | Combine scalars into a vector |
Terminal nodes that define the material's surface properties.
| Node | ID | Inputs |
|---|---|---|
SurfaceOutput |
200 | Albedo, Normal, Roughness, Metalness, AO, Emissive (PBR) |
UnlitOutput |
201 | Color, Alpha (unlit / UI materials) |
struct ShaderNode
{
uint32_t id;
ShaderNodeType type;
std::vector<ShaderNodeInput> inputs;
std::unordered_map<std::string, std::string> properties;
};Each node has a unique ID, a type, input sockets with default values, and optional string properties (e.g., texture path for TextureSample).
struct ShaderConnection
{
uint32_t fromNodeID;
uint32_t fromSocketIndex;
uint32_t toNodeID;
uint32_t toSocketIndex;
};A connection wires one node's output socket to another node's input socket.
struct ShaderGraphInput
{
std::vector<ShaderNode> nodes;
std::vector<ShaderConnection> connections;
uint32_t surfaceOutputNodeID;
uint32_t unlitOutputNodeID;
std::string materialName;
};The complete graph description passed to the compiler. Either surfaceOutputNodeID or unlitOutputNodeID should be set (not both).
struct ShaderGraphOutput
{
std::string vertexShader;
std::string pixelShader;
std::vector<std::string> errors;
int textureSlotCount;
bool success;
};The compilation result containing generated HLSL code, any error messages, and the number of texture slots used.
ShaderGraphCompiler::Compile() follows a four-step process:
-
Find the output node — Locate the
SurfaceOutputorUnlitOutputnode in the graph - Topological sort — Walk connections backward from the output node to all reachable inputs, producing a dependency-ordered list of nodes
- Emit HLSL — For each node in topological order, generate a local HLSL variable declaration. Connected inputs resolve to the upstream node's variable; unconnected inputs use default values
- Wire output struct — Map the output node's inputs to the PBR or unlit output structure fields
Each node generates a uniquely named variable (_node{id}_out{socket}) to avoid collisions.
using namespace Spark::Graphics;
ShaderGraphInput graph;
graph.materialName = "BrickWall";
// Add a texture sample node
ShaderNode texNode;
texNode.id = 1;
texNode.type = ShaderNodeType::TextureSample;
texNode.properties["texture"] = "textures/brick_diffuse.dds";
graph.nodes.push_back(texNode);
// Add a surface output node
ShaderNode outputNode;
outputNode.id = 2;
outputNode.type = ShaderNodeType::SurfaceOutput;
outputNode.inputs.resize(6); // albedo, normal, roughness, metalness, ao, emissive
graph.nodes.push_back(outputNode);
graph.surfaceOutputNodeID = 2;
// Connect texture sample → albedo input
ShaderConnection conn;
conn.fromNodeID = 1;
conn.fromSocketIndex = 0;
conn.toNodeID = 2;
conn.toSocketIndex = 0; // albedo
graph.connections.push_back(conn);
// Compile
ShaderGraphOutput result = ShaderGraphCompiler::Compile(graph);
if (result.success)
{
// result.vertexShader and result.pixelShader contain valid HLSL
LOG_INFO("Generated shaders for {}", graph.materialName);
LOG_INFO("Texture slots used: {}", result.textureSlotCount);
}
else
{
for (const auto& err : result.errors)
{
LOG_ERROR("Shader graph error: {}", err);
}
}-
SparkEditor: The material editor panel creates
ShaderGraphInputfrom the visual canvas and callsCompile(). See SparkEditor - SparkShaderCompiler: The standalone tool can also compile shader graphs from serialized JSON. See Shader Pipeline
- Material System: Generated HLSL is fed to the shader compilation pipeline and cached. See Rendering and Graphics
- Thread safety: Not thread-safe — compile one graph at a time
- Visual Scripting — General visual scripting system (references shader graph as prior art)
- Shader Pipeline — HLSL compilation, cross-compilation, and hot-reload
- Rendering and Graphics — Material system and PBR pipeline
- Asset Pipeline — Texture and material asset management
Published from 2b03dc797148. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Platform Certification
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Fuzz Policy and Parser Security
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Crash Reporting
- Golden Image Testing
- Utilities
- Testing
- Fuzz Policy and Parser Security
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers