Render Modes Guide
Nethercore ZX supports 4 rendering modes, each with different lighting and material features.
Overview
| Mode | Name | Lighting | Best For |
|---|---|---|---|
| 0 | Lambert | Simple diffuse | Flat colors, UI, retro 2D |
| 1 | Matcap | Pre-baked | Stylized, toon, sculpted look |
| 2 | Metallic-Roughness | PBR-style Blinn-Phong | Realistic materials |
| 3 | Specular-Shininess | Traditional Blinn-Phong | Classic 3D, arcade |
Set the mode in your nether.toml:
[game]
id = "my-game"
title = "My Game"
author = "Developer"
version = "1.0.0"
render_mode = 2 # 0=Lambert, 1=Matcap, 2=Metallic-Roughness, 3=Specular-Shininess
If not specified, defaults to mode 0 (Lambert). The render mode cannot be changed at runtime.
Mode 0: Lambert
Supports both flat shading (without normals) and Lambert diffuse shading (with normals). Without normals, colors come directly from textures and set_color(). With normals, applies Lambert lighting from environment and dynamic lights.
Features:
- Fastest rendering
- Flat, solid colors
- No shadows or highlights
- Perfect for 2D sprites, UI, or intentionally flat aesthetics
Example:
#![allow(unused)]
fn main() {
// nether.toml: render_mode = 0
fn render() {
// Color comes purely from texture + set_color tint
texture_bind(sprite_tex);
set_color(0xFFFFFFFF);
draw_mesh(quad);
}
}
Use cases:
- 2D games with sprite-based graphics
- UI elements
- Retro flat-shaded PS1 style
- Unlit portions of scenes (skyboxes, emissive objects)
Mode 1: Matcap
Uses matcap textures for pre-baked lighting. Fast and stylized.
Features:
- Lighting baked into matcap textures
- No dynamic lights
- Great for stylized/toon looks
- Multiple matcaps can be layered
Texture Slots:
| Slot | Purpose | Blend Mode |
|---|---|---|
| 0 | Albedo (UV-mapped) | Base color |
| 1-3 | Matcap (normal-mapped) | Configurable |
Matcap Blend Modes:
- 0 (Multiply): Darkens (shadows, AO)
- 1 (Add): Brightens (highlights, rim)
- 2 (HSV Modulate): Hue/saturation shift
Example:
#![allow(unused)]
fn main() {
// nether.toml: render_mode = 1
fn init() {
SHADOW_MATCAP = rom_texture(b"matcap_shadow".as_ptr(), 13);
HIGHLIGHT_MATCAP = rom_texture(b"matcap_highlight".as_ptr(), 16);
}
fn render() {
texture_bind(character_albedo);
matcap_set(1, SHADOW_MATCAP);
matcap_blend_mode(1, 0); // Multiply
matcap_set(2, HIGHLIGHT_MATCAP);
matcap_blend_mode(2, 1); // Add
draw_mesh(character);
}
}
Use cases:
- Stylized/cartoon characters
- Sculpt-like rendering
- Fast mobile-friendly lighting
- Consistent lighting regardless of scene
Mode 2: Metallic-Roughness
PBR-inspired Blinn-Phong with metallic/roughness workflow.
Features:
- Up to 4 dynamic lights
- Metallic/roughness material properties
- MRE texture support (Metallic/Roughness/Emissive)
- Rim lighting
- Procedural sky ambient
- Energy-conserving Gotanda normalization
Texture Slots:
| Slot | Purpose | Channels |
|---|---|---|
| 0 | Albedo | RGB: Diffuse color |
| 1 | MRE | R: Metallic, G: Roughness, B: Emissive |
Material Functions:
#![allow(unused)]
fn main() {
material_metallic(0.0); // 0 = dielectric, 1 = metal
material_roughness(0.5); // 0 = mirror, 1 = rough
material_emissive(0.0); // Self-illumination
material_rim(0.2, 0.15); // Rim light intensity and power
}
Example:
#![allow(unused)]
fn main() {
// nether.toml: render_mode = 2
fn render() {
// Set up lighting
light_set(0, 0.5, -0.7, 0.5);
light_color(0, 0xFFF2E6FF);
light_enable(0);
// Shiny metal
material_metallic(1.0);
material_roughness(0.2);
material_rim(0.1, 0.2);
texture_bind(sword_tex);
draw_mesh(sword);
// Rough stone
material_metallic(0.0);
material_roughness(0.9);
material_rim(0.0, 0.0);
texture_bind(stone_tex);
draw_mesh(wall);
}
}
Use cases:
- Realistic materials (metal, plastic, wood)
- PBR asset pipelines
- Games requiring material variety
- Modern 3D aesthetics
Mode 3: Specular-Shininess
Traditional Blinn-Phong with direct specular color control.
Features:
- Up to 4 dynamic lights
- Shininess-based specular
- Direct specular color control
- Rim lighting
- Energy-conserving Gotanda normalization
Texture Slots:
| Slot | Purpose | Channels |
|---|---|---|
| 0 | Albedo | RGB: Diffuse color |
| 1 | SSE | R: Specular intensity, G: Shininess, B: Emissive |
| 2 | Specular | RGB: Specular highlight color |
Material Functions:
#![allow(unused)]
fn main() {
material_shininess(0.7); // 0-1 → maps to 1-256
material_specular(0xFFD700FF); // Specular highlight color
material_emissive(0.0); // Self-illumination
material_rim(0.2, 0.15); // Rim light
}
Shininess Values:
| Value | Shininess | Appearance |
|---|---|---|
| 0.0-0.2 | 1-52 | Very soft (cloth, skin) |
| 0.2-0.4 | 52-103 | Broad (leather, wood) |
| 0.4-0.6 | 103-154 | Medium (plastic) |
| 0.6-0.8 | 154-205 | Tight (polished metal) |
| 0.8-1.0 | 205-256 | Mirror (chrome, glass) |
Example:
#![allow(unused)]
fn main() {
// nether.toml: render_mode = 3
fn render() {
// Gold armor
set_color(0xE6B84DFF);
material_shininess(0.8);
material_specular(0xFFD700FF);
material_rim(0.2, 0.15);
draw_mesh(armor);
// Wet skin
set_color(0xD9B399FF);
material_shininess(0.7);
material_specular(0xFFFFFFFF);
material_rim(0.3, 0.25);
draw_mesh(character);
}
}
Use cases:
- Classic 3D game aesthetics
- Colored specular highlights (metals)
- Artist-friendly workflow
- Fighting games, action games
Choosing a Mode
| If you need… | Use Mode |
|---|---|
| Fastest rendering, simple lighting | 0 (Lambert) |
| Stylized, consistent lighting | 1 (Matcap) |
| PBR workflow with MRE textures | 2 (Metallic-Roughness) |
| Colored specular, artist control | 3 (Specular-Shininess) |
Performance: All lit modes (1-3) have similar performance. Mode 0 is fastest.
Compatibility: All modes work with procedural meshes and skeletal animation.
Common Setup
All lit modes benefit from proper environment and light setup. See the EPU Environments Guide for details on the new instruction-based EPU API.
#![allow(unused)]
fn main() {
// nether.toml: render_mode = 1, 2, or 3
// 8 x [hi, lo] = 128 bytes (16 x u64).
// For presets and packing helpers, see `examples/3-inspectors/epu-showcase/`.
static ENV: [[u64; 2]; 8] = [
[0, 0], [0, 0], [0, 0], [0, 0],
[0, 0], [0, 0], [0, 0], [0, 0],
];
fn render() {
// Set environment config.
unsafe { epu_set(ENV.as_ptr().cast()); }
// Main directional light
light_set(0, 0.5, -0.7, 0.5);
light_color(0, 0xFFF2E6FF);
light_intensity(0, 1.0);
light_enable(0);
// Fill light
light_set(1, -0.8, -0.3, 0.0);
light_color(1, 0x8899BBFF);
light_intensity(1, 0.3);
light_enable(1);
// Draw scene...
// Draw environment background last (fills only background pixels).
unsafe { draw_epu(); }
}
}