Files
mod_core/shaders/SHADER_CONTRACT.md
T
2026-09-10 10:59:36 +03:00

146 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Shader contract for gd_cubism (Live2D)
## Overview
gd_cubism uses 10 shaders to render Live2D models. Each drawable (mesh part)
selects one of these shaders based on its blend mode and mask configuration.
A mod can replace any shader by placing a `.gdshader` file with the same name
in its `shaders/` directory.
## Mandatory contract
### Uniforms — DO NOT remove or rename
Every shader below MUST declare the uniforms listed in its section. The C++ renderer
sets these uniforms by name via `ShaderMaterial::set_shader_parameter()`.
Removing or renaming a uniform will break rendering.
You MAY add new uniforms (e.g. `uniform float pixel_size = 4.0;`), but you
must set them manually in code via `model.GetMeshes()`.
### Vertex shader
All shaders MUST include `UV.y = 1.0 - UV.y;` in the vertex function.
This flips the texture vertically to match Live2D's coordinate system.
### blend_mode must match
The `render_mode` line must remain compatible with the blend operation
the C++ code expects. Changing `blend_premul_alpha` to `blend_mix`
will produce incorrect transparency.
---
## Shader catalog
### 1. `2d_cubism_norm_mix.gdshader` — Normal blend (most drawables)
render_mode: `blend_premul_alpha, unshaded`
Mandatory uniforms:
```
uniform vec4 color_base : source_color;
uniform vec4 color_screen : source_color;
uniform vec4 color_multiply : source_color;
uniform vec4 channel : source_color;
uniform sampler2D tex_main : filter_linear_mipmap;
```
Varying: `varying vec4 modulate` (passed from vertex: `modulate = COLOR`)
Fragment output: `COLOR = vec4(color.rgb * color.a, color.a);`
### 2. `2d_cubism_norm_add.gdshader` — Additive blend
Same uniforms and contract as norm_mix. Fragment output:
`COLOR = vec4(color.rgb * color.a, 0.0);` (alpha=0 for additive)
### 3. `2d_cubism_norm_mul.gdshader` — Multiply blend
Same uniforms and contract as norm_mix.
### 4. `2d_cubism_mask.gdshader` — Mask generation (offscreen)
render_mode: `blend_mix, unshaded`
Mandatory uniforms:
```
uniform vec4 channel : source_color;
uniform sampler2D tex_main : filter_linear_mipmap;
```
Fragment output: `COLOR = channel * texture(tex_main, UV).a;`
This shader writes alpha to the mask texture. Not visible on screen.
### 510. Masked drawable shaders
`2d_cubism_mask_mix`, `mask_add`, `mask_mul`, `mask_mix_inv`, `mask_add_inv`, `mask_mul_inv`
render_mode: same as their non-mask counterpart
Mandatory uniforms (all of norm_mix PLUS):
```
uniform sampler2D tex_mask : filter_linear_mipmap;
```
Additional varyings (computed in vertex):
```
varying vec2 MASK_UV;
```
Mask UV computation in vertex:
```glsl
MASK_UV = (VERTEX - mesh_offset) / mask_size;
// where mask_size = textureSize(tex_mask, 0) / mask_scale
```
Fragment must sample `tex_mask` and multiply/lerp the main color by
the sum of mask channels: `clip_mask.r + clip_mask.g + clip_mask.b + clip_mask.a`.
The `_inv` variants invert this: `(1.0 - mask_val)`.
---
## How to add custom logic
**Safe additions** (will not break rendering):
- Add new `uniform` declarations (set values via `ShaderMaterial.SetShaderParameter`)
- Modify internal fragment calculations (e.g. pixel-art downscale)
- Add conditional logic (e.g. `if (pixel_size > 1.0) { ... }`)
**Allowed modifications:**
- Change texture filtering: `filter_linear_mipmap``filter_nearest`
- Add post-processing in fragment (color grading, dithering, outline)
- Add noise/procedural effects using new uniforms
**Forbidden modifications:**
- Remove or rename mandatory uniforms
- Change `render_mode` blend type
- Remove `UV.y = 1.0 - UV.y` from vertex
- Change the data type of mandatory uniforms (vec4 → vec3, etc.)
---
## Mod override example
To create a pixel-art Live2D shader:
1. Copy `2d_cubism_norm_mix.gdshader` to `mods/your_mod/shaders/`
2. Add a new uniform: `uniform float pixel_size : hint_range(1.0, 16.0) = 4.0;`
3. Modify fragment to downsample:
```glsl
vec2 tex_size = vec2(textureSize(tex_main, 0));
vec2 snapped_uv = floor(UV * tex_size / pixel_size) * pixel_size / tex_size;
vec4 color_tex = texture(tex_main, snapped_uv);
```
4. Keep all mandatory uniforms and the vertex shader intact.
5. In code, find the material and set `pixel_size`:
```csharp
var meshes = model.GetMeshes();
foreach (var kv in meshes) {
var mesh = (ArrayMesh)kv.Value;
var mat = (ShaderMaterial)mesh.SurfaceGetMaterial(0);
mat.SetShaderParameter("pixel_size", 4.0f);
}
```