godot-shaders-basics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Shader Basics

着色器基础

Fragment/vertex shaders, uniforms, and built-in variables define custom visual effects.
片段/顶点着色器、uniform及内置变量用于定义自定义视觉效果。

Available Scripts

可用脚本

vfx_port_shader.gdshader

vfx_port_shader.gdshader

Expert shader template with parameter validation and common effect patterns.
带有参数验证和通用效果模式的专家级着色器模板。

shader_parameter_animator.gd

shader_parameter_animator.gd

Runtime shader uniform animation without AnimationPlayer - for dynamic effects.
无需AnimationPlayer即可运行时动画化着色器uniform,用于实现动态效果。

NEVER Do in Shaders

着色器编程禁忌

  • NEVER use expensive operations in fragment()
    pow()
    ,
    sqrt()
    ,
    sin()
    on every pixel? 1920x1080 = 2M calls/frame = lag. Pre-calculate OR use texture lookups.
  • NEVER forget to normalize vectors
    reflect(direction, normal)
    without normalization? Wrong reflections + rendering artifacts. ALWAYS normalize direction vectors.
  • NEVER use if/else for branching — GPUs hate branching (SIMD architecture). Use
    mix()
    ,
    step()
    ,
    smoothstep()
    for conditional logic.
  • NEVER modify UV without bounds check
    UV.x += 10.0
    goes outside 0-1 range? Texture sampling breaks. Use
    fract()
    OR
    clamp()
    .
  • NEVER use TIME without delta
    COLOR.a = sin(TIME)
    runs at variable speed on different framerates. Use
    TIME * speed_factor
    for consistent animation.
  • NEVER forget hint_source_color for colors
    uniform vec4 tint
    without hint? Inspector shows raw floats. Use
    uniform vec4 tint : source_color
    for color picker.

gdsl
shader_type canvas_item;

void fragment() {
    // Get texture color
    vec4 tex_color = texture(TEXTURE, UV);
    
    // Tint red
    COLOR = tex_color * vec4(1.0, 0.5, 0.5, 1.0);
}
Apply to Sprite:
  1. Select Sprite2D node
  2. Material → New ShaderMaterial
  3. Shader → New Shader
  4. Paste code
  • 绝对不要在fragment()中使用高开销操作 — 每个像素都调用
    pow()
    sqrt()
    sin()
    ?1920x1080分辨率下每帧会有200万次调用,导致卡顿。请预先计算或使用纹理查找。
  • 绝对不要忘记归一化向量 — 未归一化就使用
    reflect(direction, normal)
    ?会导致错误的反射和渲染 artifacts。务必归一化方向向量。
  • 绝对不要使用if/else进行分支判断 — GPU讨厌分支逻辑(基于SIMD架构)。使用
    mix()
    step()
    smoothstep()
    实现条件逻辑。
  • 绝对不要在未做边界检查的情况下修改UV
    UV.x += 10.0
    会超出0-1范围?纹理采样会失效。使用
    fract()
    clamp()
    处理。
  • 绝对不要不结合delta使用TIME
    COLOR.a = sin(TIME)
    在不同帧率下运行速度不一致。使用
    TIME * speed_factor
    保证动画速度一致。
  • 绝对不要忘记为颜色变量添加hint_source_color
    uniform vec4 tint
    未添加提示?检查器会显示原始浮点数。使用
    uniform vec4 tint : source_color
    来启用颜色选择器。

gdsl
shader_type canvas_item;

void fragment() {
    // Get texture color
    vec4 tex_color = texture(TEXTURE, UV);
    
    // Tint red
    COLOR = tex_color * vec4(1.0, 0.5, 0.5, 1.0);
}
应用到Sprite:
  1. 选择Sprite2D节点
  2. 材质 → 新建ShaderMaterial
  3. 着色器 → 新建Shader
  4. 粘贴代码

Common 2D Effects

常见2D效果

Dissolve Effect

溶解效果

glsl
shader_type canvas_item;

uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D noise_texture;

void fragment() {
    vec4 tex_color = texture(TEXTURE, UV);
    float noise = texture(noise_texture, UV).r;
    
    if (noise < dissolve_amount) {
        discard;  // Make pixel transparent
    }
    
    COLOR = tex_color;
}
glsl
shader_type canvas_item;

uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D noise_texture;

void fragment() {
    vec4 tex_color = texture(TEXTURE, UV);
    float noise = texture(noise_texture, UV).r;
    
    if (noise < dissolve_amount) {
        discard;  // Make pixel transparent
    }
    
    COLOR = tex_color;
}

Wave Distortion

波浪扭曲效果

glsl
shader_type canvas_item;

uniform float wave_speed = 2.0;
uniform float wave_amount = 0.05;

void fragment() {
    vec2 uv = UV;
    uv.x += sin(uv.y * 10.0 + TIME * wave_speed) * wave_amount;
    
    COLOR = texture(TEXTURE, uv);
}
glsl
shader_type canvas_item;

uniform float wave_speed = 2.0;
uniform float wave_amount = 0.05;

void fragment() {
    vec2 uv = UV;
    uv.x += sin(uv.y * 10.0 + TIME * wave_speed) * wave_amount;
    
    COLOR = texture(TEXTURE, uv);
}

Outline

描边效果

glsl
shader_type canvas_item;

uniform vec4 outline_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float outline_width = 2.0;

void fragment() {
    vec4 col = texture(TEXTURE, UV);
    vec2 pixel_size = TEXTURE_PIXEL_SIZE * outline_width;
    
    float alpha = col.a;
    alpha = max(alpha, texture(TEXTURE, UV + vec2(pixel_size.x, 0.0)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(-pixel_size.x, 0.0)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(0.0, pixel_size.y)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(0.0, -pixel_size.y)).a);
    
    COLOR = mix(outline_color, col, col.a);
    COLOR.a = alpha;
}
glsl
shader_type canvas_item;

uniform vec4 outline_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float outline_width = 2.0;

void fragment() {
    vec4 col = texture(TEXTURE, UV);
    vec2 pixel_size = TEXTURE_PIXEL_SIZE * outline_width;
    
    float alpha = col.a;
    alpha = max(alpha, texture(TEXTURE, UV + vec2(pixel_size.x, 0.0)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(-pixel_size.x, 0.0)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(0.0, pixel_size.y)).a);
    alpha = max(alpha, texture(TEXTURE, UV + vec2(0.0, -pixel_size.y)).a);
    
    COLOR = mix(outline_color, col, col.a);
    COLOR.a = alpha;
}

3D Shaders

3D着色器

Basic 3D Shader

基础3D着色器

glsl
shader_type spatial;

void fragment() {
    ALBEDO = vec3(1.0, 0.0, 0.0);  // Red material
}
glsl
shader_type spatial;

void fragment() {
    ALBEDO = vec3(1.0, 0.0, 0.0);  // Red material
}

Toon Shading (Cel-Shading)

卡通着色(Cel-Shading)

glsl
shader_type spatial;

uniform vec3 base_color : source_color = vec3(1.0);
uniform int color_steps = 3;

void light() {
    float NdotL = dot(NORMAL, LIGHT);
    float stepped = floor(NdotL * float(color_steps)) / float(color_steps);
    
    DIFFUSE_LIGHT = base_color * stepped;
}
glsl
shader_type spatial;

uniform vec3 base_color : source_color = vec3(1.0);
uniform int color_steps = 3;

void light() {
    float NdotL = dot(NORMAL, LIGHT);
    float stepped = floor(NdotL * float(color_steps)) / float(color_steps);
    
    DIFFUSE_LIGHT = base_color * stepped;
}

Screen-Space Effects

屏幕空间效果

Vignette

暗角效果

glsl
shader_type canvas_item;

uniform float vignette_strength = 0.5;

void fragment() {
    vec4 color = texture(TEXTURE, UV);
    
    // Distance from center
    vec2 center = vec2(0.5, 0.5);
    float dist = distance(UV, center);
    
    float vignette = 1.0 - dist * vignette_strength;
    
    COLOR = color * vignette;
}
glsl
shader_type canvas_item;

uniform float vignette_strength = 0.5;

void fragment() {
    vec4 color = texture(TEXTURE, UV);
    
    // Distance from center
    vec2 center = vec2(0.5, 0.5);
    float dist = distance(UV, center);
    
    float vignette = 1.0 - dist * vignette_strength;
    
    COLOR = color * vignette;
}

Uniforms (Parameters)

Uniform(参数)

glsl
// Float slider
uniform float intensity : hint_range(0.0, 1.0) = 0.5;

// Color picker
uniform vec4 tint_color : source_color = vec4(1.0);

// Texture
uniform sampler2D noise_texture;

// Access in code:
material.set_shader_parameter("intensity", 0.8)
glsl
// Float slider
uniform float intensity : hint_range(0.0, 1.0) = 0.5;

// Color picker
uniform vec4 tint_color : source_color = vec4(1.0);

// Texture
uniform sampler2D noise_texture;

// Access in code:
material.set_shader_parameter("intensity", 0.8)

Built-in Variables

内置变量

2D (canvas_item):
  • UV
    - Texture coordinates (0-1)
  • COLOR
    - Output color
  • TEXTURE
    - Current texture
  • TIME
    - Time since start
  • SCREEN_UV
    - Screen coordinates
3D (spatial):
  • ALBEDO
    - Base color
  • NORMAL
    - Surface normal
  • ROUGHNESS
    - Surface roughness
  • METALLIC
    - Metallic value
2D(canvas_item):
  • UV
    - 纹理坐标(0-1)
  • COLOR
    - 输出颜色
  • TEXTURE
    - 当前纹理
  • TIME
    - 程序启动后的时间
  • SCREEN_UV
    - 屏幕坐标
3D(spatial):
  • ALBEDO
    - 基础颜色
  • NORMAL
    - 表面法线
  • ROUGHNESS
    - 表面粗糙度
  • METALLIC
    - 金属度

Best Practices

最佳实践

1. Use Uniforms for Tweaking

1. 使用Uniform进行参数调整

glsl
// ✅ Good - adjustable
uniform float speed = 1.0;

void fragment() {
    COLOR.r = sin(TIME * speed);
}

// ❌ Bad - hardcoded
void fragment() {
    COLOR.r = sin(TIME * 2.5);
}
glsl
// ✅ 推荐 - 可调整
uniform float speed = 1.0;

void fragment() {
    COLOR.r = sin(TIME * speed);
}

// ❌ 不推荐 - 硬编码
void fragment() {
    COLOR.r = sin(TIME * 2.5);
}

2. Optimize Performance

2. 性能优化

glsl
// Avoid expensive operations in fragment shader
// Pre-calculate values when possible
// Use textures for complex patterns
glsl
// 避免在片段着色器中使用高开销操作
// 尽可能预先计算值
// 对复杂图案使用纹理

3. Comment Shaders

3. 为着色器添加注释

glsl
// Water wave effect
// Creates horizontal distortion based on sine wave
uniform float wave_amplitude = 0.02;
glsl
// 水波效果
// 基于正弦波创建水平扭曲
uniform float wave_amplitude = 0.02;

Reference

参考资料

Related

相关内容

  • Master Skill: godot-master
  • 核心技能:godot-master