feat(engine): 添加材质系统和着色器管理
This commit is contained in:
207
packages/engine/src/renderer/material/manager.rs
Normal file
207
packages/engine/src/renderer/material/manager.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
177
packages/engine/src/renderer/material/material.rs
Normal file
177
packages/engine/src/renderer/material/material.rs
Normal 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).
|
||||
/// 设置颜色uniform(RGBA,0.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
|
||||
}
|
||||
}
|
||||
10
packages/engine/src/renderer/material/mod.rs
Normal file
10
packages/engine/src/renderer/material/mod.rs
Normal 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};
|
||||
185
packages/engine/src/renderer/material/uniform.rs
Normal file
185
packages/engine/src/renderer/material/uniform.rs
Normal 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).
|
||||
/// 设置颜色uniform(RGBA,0.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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user