跳转到内容

材质与着色器

Material API 管理自定义着色器和渲染效果。通过 SpriteSpineAnimation 组件的 material 字段赋值材质。

创建着色器

import { Material } from 'esengine';
const shader = Material.createShader(vertexSrc, fragmentSrc);

返回 ShaderHandle(number 类型),返回 0 表示创建失败。

内置顶点属性

所有着色器共享固定的顶点属性位置:

Location名称类型说明
0a_positionvec3顶点位置
1a_colorvec4顶点颜色
2a_texCoordvec2纹理坐标

内置着色器源码

ShaderSources 提供默认的精灵和颜色着色器作为参考:

常量说明
ShaderSources.SPRITE_VERTEX默认精灵顶点着色器
ShaderSources.SPRITE_FRAGMENT默认精灵片段着色器
ShaderSources.COLOR_VERTEX无纹理几何体的顶点着色器
ShaderSources.COLOR_FRAGMENT无纹理几何体的片段着色器

创建材质

import { Material, BlendMode } from 'esengine';
const mat = Material.create({
shader,
uniforms: {
u_time: 0,
u_tint: { r: 1, g: 0, b: 0, a: 1 },
},
blendMode: BlendMode.Additive,
});
sprite.material = mat;

MaterialOptions

字段类型默认值说明
shaderShaderHandle必需。使用的着色器
uniformsRecord<string, UniformValue>{}初始 uniform 值
blendModeBlendModeNormal混合模式
depthTestbooleanfalse启用深度测试

Uniform

设置和获取

Material.setUniform(mat, 'u_time', elapsed);
Material.setUniform(mat, 'u_tint', { r: 1, g: 0.5, b: 0, a: 1 });
const time = Material.getUniform(mat, 'u_time');

Uniform 类型

类型示例
number1.5
Vec2{ x: 0.5, y: 1.0 }
Vec3{ x: 1, y: 0, z: 0 }
Color{ r: 1, g: 1, b: 1, a: 1 }
Vec4{ x: 1, y: 1, z: 1, w: 1 }
number[][1, 2, 3, 4]
TextureRefMaterial.tex(textureId, slot?)

纹理 Uniform

使用 Material.tex() 创建纹理引用用于采样器 uniform:

const tex = await assets.loadTexture('assets/noise.png');
Material.setUniform(mat, 'u_noiseTex', Material.tex(tex.handle, 1));

BlendMode

名称说明
0Normal标准 alpha 混合
1Additive加法混合(发光效果)
2Multiply乘法混合(变暗)
3Screen滤色混合(变亮)
4PremultipliedAlpha预乘 alpha 混合
Material.setBlendMode(mat, BlendMode.Screen);
const mode = Material.getBlendMode(mat);

材质实例

创建共享着色器但拥有独立 uniform 的实例:

const instance = Material.createInstance(sourceMat);
Material.setUniform(instance, 'u_tint', { r: 0, g: 1, b: 0, a: 1 });

着色器文件格式(.esshader)

着色器文件使用 #pragma 指令分隔顶点和片段部分:

#pragma vertex
#version 300 es
precision highp float;
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_texCoord;
uniform mat4 u_projection;
uniform mat4 u_model;
out vec4 v_color;
out vec2 v_texCoord;
void main() {
v_color = a_color;
v_texCoord = a_texCoord;
gl_Position = u_projection * u_model * vec4(a_position, 1.0);
}
#pragma end
#pragma fragment
#version 300 es
precision highp float;
in vec4 v_color;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = texture(u_texture, v_texCoord) * v_color;
}
#pragma end

通过资源服务器加载着色器文件:

const shader = await assets.loadShader('assets/effects/glow.esshader');

材质文件格式(.esmaterial)

材质可以定义为 JSON 文件,通过资源服务器加载:

{
"version": "1.0",
"type": "material",
"shader": "effects/glow.esshader",
"blendMode": 1,
"depthTest": false,
"properties": {
"u_intensity": 1.5,
"u_color": { "x": 1, "y": 0.5, "z": 0, "w": 1 }
}
}
字段类型说明
versionstring格式版本("1.0"
typestring必须为 "material"
shaderstring.esshader 文件路径(相对于材质文件或绝对路径)
blendModenumberBlendMode 枚举值
depthTestboolean启用深度测试
propertiesobjectuniform 名称/值对
const loaded = await assets.loadMaterial('assets/effects/glow.esmaterial');
sprite.material = loaded.handle;

示例:闪烁效果

在系统中动态更新 uniform 实现闪烁效果:

import { defineSystem, addSystem, Query, Mut, Res } from 'esengine';
import { Sprite, Material, BlendMode, Time } from 'esengine';
const flashShader = Material.createShader(
ShaderSources.SPRITE_VERTEX,
`#version 300 es
precision highp float;
in vec4 v_color;
in vec2 v_texCoord;
uniform sampler2D u_texture;
uniform float u_flash;
out vec4 fragColor;
void main() {
vec4 tex = texture(u_texture, v_texCoord) * v_color;
fragColor = mix(tex, vec4(1.0), u_flash * step(0.5, tex.a));
}`
);
const flashMat = Material.create({
shader: flashShader,
uniforms: { u_flash: 0.0 },
});
addSystem(defineSystem(
[Res(Time)],
(time) => {
const flash = Math.abs(Math.sin(time.elapsed * 5.0));
Material.setUniform(flashMat, 'u_flash', flash);
}
));

完整 API 参考

方法说明
Material.createShader(vertex, fragment)创建着色器程序
Material.releaseShader(shader)释放着色器
Material.create(options)创建材质
Material.createInstance(source)创建共享着色器的材质实例
Material.createFromAsset(data, shader)从解析的 .esmaterial 文件创建
Material.setUniform(mat, name, value)设置 uniform 值
Material.getUniform(mat, name)获取 uniform 值
Material.getUniforms(mat)获取所有 uniform(Map)
Material.setBlendMode(mat, mode)设置混合模式
Material.getBlendMode(mat)获取混合模式
Material.setDepthTest(mat, enabled)设置深度测试
Material.getShader(mat)获取着色器句柄
Material.release(mat)释放材质
Material.isValid(mat)检查材质是否存在
Material.toAssetData(mat, shaderPath)导出为可序列化格式
Material.tex(textureId, slot?)创建纹理 uniform 引用

下一步