9. 2.5D材质与着色器
9. 2.5D材质与着色器
材质是什么?
想象你做了一个泥塑小人,光秃秃的泥土颜色看起来很单调。这时候你给它涂上颜色、贴上花纹、刷上光泽——这个"装扮"的过程,就是给模型添加材质。
在 Godot 里,材质(Material) 就是决定一个物体"看起来是什么样子"的配方。它告诉渲染引擎:这个物体是金属的还是木头的?表面光滑还是粗糙?会不会反光?
没有材质的模型就像没穿衣服的人体模型——形状有了,但没有质感。
Godot 中的材质类型
Godot 4 提供了几种主要的材质类型,各有用途:
1. StandardMaterial3D(标准材质)
这是最常用的材质,适合大多数情况。就像一个"万能调色盘",你可以调节颜色、光泽、透明度等各种参数,不需要写任何代码。
适合: 普通物体、角色、道具
2. ORM 材质(ORMMaterial3D)
ORM 是三个单词的缩写:
- Occlusion(遮蔽):哪些地方被遮住了光
- Roughness(粗糙度):表面有多粗糙
- Metallic(金属度):是否像金属一样反光
这种材质把三张贴图合并成一张,节省内存,适合追求性能的项目。
3. ShaderMaterial(着色器材质)
这是最灵活的材质,允许你用代码完全自定义渲染效果。就像从"买现成衣服"变成"自己设计裁缝"——可以做出任何效果,但需要学习着色器语言。
2.5D 常用材质风格
2.5D 游戏有几种经典的视觉风格,每种风格对材质的要求不同:
低多边形风格(Low Poly)
低多边形风格的特点是面数少、颜色纯、没有复杂光影。就像折纸艺术——简单但有独特美感。
材质设置:
- 关闭法线贴图
- 使用纯色 Albedo(颜色贴图)
- 将 Roughness(粗糙度)调高(接近 1.0)
- Metallic(金属度)设为 0
在 Godot 编辑器中:
- 选中 MeshInstance3D 节点
- 在 Inspector 面板找到 Material
- 新建 StandardMaterial3D
- 设置 Albedo Color 为你想要的颜色
- 将 Roughness 调到 0.9 以上
卡通风格(Toon/Cel Shading)
卡通风格模仿手绘动漫的感觉:颜色分成明显的色阶(不是渐变),加上黑色轮廓线。就像《塞尔达传说:风之杖》那种感觉。
实现方式:
- 使用 ShaderMaterial 自定义光照计算
- 将光照分成 2-3 个色阶(亮面/暗面/中间)
- 添加轮廓线(后面会有示例)
像素风格(Pixel Art)
像素风格在 2.5D 中很特别:3D 场景 + 像素贴图。关键是让贴图保持像素感,不要被模糊处理。
材质设置:
- 导入贴图时,将 Filter 设为 Nearest(最近邻过滤)
- 这样像素边缘保持清晰,不会被模糊
在 Godot 中设置像素贴图:
- 在 FileSystem 面板找到贴图文件
- 点击贴图,在 Import 面板
- 将 Filter 改为 Nearest
- 点击 Reimport
贴图类型详解
贴图就是"图片",不同类型的贴图负责描述物体外观的不同方面:
Albedo(反照率/颜色贴图)
这是最基础的贴图,就是物体的"底色"。就像给人画像时先画皮肤颜色。
Normal Map(法线贴图)
法线贴图是一张蓝紫色的图片,它不改变模型的实际形状,但能让光照产生凹凸感的错觉。就像在平整的墙上画出砖块纹理的阴影——看起来有立体感,但实际上是平的。
2.5D 中的使用建议: 低多边形风格通常不用法线贴图;写实风格可以用来增加细节。
Roughness(粗糙度贴图)
控制表面的光滑程度:
- 值接近 0 = 非常光滑(像镜子)
- 值接近 1 = 非常粗糙(像砂纸)
Emission(自发光贴图)
让物体自己发光,不依赖场景中的灯光。适合做霓虹灯、魔法效果、UI 元素。
ShaderMaterial 入门
着色器是什么?
着色器(Shader)是运行在显卡上的小程序,专门负责计算每个像素的颜色。
用一个比喻:普通材质就像"预设菜单",你只能选已有的菜;着色器就像"自己下厨",可以做任何菜,但需要知道怎么做。
Godot 使用自己的着色器语言 GLSL 风格,语法类似 C 语言。
着色器的基本结构
shader_type spatial; // 声明这是3D着色器
void vertex() {
// 在这里修改顶点位置
}
void fragment() {
// 在这里计算像素颜色
ALBEDO = vec3(1.0, 0.0, 0.0); // 红色
}实用 2.5D 着色器示例
示例1:卡通轮廓线着色器
这个着色器给物体添加黑色轮廓线,实现卡通效果:
// outline_shader.gdshader
shader_type spatial;
render_mode unshaded, cull_front;
uniform float outline_width : hint_range(0.0, 0.1) = 0.02;
uniform vec4 outline_color : source_color = vec4(0.0, 0.0, 0.0, 1.0);
void vertex() {
// 沿法线方向膨胀顶点,形成轮廓
VERTEX += NORMAL * outline_width;
}
void fragment() {
ALBEDO = outline_color.rgb;
}使用方法:
- 在
res://shaders/目录新建文件outline.gdshader - 粘贴上面的代码
- 给角色模型添加一个额外的 MeshInstance3D(复制一份)
- 将这个复制体的材质设为 ShaderMaterial,使用这个着色器
- 调整
outline_width参数控制轮廓粗细
示例2:像素化后处理着色器
这个着色器让整个画面产生像素化效果:
// pixelate_shader.gdshader
shader_type canvas_item;
uniform int pixel_size : hint_range(1, 32) = 4;
void fragment() {
vec2 uv = SCREEN_UV;
vec2 screen_size = vec2(textureSize(SCREEN_TEXTURE, 0));
// 将UV坐标对齐到像素格子
float px = float(pixel_size) / screen_size.x;
float py = float(pixel_size) / screen_size.y;
uv = floor(uv / vec2(px, py)) * vec2(px, py);
COLOR = texture(SCREEN_TEXTURE, uv);
}使用方法:
- 在场景中添加
CanvasLayer节点 - 在 CanvasLayer 下添加
ColorRect节点,设置为全屏 - 给 ColorRect 添加 ShaderMaterial,使用这个着色器
用代码动态修改材质
有时候我们需要在游戏运行时改变物体的颜色或材质,比如角色受伤变红、拾取道具发光等。
using Godot;
public partial class MaterialController : Node3D
{
[Export] private MeshInstance3D _meshInstance;
// 原始颜色
private Color _originalColor = Colors.White;
public override void _Ready()
{
// 重要:必须先复制材质,否则会影响所有使用同一材质的物体
var material = _meshInstance.GetActiveMaterial(0) as StandardMaterial3D;
if (material != null)
{
// 创建材质的独立副本
_meshInstance.SetSurfaceOverrideMaterial(0, (StandardMaterial3D)material.Duplicate());
_originalColor = material.AlbedoColor;
}
}
// 切换到受伤颜色(红色)
public void SetHurtColor()
{
var material = _meshInstance.GetSurfaceOverrideMaterial(0) as StandardMaterial3D;
if (material != null)
{
material.AlbedoColor = new Color(1.0f, 0.2f, 0.2f); // 红色
}
}
// 恢复原始颜色
public void ResetColor()
{
var material = _meshInstance.GetSurfaceOverrideMaterial(0) as StandardMaterial3D;
if (material != null)
{
material.AlbedoColor = _originalColor;
}
}
// 设置自发光(发光效果)
public void SetGlowing(bool enabled, Color glowColor = default)
{
var material = _meshInstance.GetSurfaceOverrideMaterial(0) as StandardMaterial3D;
if (material != null)
{
material.EmissionEnabled = enabled;
if (enabled)
{
material.Emission = glowColor == default ? Colors.Yellow : glowColor;
material.EmissionEnergyMultiplier = 2.0f;
}
}
}
// 切换整个材质(比如切换到透明材质)
public void SwitchToTransparent()
{
var newMaterial = new StandardMaterial3D();
newMaterial.Transparency = BaseMaterial3D.TransparencyEnum.Alpha;
newMaterial.AlbedoColor = new Color(1, 1, 1, 0.5f); // 半透明白色
_meshInstance.SetSurfaceOverrideMaterial(0, newMaterial);
}
}extends Node3D
@export var mesh_instance: MeshInstance3D
# 原始颜色
var _original_color: Color = Color.WHITE
func _ready() -> void:
# 重要:必须先复制材质,否则会影响所有使用同一材质的物体
var material = mesh_instance.get_active_material(0) as StandardMaterial3D
if material:
# 创建材质的独立副本
mesh_instance.set_surface_override_material(0, material.duplicate())
_original_color = material.albedo_color
# 切换到受伤颜色(红色)
func set_hurt_color() -> void:
var material = mesh_instance.get_surface_override_material(0) as StandardMaterial3D
if material:
material.albedo_color = Color(1.0, 0.2, 0.2) # 红色
# 恢复原始颜色
func reset_color() -> void:
var material = mesh_instance.get_surface_override_material(0) as StandardMaterial3D
if material:
material.albedo_color = _original_color
# 设置自发光(发光效果)
func set_glowing(enabled: bool, glow_color: Color = Color.YELLOW) -> void:
var material = mesh_instance.get_surface_override_material(0) as StandardMaterial3D
if material:
material.emission_enabled = enabled
if enabled:
material.emission = glow_color
material.emission_energy_multiplier = 2.0
# 切换整个材质(比如切换到透明材质)
func switch_to_transparent() -> void:
var new_material = StandardMaterial3D.new()
new_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
new_material.albedo_color = Color(1, 1, 1, 0.5) # 半透明白色
mesh_instance.set_surface_override_material(0, new_material)材质性能优化建议
材质用得不好会拖慢游戏性能,以下是几个实用建议:
1. 共享材质
如果多个物体外观相同,让它们共用同一个材质资源,而不是每个物体都创建新材质。就像一个班级的学生穿同款校服,而不是每人定制。
注意: 如果需要在运行时修改某个物体的材质,必须先用 duplicate() 复制一份,否则会影响所有共用这个材质的物体。
2. 减少透明材质
透明材质(Transparency)比不透明材质消耗更多性能,因为渲染引擎需要对透明物体进行排序。能用不透明材质就不用透明材质。
3. 贴图尺寸
贴图尺寸应该是 2 的幂次方(如 256×256、512×512、1024×1024),这样 GPU 处理效率最高。
4. 合并网格
多个使用相同材质的小物体,可以合并成一个大网格(Merge Meshes),减少绘制调用次数。
5. LOD(细节层次)
远处的物体不需要高精度材质,可以使用 LOD 技术在不同距离切换不同精度的材质和模型。
小结
| 材质类型 | 适用场景 | 难度 |
|---|---|---|
| StandardMaterial3D | 大多数物体 | 简单 |
| ORMMaterial3D | 追求性能的项目 | 简单 |
| ShaderMaterial | 特殊视觉效果 | 需要学习着色器 |
2.5D 游戏中,材质风格的选择直接影响游戏的整体视觉感受。建议先确定好游戏的美术风格(低多边形/卡通/像素),再统一设置材质参数,保持视觉一致性。
