feat(engine): 添加材质系统和着色器管理

This commit is contained in:
yhh
2025-12-03 16:20:13 +08:00
parent 0c590d7c12
commit 4a2362edf2
12 changed files with 1321 additions and 50 deletions

View File

@@ -0,0 +1,207 @@
//! Material manager for storing and retrieving materials.
//! 材质管理器,用于存储和检索材质。
use std::collections::HashMap;
use web_sys::WebGl2RenderingContext;
use super::material::{Material, BlendMode};
/// Reserved material IDs for built-in materials.
/// 内置材质的保留ID。
pub const MATERIAL_ID_DEFAULT: u32 = 0;
pub const MATERIAL_ID_ADDITIVE: u32 = 1;
pub const MATERIAL_ID_MULTIPLY: u32 = 2;
pub const MATERIAL_ID_UNLIT: u32 = 3;
/// Material manager for creating and caching materials.
/// 材质管理器,用于创建和缓存材质。
pub struct MaterialManager {
/// Stored materials indexed by ID.
/// 按ID索引的存储材质。
materials: HashMap<u32, Material>,
/// Next available material ID for custom materials.
/// 下一个可用的自定义材质ID。
next_material_id: u32,
}
impl MaterialManager {
/// Create a new material manager with built-in materials.
/// 创建带有内置材质的新材质管理器。
pub fn new() -> Self {
let mut manager = Self {
materials: HashMap::new(),
next_material_id: 100, // Reserve 0-99 for built-in materials
};
// Register built-in materials | 注册内置材质
manager.materials.insert(MATERIAL_ID_DEFAULT, Material::sprite());
manager.materials.insert(MATERIAL_ID_ADDITIVE, Material::additive());
manager.materials.insert(MATERIAL_ID_MULTIPLY, Material::multiply());
manager.materials.insert(MATERIAL_ID_UNLIT, Material::unlit());
log::info!("MaterialManager initialized with {} built-in materials | 材质管理器初始化完成,内置材质数量: {}",
manager.materials.len(), manager.materials.len());
manager
}
/// Register a custom material.
/// 注册自定义材质。
///
/// # Returns | 返回
/// The material ID for referencing this material | 用于引用此材质的ID
pub fn register_material(&mut self, material: Material) -> u32 {
let material_id = self.next_material_id;
self.next_material_id += 1;
log::debug!("Registered material '{}' with ID: {} | 注册材质 '{}' ID: {}",
material.name, material_id, material.name, material_id);
self.materials.insert(material_id, material);
material_id
}
/// Register a material with a specific ID.
/// 使用特定ID注册材质。
pub fn register_material_with_id(&mut self, material_id: u32, material: Material) {
log::debug!("Registered material '{}' with ID: {} | 注册材质 '{}' ID: {}",
material.name, material_id, material.name, material_id);
self.materials.insert(material_id, material);
// Update next_material_id if necessary
if material_id >= self.next_material_id {
self.next_material_id = material_id + 1;
}
}
/// Get a material by ID.
/// 按ID获取材质。
#[inline]
pub fn get_material(&self, material_id: u32) -> Option<&Material> {
self.materials.get(&material_id)
}
/// Get a mutable material by ID.
/// 按ID获取可变材质。
#[inline]
pub fn get_material_mut(&mut self, material_id: u32) -> Option<&mut Material> {
self.materials.get_mut(&material_id)
}
/// Get the default material.
/// 获取默认材质。
#[inline]
pub fn get_default_material(&self) -> &Material {
self.materials.get(&MATERIAL_ID_DEFAULT)
.expect("Default material should always exist | 默认材质应该始终存在")
}
/// Check if a material exists.
/// 检查材质是否存在。
#[inline]
pub fn has_material(&self, material_id: u32) -> bool {
self.materials.contains_key(&material_id)
}
/// Remove a material.
/// 移除材质。
///
/// Note: Cannot remove built-in materials (ID < 100).
/// 注意无法移除内置材质ID < 100
pub fn remove_material(&mut self, material_id: u32) -> bool {
if material_id < 100 {
log::warn!("Cannot remove built-in material: {} | 无法移除内置材质: {}", material_id, material_id);
return false;
}
self.materials.remove(&material_id).is_some()
}
/// Update a material's uniform value.
/// 更新材质的uniform值。
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
if let Some(material) = self.materials.get_mut(&material_id) {
material.uniforms.set_float(name, value);
true
} else {
false
}
}
/// Update a material's vec4 uniform.
/// 更新材质的vec4 uniform。
pub fn set_material_vec4(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32, w: f32) -> bool {
if let Some(material) = self.materials.get_mut(&material_id) {
material.uniforms.set_vec4(name, x, y, z, w);
true
} else {
false
}
}
/// Apply blend mode to WebGL context.
/// 将混合模式应用到WebGL上下文。
pub fn apply_blend_mode(gl: &WebGl2RenderingContext, blend_mode: BlendMode) {
match blend_mode {
BlendMode::None => {
gl.disable(WebGl2RenderingContext::BLEND);
}
BlendMode::Alpha => {
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
);
}
BlendMode::Additive => {
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
);
}
BlendMode::Multiply => {
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func(
WebGl2RenderingContext::DST_COLOR,
WebGl2RenderingContext::ZERO,
);
}
BlendMode::Screen => {
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func(
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE_MINUS_SRC_COLOR,
);
}
BlendMode::PremultipliedAlpha => {
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func(
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
);
}
}
}
/// Get all material IDs.
/// 获取所有材质ID。
pub fn material_ids(&self) -> Vec<u32> {
self.materials.keys().copied().collect()
}
/// Get material count.
/// 获取材质数量。
#[inline]
pub fn material_count(&self) -> usize {
self.materials.len()
}
}
impl Default for MaterialManager {
fn default() -> Self {
Self::new()
}
}

View File

@@ -0,0 +1,177 @@
//! Material definition and properties.
//! 材质定义和属性。
use super::uniform::MaterialUniforms;
/// Blend modes for material rendering.
/// 材质渲染的混合模式。
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum BlendMode {
/// No blending, fully opaque | 无混合,完全不透明
None,
/// Standard alpha blending | 标准透明度混合
#[default]
Alpha,
/// Additive blending (good for glow effects) | 加法混合(适用于发光效果)
Additive,
/// Multiplicative blending (good for shadows) | 乘法混合(适用于阴影)
Multiply,
/// Screen blending (opposite of multiply) | 滤色混合(与乘法相反)
Screen,
/// Premultiplied alpha | 预乘透明度
PremultipliedAlpha,
}
/// Cull modes for material rendering.
/// 材质渲染的剔除模式。
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum CullMode {
/// No face culling | 不剔除
#[default]
None,
/// Cull front faces | 剔除正面
Front,
/// Cull back faces | 剔除背面
Back,
}
/// Material definition for 2D rendering.
/// 2D渲染的材质定义。
///
/// A material combines a shader program with uniform parameters and render states.
/// 材质将着色器程序与uniform参数和渲染状态组合在一起。
#[derive(Clone, Debug)]
pub struct Material {
/// Shader program ID | 着色器程序ID
pub shader_id: u32,
/// Material uniform parameters | 材质uniform参数
pub uniforms: MaterialUniforms,
/// Blend mode | 混合模式
pub blend_mode: BlendMode,
/// Cull mode | 剔除模式
pub cull_mode: CullMode,
/// Depth test enabled | 是否启用深度测试
pub depth_test: bool,
/// Depth write enabled | 是否启用深度写入
pub depth_write: bool,
/// Material name (for debugging) | 材质名称(用于调试)
pub name: String,
}
impl Default for Material {
fn default() -> Self {
Self {
shader_id: 0, // Default sprite shader
uniforms: MaterialUniforms::new(),
blend_mode: BlendMode::Alpha,
cull_mode: CullMode::None,
depth_test: false,
depth_write: false,
name: "Default".to_string(),
}
}
}
impl Material {
/// Create a new material with default settings.
/// 使用默认设置创建新材质。
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
..Default::default()
}
}
/// Create a material with a specific shader.
/// 使用特定着色器创建材质。
pub fn with_shader(name: &str, shader_id: u32) -> Self {
Self {
name: name.to_string(),
shader_id,
..Default::default()
}
}
/// Set the blend mode.
/// 设置混合模式。
pub fn set_blend_mode(&mut self, mode: BlendMode) -> &mut Self {
self.blend_mode = mode;
self
}
/// Set a float uniform.
/// 设置浮点uniform。
pub fn set_float(&mut self, name: &str, value: f32) -> &mut Self {
self.uniforms.set_float(name, value);
self
}
/// Set a vec2 uniform.
/// 设置vec2 uniform。
pub fn set_vec2(&mut self, name: &str, x: f32, y: f32) -> &mut Self {
self.uniforms.set_vec2(name, x, y);
self
}
/// Set a vec3 uniform.
/// 设置vec3 uniform。
pub fn set_vec3(&mut self, name: &str, x: f32, y: f32, z: f32) -> &mut Self {
self.uniforms.set_vec3(name, x, y, z);
self
}
/// Set a vec4 uniform.
/// 设置vec4 uniform。
pub fn set_vec4(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) -> &mut Self {
self.uniforms.set_vec4(name, x, y, z, w);
self
}
/// Set a color uniform (RGBA, 0.0-1.0).
/// 设置颜色uniformRGBA0.0-1.0)。
pub fn set_color(&mut self, name: &str, r: f32, g: f32, b: f32, a: f32) -> &mut Self {
self.uniforms.set_color(name, r, g, b, a);
self
}
}
// ============= Built-in material presets =============
// ============= 内置材质预设 =============
impl Material {
/// Create a standard sprite material.
/// 创建标准精灵材质。
pub fn sprite() -> Self {
Self::new("Sprite")
}
/// Create an additive (glow) material.
/// 创建加法(发光)材质。
pub fn additive() -> Self {
let mut mat = Self::new("Additive");
mat.blend_mode = BlendMode::Additive;
mat
}
/// Create a multiply (shadow) material.
/// 创建乘法(阴影)材质。
pub fn multiply() -> Self {
let mut mat = Self::new("Multiply");
mat.blend_mode = BlendMode::Multiply;
mat
}
/// Create an unlit/opaque material.
/// 创建无光照/不透明材质。
pub fn unlit() -> Self {
let mut mat = Self::new("Unlit");
mat.blend_mode = BlendMode::None;
mat
}
}

View File

@@ -0,0 +1,10 @@
//! Material system for 2D rendering.
//! 2D渲染的材质系统。
mod material;
mod manager;
mod uniform;
pub use material::{Material, BlendMode, CullMode};
pub use manager::MaterialManager;
pub use uniform::{UniformValue, MaterialUniforms};

View File

@@ -0,0 +1,185 @@
//! Material uniform values and types.
//! 材质uniform值和类型。
use std::collections::HashMap;
use web_sys::{WebGl2RenderingContext, WebGlUniformLocation};
use crate::renderer::shader::ShaderProgram;
/// Uniform value types supported by the material system.
/// 材质系统支持的uniform值类型。
#[derive(Clone, Debug)]
pub enum UniformValue {
/// Single float value | 单精度浮点值
Float(f32),
/// Two component vector | 二维向量
Vec2([f32; 2]),
/// Three component vector | 三维向量
Vec3([f32; 3]),
/// Four component vector (also used for colors) | 四维向量(也用于颜色)
Vec4([f32; 4]),
/// Single integer value | 整数值
Int(i32),
/// 3x3 matrix | 3x3矩阵
Mat3([f32; 9]),
/// 4x4 matrix | 4x4矩阵
Mat4([f32; 16]),
/// Texture sampler slot | 纹理采样器槽位
Sampler(i32),
}
impl UniformValue {
/// Apply this uniform value to a shader.
/// 将此uniform值应用到着色器。
pub fn apply(&self, gl: &WebGl2RenderingContext, location: &WebGlUniformLocation) {
match self {
UniformValue::Float(v) => {
gl.uniform1f(Some(location), *v);
}
UniformValue::Vec2(v) => {
gl.uniform2f(Some(location), v[0], v[1]);
}
UniformValue::Vec3(v) => {
gl.uniform3f(Some(location), v[0], v[1], v[2]);
}
UniformValue::Vec4(v) => {
gl.uniform4f(Some(location), v[0], v[1], v[2], v[3]);
}
UniformValue::Int(v) => {
gl.uniform1i(Some(location), *v);
}
UniformValue::Mat3(v) => {
gl.uniform_matrix3fv_with_f32_array(Some(location), false, v);
}
UniformValue::Mat4(v) => {
gl.uniform_matrix4fv_with_f32_array(Some(location), false, v);
}
UniformValue::Sampler(slot) => {
gl.uniform1i(Some(location), *slot);
}
}
}
}
/// Collection of material uniform values.
/// 材质uniform值集合。
#[derive(Clone, Debug, Default)]
pub struct MaterialUniforms {
/// Named uniform values | 命名的uniform值
values: HashMap<String, UniformValue>,
}
impl MaterialUniforms {
/// Create empty uniforms collection.
/// 创建空的uniform集合。
pub fn new() -> Self {
Self {
values: HashMap::new(),
}
}
/// Set a uniform value.
/// 设置uniform值。
pub fn set(&mut self, name: &str, value: UniformValue) {
self.values.insert(name.to_string(), value);
}
/// Get a uniform value.
/// 获取uniform值。
pub fn get(&self, name: &str) -> Option<&UniformValue> {
self.values.get(name)
}
/// Remove a uniform value.
/// 移除uniform值。
pub fn remove(&mut self, name: &str) -> Option<UniformValue> {
self.values.remove(name)
}
/// Check if a uniform exists.
/// 检查uniform是否存在。
pub fn has(&self, name: &str) -> bool {
self.values.contains_key(name)
}
/// Apply all uniforms to a shader program.
/// 将所有uniform应用到着色器程序。
pub fn apply_to_shader(&self, gl: &WebGl2RenderingContext, shader: &ShaderProgram) {
for (name, value) in &self.values {
if let Some(location) = shader.get_uniform_location(gl, name) {
value.apply(gl, &location);
}
}
}
/// Get all uniform names.
/// 获取所有uniform名称。
pub fn names(&self) -> Vec<&String> {
self.values.keys().collect()
}
/// Clear all uniforms.
/// 清除所有uniform。
pub fn clear(&mut self) {
self.values.clear();
}
/// Get uniform count.
/// 获取uniform数量。
pub fn len(&self) -> usize {
self.values.len()
}
/// Check if empty.
/// 检查是否为空。
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
// ============= Convenience setters =============
// ============= 便捷设置方法 =============
impl MaterialUniforms {
/// Set a float uniform.
/// 设置浮点uniform。
pub fn set_float(&mut self, name: &str, value: f32) {
self.set(name, UniformValue::Float(value));
}
/// Set a vec2 uniform.
/// 设置vec2 uniform。
pub fn set_vec2(&mut self, name: &str, x: f32, y: f32) {
self.set(name, UniformValue::Vec2([x, y]));
}
/// Set a vec3 uniform.
/// 设置vec3 uniform。
pub fn set_vec3(&mut self, name: &str, x: f32, y: f32, z: f32) {
self.set(name, UniformValue::Vec3([x, y, z]));
}
/// Set a vec4 uniform (also used for colors).
/// 设置vec4 uniform也用于颜色
pub fn set_vec4(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) {
self.set(name, UniformValue::Vec4([x, y, z, w]));
}
/// Set a color uniform (RGBA, 0.0-1.0).
/// 设置颜色uniformRGBA0.0-1.0)。
pub fn set_color(&mut self, name: &str, r: f32, g: f32, b: f32, a: f32) {
self.set(name, UniformValue::Vec4([r, g, b, a]));
}
/// Set an integer uniform.
/// 设置整数uniform。
pub fn set_int(&mut self, name: &str, value: i32) {
self.set(name, UniformValue::Int(value));
}
/// Set a texture sampler uniform.
/// 设置纹理采样器uniform。
pub fn set_sampler(&mut self, name: &str, slot: i32) {
self.set(name, UniformValue::Sampler(slot));
}
}