feat(engine): 添加材质系统和着色器管理
This commit is contained in:
@@ -185,6 +185,7 @@ impl Engine {
|
|||||||
texture_ids: &[u32],
|
texture_ids: &[u32],
|
||||||
uvs: &[f32],
|
uvs: &[f32],
|
||||||
colors: &[u32],
|
colors: &[u32],
|
||||||
|
material_ids: &[u32],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Debug: log once
|
// Debug: log once
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@@ -199,6 +200,7 @@ impl Engine {
|
|||||||
texture_ids,
|
texture_ids,
|
||||||
uvs,
|
uvs,
|
||||||
colors,
|
colors,
|
||||||
|
material_ids,
|
||||||
&self.texture_manager,
|
&self.texture_manager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -533,4 +535,176 @@ impl Engine {
|
|||||||
pub fn viewport_ids(&self) -> Vec<String> {
|
pub fn viewport_ids(&self) -> Vec<String> {
|
||||||
self.viewport_manager.viewport_ids().into_iter().cloned().collect()
|
self.viewport_manager.viewport_ids().into_iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Shader Management =====
|
||||||
|
// ===== 着色器管理 =====
|
||||||
|
|
||||||
|
/// Compile and register a custom shader.
|
||||||
|
/// 编译并注册自定义着色器。
|
||||||
|
pub fn compile_shader(
|
||||||
|
&mut self,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<u32> {
|
||||||
|
self.renderer.compile_shader(self.context.gl(), vertex_source, fragment_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile a shader with a specific ID.
|
||||||
|
/// 使用特定ID编译着色器。
|
||||||
|
pub fn compile_shader_with_id(
|
||||||
|
&mut self,
|
||||||
|
shader_id: u32,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.renderer.compile_shader_with_id(self.context.gl(), shader_id, vertex_source, fragment_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a shader exists.
|
||||||
|
/// 检查着色器是否存在。
|
||||||
|
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||||
|
self.renderer.has_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a shader.
|
||||||
|
/// 移除着色器。
|
||||||
|
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||||
|
self.renderer.remove_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Material Management =====
|
||||||
|
// ===== 材质管理 =====
|
||||||
|
|
||||||
|
/// Create and register a new material.
|
||||||
|
/// 创建并注册新材质。
|
||||||
|
pub fn create_material(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
shader_id: u32,
|
||||||
|
blend_mode: u8,
|
||||||
|
) -> u32 {
|
||||||
|
use crate::renderer::material::{Material, BlendMode};
|
||||||
|
|
||||||
|
let blend = match blend_mode {
|
||||||
|
0 => BlendMode::None,
|
||||||
|
1 => BlendMode::Alpha,
|
||||||
|
2 => BlendMode::Additive,
|
||||||
|
3 => BlendMode::Multiply,
|
||||||
|
4 => BlendMode::Screen,
|
||||||
|
5 => BlendMode::PremultipliedAlpha,
|
||||||
|
_ => BlendMode::Alpha,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut material = Material::with_shader(name, shader_id);
|
||||||
|
material.blend_mode = blend;
|
||||||
|
|
||||||
|
self.renderer.register_material(material)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a material with a specific ID.
|
||||||
|
/// 使用特定ID创建材质。
|
||||||
|
pub fn create_material_with_id(
|
||||||
|
&mut self,
|
||||||
|
material_id: u32,
|
||||||
|
name: &str,
|
||||||
|
shader_id: u32,
|
||||||
|
blend_mode: u8,
|
||||||
|
) {
|
||||||
|
use crate::renderer::material::{Material, BlendMode};
|
||||||
|
|
||||||
|
let blend = match blend_mode {
|
||||||
|
0 => BlendMode::None,
|
||||||
|
1 => BlendMode::Alpha,
|
||||||
|
2 => BlendMode::Additive,
|
||||||
|
3 => BlendMode::Multiply,
|
||||||
|
4 => BlendMode::Screen,
|
||||||
|
5 => BlendMode::PremultipliedAlpha,
|
||||||
|
_ => BlendMode::Alpha,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut material = Material::with_shader(name, shader_id);
|
||||||
|
material.blend_mode = blend;
|
||||||
|
|
||||||
|
self.renderer.register_material_with_id(material_id, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a material exists.
|
||||||
|
/// 检查材质是否存在。
|
||||||
|
pub fn has_material(&self, material_id: u32) -> bool {
|
||||||
|
self.renderer.has_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a material.
|
||||||
|
/// 移除材质。
|
||||||
|
pub fn remove_material(&mut self, material_id: u32) -> bool {
|
||||||
|
self.renderer.remove_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's float uniform.
|
||||||
|
/// 设置材质的浮点uniform。
|
||||||
|
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
|
||||||
|
self.renderer.set_material_float(material_id, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's vec2 uniform.
|
||||||
|
/// 设置材质的vec2 uniform。
|
||||||
|
pub fn set_material_vec2(&mut self, material_id: u32, name: &str, x: f32, y: f32) -> bool {
|
||||||
|
if let Some(material) = self.renderer.get_material_mut(material_id) {
|
||||||
|
material.uniforms.set_vec2(name, x, y);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's vec3 uniform.
|
||||||
|
/// 设置材质的vec3 uniform。
|
||||||
|
pub fn set_material_vec3(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32) -> bool {
|
||||||
|
if let Some(material) = self.renderer.get_material_mut(material_id) {
|
||||||
|
material.uniforms.set_vec3(name, x, y, z);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set 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 {
|
||||||
|
self.renderer.set_material_vec4(material_id, name, x, y, z, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's color uniform.
|
||||||
|
/// 设置材质的颜色uniform。
|
||||||
|
pub fn set_material_color(&mut self, material_id: u32, name: &str, r: f32, g: f32, b: f32, a: f32) -> bool {
|
||||||
|
if let Some(material) = self.renderer.get_material_mut(material_id) {
|
||||||
|
material.uniforms.set_color(name, r, g, b, a);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's blend mode.
|
||||||
|
/// 设置材质的混合模式。
|
||||||
|
pub fn set_material_blend_mode(&mut self, material_id: u32, blend_mode: u8) -> bool {
|
||||||
|
use crate::renderer::material::BlendMode;
|
||||||
|
|
||||||
|
let blend = match blend_mode {
|
||||||
|
0 => BlendMode::None,
|
||||||
|
1 => BlendMode::Alpha,
|
||||||
|
2 => BlendMode::Additive,
|
||||||
|
3 => BlendMode::Multiply,
|
||||||
|
4 => BlendMode::Screen,
|
||||||
|
5 => BlendMode::PremultipliedAlpha,
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(material) = self.renderer.get_material_mut(material_id) {
|
||||||
|
material.blend_mode = blend;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ impl GameEngine {
|
|||||||
/// * `texture_ids` - Uint32Array of texture IDs | 纹理ID数组
|
/// * `texture_ids` - Uint32Array of texture IDs | 纹理ID数组
|
||||||
/// * `uvs` - Float32Array [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
/// * `uvs` - Float32Array [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
||||||
/// * `colors` - Uint32Array of packed RGBA colors | 打包的RGBA颜色数组
|
/// * `colors` - Uint32Array of packed RGBA colors | 打包的RGBA颜色数组
|
||||||
|
/// * `material_ids` - Uint32Array of material IDs (0 = default) | 材质ID数组(0 = 默认)
|
||||||
#[wasm_bindgen(js_name = submitSpriteBatch)]
|
#[wasm_bindgen(js_name = submitSpriteBatch)]
|
||||||
pub fn submit_sprite_batch(
|
pub fn submit_sprite_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -149,9 +150,10 @@ impl GameEngine {
|
|||||||
texture_ids: &[u32],
|
texture_ids: &[u32],
|
||||||
uvs: &[f32],
|
uvs: &[f32],
|
||||||
colors: &[u32],
|
colors: &[u32],
|
||||||
|
material_ids: &[u32],
|
||||||
) -> std::result::Result<(), JsValue> {
|
) -> std::result::Result<(), JsValue> {
|
||||||
self.engine
|
self.engine
|
||||||
.submit_sprite_batch(transforms, texture_ids, uvs, colors)
|
.submit_sprite_batch(transforms, texture_ids, uvs, colors, material_ids)
|
||||||
.map_err(|e| JsValue::from_str(&e.to_string()))
|
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,4 +465,150 @@ impl GameEngine {
|
|||||||
pub fn get_viewport_ids(&self) -> Vec<String> {
|
pub fn get_viewport_ids(&self) -> Vec<String> {
|
||||||
self.engine.viewport_ids()
|
self.engine.viewport_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== Shader API =====
|
||||||
|
// ===== 着色器 API =====
|
||||||
|
|
||||||
|
/// Compile and register a custom shader.
|
||||||
|
/// 编译并注册自定义着色器。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||||
|
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||||
|
///
|
||||||
|
/// # Returns | 返回
|
||||||
|
/// The shader ID for referencing this shader | 用于引用此着色器的ID
|
||||||
|
#[wasm_bindgen(js_name = compileShader)]
|
||||||
|
pub fn compile_shader(
|
||||||
|
&mut self,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> std::result::Result<u32, JsValue> {
|
||||||
|
self.engine
|
||||||
|
.compile_shader(vertex_source, fragment_source)
|
||||||
|
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile a shader with a specific ID.
|
||||||
|
/// 使用特定ID编译着色器。
|
||||||
|
#[wasm_bindgen(js_name = compileShaderWithId)]
|
||||||
|
pub fn compile_shader_with_id(
|
||||||
|
&mut self,
|
||||||
|
shader_id: u32,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> std::result::Result<(), JsValue> {
|
||||||
|
self.engine
|
||||||
|
.compile_shader_with_id(shader_id, vertex_source, fragment_source)
|
||||||
|
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a shader exists.
|
||||||
|
/// 检查着色器是否存在。
|
||||||
|
#[wasm_bindgen(js_name = hasShader)]
|
||||||
|
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||||
|
self.engine.has_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a shader.
|
||||||
|
/// 移除着色器。
|
||||||
|
#[wasm_bindgen(js_name = removeShader)]
|
||||||
|
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||||
|
self.engine.remove_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Material API =====
|
||||||
|
// ===== 材质 API =====
|
||||||
|
|
||||||
|
/// Create and register a new material.
|
||||||
|
/// 创建并注册新材质。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `name` - Material name for debugging | 材质名称(用于调试)
|
||||||
|
/// * `shader_id` - Shader ID to use | 使用的着色器ID
|
||||||
|
/// * `blend_mode` - Blend mode: 0=None, 1=Alpha, 2=Additive, 3=Multiply, 4=Screen, 5=PremultipliedAlpha
|
||||||
|
///
|
||||||
|
/// # Returns | 返回
|
||||||
|
/// The material ID for referencing this material | 用于引用此材质的ID
|
||||||
|
#[wasm_bindgen(js_name = createMaterial)]
|
||||||
|
pub fn create_material(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
shader_id: u32,
|
||||||
|
blend_mode: u8,
|
||||||
|
) -> u32 {
|
||||||
|
self.engine.create_material(name, shader_id, blend_mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a material with a specific ID.
|
||||||
|
/// 使用特定ID创建材质。
|
||||||
|
#[wasm_bindgen(js_name = createMaterialWithId)]
|
||||||
|
pub fn create_material_with_id(
|
||||||
|
&mut self,
|
||||||
|
material_id: u32,
|
||||||
|
name: &str,
|
||||||
|
shader_id: u32,
|
||||||
|
blend_mode: u8,
|
||||||
|
) {
|
||||||
|
self.engine.create_material_with_id(material_id, name, shader_id, blend_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a material exists.
|
||||||
|
/// 检查材质是否存在。
|
||||||
|
#[wasm_bindgen(js_name = hasMaterial)]
|
||||||
|
pub fn has_material(&self, material_id: u32) -> bool {
|
||||||
|
self.engine.has_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a material.
|
||||||
|
/// 移除材质。
|
||||||
|
#[wasm_bindgen(js_name = removeMaterial)]
|
||||||
|
pub fn remove_material(&mut self, material_id: u32) -> bool {
|
||||||
|
self.engine.remove_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's float uniform.
|
||||||
|
/// 设置材质的浮点uniform。
|
||||||
|
#[wasm_bindgen(js_name = setMaterialFloat)]
|
||||||
|
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
|
||||||
|
self.engine.set_material_float(material_id, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's vec2 uniform.
|
||||||
|
/// 设置材质的vec2 uniform。
|
||||||
|
#[wasm_bindgen(js_name = setMaterialVec2)]
|
||||||
|
pub fn set_material_vec2(&mut self, material_id: u32, name: &str, x: f32, y: f32) -> bool {
|
||||||
|
self.engine.set_material_vec2(material_id, name, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's vec3 uniform.
|
||||||
|
/// 设置材质的vec3 uniform。
|
||||||
|
#[wasm_bindgen(js_name = setMaterialVec3)]
|
||||||
|
pub fn set_material_vec3(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32) -> bool {
|
||||||
|
self.engine.set_material_vec3(material_id, name, x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's vec4 uniform (also used for colors).
|
||||||
|
/// 设置材质的vec4 uniform(也用于颜色)。
|
||||||
|
#[wasm_bindgen(js_name = setMaterialVec4)]
|
||||||
|
pub fn set_material_vec4(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32, w: f32) -> bool {
|
||||||
|
self.engine.set_material_vec4(material_id, name, x, y, z, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's color uniform (RGBA, 0.0-1.0).
|
||||||
|
/// 设置材质的颜色uniform(RGBA,0.0-1.0)。
|
||||||
|
#[wasm_bindgen(js_name = setMaterialColor)]
|
||||||
|
pub fn set_material_color(&mut self, material_id: u32, name: &str, r: f32, g: f32, b: f32, a: f32) -> bool {
|
||||||
|
self.engine.set_material_color(material_id, name, r, g, b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's blend mode.
|
||||||
|
/// 设置材质的混合模式。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `blend_mode` - 0=None, 1=Alpha, 2=Additive, 3=Multiply, 4=Screen, 5=PremultipliedAlpha
|
||||||
|
#[wasm_bindgen(js_name = setMaterialBlendMode)]
|
||||||
|
pub fn set_material_blend_mode(&mut self, material_id: u32, blend_mode: u8) -> bool {
|
||||||
|
self.engine.set_material_blend_mode(material_id, blend_mode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
mod sprite_batch;
|
mod sprite_batch;
|
||||||
mod vertex;
|
mod vertex;
|
||||||
|
|
||||||
pub use sprite_batch::SpriteBatch;
|
pub use sprite_batch::{BatchKey, SpriteBatch};
|
||||||
pub use vertex::{SpriteVertex, VERTEX_SIZE};
|
pub use vertex::{SpriteVertex, VERTEX_SIZE};
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ const TRANSFORM_STRIDE: usize = 7;
|
|||||||
/// UV数据步长。
|
/// UV数据步长。
|
||||||
const UV_STRIDE: usize = 4;
|
const UV_STRIDE: usize = 4;
|
||||||
|
|
||||||
|
/// Batch key combining material and texture IDs.
|
||||||
|
/// 组合材质ID和纹理ID的批次键。
|
||||||
|
#[derive(Hash, Eq, PartialEq, Clone, Copy, Debug)]
|
||||||
|
pub struct BatchKey {
|
||||||
|
/// Material ID (0 = default material).
|
||||||
|
/// 材质ID(0 = 默认材质)。
|
||||||
|
pub material_id: u32,
|
||||||
|
/// Texture ID.
|
||||||
|
/// 纹理ID。
|
||||||
|
pub texture_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
/// Sprite batch renderer.
|
/// Sprite batch renderer.
|
||||||
/// 精灵批处理渲染器。
|
/// 精灵批处理渲染器。
|
||||||
///
|
///
|
||||||
@@ -35,7 +47,7 @@ const UV_STRIDE: usize = 4;
|
|||||||
///
|
///
|
||||||
/// # Performance | 性能
|
/// # Performance | 性能
|
||||||
/// - Uses dynamic vertex buffer for efficient updates | 使用动态顶点缓冲区以高效更新
|
/// - Uses dynamic vertex buffer for efficient updates | 使用动态顶点缓冲区以高效更新
|
||||||
/// - Groups sprites by texture to minimize state changes | 按纹理分组精灵以最小化状态更改
|
/// - Groups sprites by material and texture to minimize state changes | 按材质和纹理分组精灵以最小化状态更改
|
||||||
/// - Supports up to 10000+ sprites per batch | 每批次支持10000+精灵
|
/// - Supports up to 10000+ sprites per batch | 每批次支持10000+精灵
|
||||||
pub struct SpriteBatch {
|
pub struct SpriteBatch {
|
||||||
/// Vertex array object.
|
/// Vertex array object.
|
||||||
@@ -54,9 +66,9 @@ pub struct SpriteBatch {
|
|||||||
/// 最大精灵数。
|
/// 最大精灵数。
|
||||||
max_sprites: usize,
|
max_sprites: usize,
|
||||||
|
|
||||||
/// Per-texture vertex data buffers.
|
/// Per-material-texture vertex data buffers.
|
||||||
/// 按纹理分组的顶点数据缓冲区。
|
/// 按材质和纹理分组的顶点数据缓冲区。
|
||||||
texture_batches: HashMap<u32, Vec<f32>>,
|
batches: HashMap<BatchKey, Vec<f32>>,
|
||||||
|
|
||||||
/// Total sprite count across all batches.
|
/// Total sprite count across all batches.
|
||||||
/// 所有批次的总精灵数。
|
/// 所有批次的总精灵数。
|
||||||
@@ -124,7 +136,7 @@ impl SpriteBatch {
|
|||||||
vbo,
|
vbo,
|
||||||
ibo,
|
ibo,
|
||||||
max_sprites,
|
max_sprites,
|
||||||
texture_batches: HashMap::new(),
|
batches: HashMap::new(),
|
||||||
sprite_count: 0,
|
sprite_count: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -192,7 +204,7 @@ impl SpriteBatch {
|
|||||||
/// Clear the batch for a new frame.
|
/// Clear the batch for a new frame.
|
||||||
/// 为新帧清空批处理。
|
/// 为新帧清空批处理。
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
for batch in self.texture_batches.values_mut() {
|
for batch in self.batches.values_mut() {
|
||||||
batch.clear();
|
batch.clear();
|
||||||
}
|
}
|
||||||
self.sprite_count = 0;
|
self.sprite_count = 0;
|
||||||
@@ -206,6 +218,7 @@ impl SpriteBatch {
|
|||||||
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
|
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
|
||||||
/// * `uvs` - [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
/// * `uvs` - [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
||||||
/// * `colors` - Packed RGBA color per sprite | 每个精灵的打包RGBA颜色
|
/// * `colors` - Packed RGBA color per sprite | 每个精灵的打包RGBA颜色
|
||||||
|
/// * `material_ids` - Material ID for each sprite (0 = default) | 每个精灵的材质ID(0 = 默认)
|
||||||
/// * `_texture_manager` - Texture manager for getting texture sizes | 纹理管理器
|
/// * `_texture_manager` - Texture manager for getting texture sizes | 纹理管理器
|
||||||
pub fn add_sprites(
|
pub fn add_sprites(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -213,6 +226,7 @@ impl SpriteBatch {
|
|||||||
texture_ids: &[u32],
|
texture_ids: &[u32],
|
||||||
uvs: &[f32],
|
uvs: &[f32],
|
||||||
colors: &[u32],
|
colors: &[u32],
|
||||||
|
material_ids: &[u32],
|
||||||
_texture_manager: &TextureManager,
|
_texture_manager: &TextureManager,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let sprite_count = texture_ids.len();
|
let sprite_count = texture_ids.len();
|
||||||
@@ -242,6 +256,14 @@ impl SpriteBatch {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if material_ids.len() != sprite_count {
|
||||||
|
return Err(EngineError::InvalidBatchData(format!(
|
||||||
|
"Material ID data length mismatch: expected {}, got {}",
|
||||||
|
sprite_count,
|
||||||
|
material_ids.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
// Check capacity | 检查容量
|
// Check capacity | 检查容量
|
||||||
if self.sprite_count + sprite_count > self.max_sprites {
|
if self.sprite_count + sprite_count > self.max_sprites {
|
||||||
return Err(EngineError::InvalidBatchData(format!(
|
return Err(EngineError::InvalidBatchData(format!(
|
||||||
@@ -250,7 +272,7 @@ impl SpriteBatch {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add each sprite grouped by texture | 按纹理分组添加每个精灵
|
// Add each sprite grouped by material and texture | 按材质和纹理分组添加每个精灵
|
||||||
for i in 0..sprite_count {
|
for i in 0..sprite_count {
|
||||||
let t_offset = i * TRANSFORM_STRIDE;
|
let t_offset = i * TRANSFORM_STRIDE;
|
||||||
let uv_offset = i * UV_STRIDE;
|
let uv_offset = i * UV_STRIDE;
|
||||||
@@ -276,11 +298,14 @@ impl SpriteBatch {
|
|||||||
let width = scale_x;
|
let width = scale_x;
|
||||||
let height = scale_y;
|
let height = scale_y;
|
||||||
|
|
||||||
let texture_id = texture_ids[i];
|
let batch_key = BatchKey {
|
||||||
|
material_id: material_ids[i],
|
||||||
|
texture_id: texture_ids[i],
|
||||||
|
};
|
||||||
|
|
||||||
// Get or create batch for this texture | 获取或创建此纹理的批次
|
// Get or create batch for this material+texture combination | 获取或创建此材质+纹理组合的批次
|
||||||
let batch = self.texture_batches
|
let batch = self.batches
|
||||||
.entry(texture_id)
|
.entry(batch_key)
|
||||||
.or_insert_with(Vec::new);
|
.or_insert_with(Vec::new);
|
||||||
|
|
||||||
// Calculate transformed vertices and add to batch | 计算变换后的顶点并添加到批次
|
// Calculate transformed vertices and add to batch | 计算变换后的顶点并添加到批次
|
||||||
@@ -367,9 +392,9 @@ impl SpriteBatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flush a specific texture batch to GPU and render.
|
/// Flush a batch to GPU and render.
|
||||||
/// 将特定纹理批次刷新到GPU并渲染。
|
/// 将批次刷新到GPU并渲染。
|
||||||
fn flush_texture_batch(&self, gl: &WebGl2RenderingContext, vertices: &[f32]) {
|
fn flush_batch(&self, gl: &WebGl2RenderingContext, vertices: &[f32]) {
|
||||||
if vertices.is_empty() {
|
if vertices.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -403,17 +428,17 @@ impl SpriteBatch {
|
|||||||
gl.bind_vertex_array(None);
|
gl.bind_vertex_array(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get texture batches for rendering.
|
/// Get all batches for rendering.
|
||||||
/// 获取用于渲染的纹理批次。
|
/// 获取所有批次用于渲染。
|
||||||
pub fn texture_batches(&self) -> &HashMap<u32, Vec<f32>> {
|
pub fn batches(&self) -> &HashMap<BatchKey, Vec<f32>> {
|
||||||
&self.texture_batches
|
&self.batches
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flush a specific texture batch.
|
/// Flush a specific batch by key.
|
||||||
/// 刷新特定纹理批次。
|
/// 按键刷新特定批次。
|
||||||
pub fn flush_for_texture(&self, gl: &WebGl2RenderingContext, texture_id: u32) {
|
pub fn flush_for_batch(&self, gl: &WebGl2RenderingContext, key: &BatchKey) {
|
||||||
if let Some(vertices) = self.texture_batches.get(&texture_id) {
|
if let Some(vertices) = self.batches.get(key) {
|
||||||
self.flush_texture_batch(gl, vertices);
|
self.flush_batch(gl, vertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
pub mod batch;
|
pub mod batch;
|
||||||
pub mod shader;
|
pub mod shader;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
pub mod material;
|
||||||
|
|
||||||
mod renderer2d;
|
mod renderer2d;
|
||||||
mod camera;
|
mod camera;
|
||||||
@@ -18,3 +19,5 @@ pub use texture::{Texture, TextureManager};
|
|||||||
pub use grid::GridRenderer;
|
pub use grid::GridRenderer;
|
||||||
pub use gizmo::{GizmoRenderer, TransformMode};
|
pub use gizmo::{GizmoRenderer, TransformMode};
|
||||||
pub use viewport::{RenderTarget, ViewportManager, ViewportConfig};
|
pub use viewport::{RenderTarget, ViewportManager, ViewportConfig};
|
||||||
|
pub use shader::{ShaderManager, ShaderProgram, SHADER_ID_DEFAULT_SPRITE};
|
||||||
|
pub use material::{Material, MaterialManager, BlendMode, CullMode, UniformValue, MaterialUniforms};
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ use crate::core::error::Result;
|
|||||||
use crate::resource::TextureManager;
|
use crate::resource::TextureManager;
|
||||||
use super::batch::SpriteBatch;
|
use super::batch::SpriteBatch;
|
||||||
use super::camera::Camera2D;
|
use super::camera::Camera2D;
|
||||||
use super::shader::{ShaderProgram, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
use super::shader::ShaderManager;
|
||||||
|
use super::material::MaterialManager;
|
||||||
|
|
||||||
/// 2D renderer with batched sprite rendering.
|
/// 2D renderer with batched sprite rendering.
|
||||||
/// 带批处理精灵渲染的2D渲染器。
|
/// 带批处理精灵渲染的2D渲染器。
|
||||||
@@ -20,9 +21,13 @@ pub struct Renderer2D {
|
|||||||
/// 精灵批处理渲染器。
|
/// 精灵批处理渲染器。
|
||||||
sprite_batch: SpriteBatch,
|
sprite_batch: SpriteBatch,
|
||||||
|
|
||||||
/// Sprite shader program.
|
/// Shader manager.
|
||||||
/// 精灵Shader程序。
|
/// 着色器管理器。
|
||||||
shader: ShaderProgram,
|
shader_manager: ShaderManager,
|
||||||
|
|
||||||
|
/// Material manager.
|
||||||
|
/// 材质管理器。
|
||||||
|
material_manager: MaterialManager,
|
||||||
|
|
||||||
/// 2D camera.
|
/// 2D camera.
|
||||||
/// 2D相机。
|
/// 2D相机。
|
||||||
@@ -31,6 +36,16 @@ pub struct Renderer2D {
|
|||||||
/// Clear color (RGBA).
|
/// Clear color (RGBA).
|
||||||
/// 清除颜色 (RGBA)。
|
/// 清除颜色 (RGBA)。
|
||||||
clear_color: [f32; 4],
|
clear_color: [f32; 4],
|
||||||
|
|
||||||
|
/// Current active shader ID.
|
||||||
|
/// 当前激活的着色器ID。
|
||||||
|
#[allow(dead_code)]
|
||||||
|
current_shader_id: u32,
|
||||||
|
|
||||||
|
/// Current active material ID.
|
||||||
|
/// 当前激活的材质ID。
|
||||||
|
#[allow(dead_code)]
|
||||||
|
current_material_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer2D {
|
impl Renderer2D {
|
||||||
@@ -42,7 +57,8 @@ impl Renderer2D {
|
|||||||
/// * `max_sprites` - Maximum sprites per batch | 每批次最大精灵数
|
/// * `max_sprites` - Maximum sprites per batch | 每批次最大精灵数
|
||||||
pub fn new(gl: &WebGl2RenderingContext, max_sprites: usize) -> Result<Self> {
|
pub fn new(gl: &WebGl2RenderingContext, max_sprites: usize) -> Result<Self> {
|
||||||
let sprite_batch = SpriteBatch::new(gl, max_sprites)?;
|
let sprite_batch = SpriteBatch::new(gl, max_sprites)?;
|
||||||
let shader = ShaderProgram::new(gl, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER)?;
|
let shader_manager = ShaderManager::new(gl)?;
|
||||||
|
let material_manager = MaterialManager::new();
|
||||||
|
|
||||||
// Get canvas size for camera | 获取canvas尺寸用于相机
|
// Get canvas size for camera | 获取canvas尺寸用于相机
|
||||||
let canvas = gl.canvas()
|
let canvas = gl.canvas()
|
||||||
@@ -59,9 +75,12 @@ impl Renderer2D {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sprite_batch,
|
sprite_batch,
|
||||||
shader,
|
shader_manager,
|
||||||
|
material_manager,
|
||||||
camera,
|
camera,
|
||||||
clear_color: [0.1, 0.1, 0.12, 1.0],
|
clear_color: [0.1, 0.1, 0.12, 1.0],
|
||||||
|
current_shader_id: 0,
|
||||||
|
current_material_id: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +92,7 @@ impl Renderer2D {
|
|||||||
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
|
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
|
||||||
/// * `uvs` - UV coordinates for each sprite | 每个精灵的UV坐标
|
/// * `uvs` - UV coordinates for each sprite | 每个精灵的UV坐标
|
||||||
/// * `colors` - Packed color for each sprite | 每个精灵的打包颜色
|
/// * `colors` - Packed color for each sprite | 每个精灵的打包颜色
|
||||||
|
/// * `material_ids` - Material ID for each sprite (0 = default) | 每个精灵的材质ID(0 = 默认)
|
||||||
/// * `texture_manager` - Texture manager | 纹理管理器
|
/// * `texture_manager` - Texture manager | 纹理管理器
|
||||||
pub fn submit_batch(
|
pub fn submit_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -80,6 +100,7 @@ impl Renderer2D {
|
|||||||
texture_ids: &[u32],
|
texture_ids: &[u32],
|
||||||
uvs: &[f32],
|
uvs: &[f32],
|
||||||
colors: &[u32],
|
colors: &[u32],
|
||||||
|
material_ids: &[u32],
|
||||||
texture_manager: &TextureManager,
|
texture_manager: &TextureManager,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.sprite_batch.add_sprites(
|
self.sprite_batch.add_sprites(
|
||||||
@@ -87,6 +108,7 @@ impl Renderer2D {
|
|||||||
texture_ids,
|
texture_ids,
|
||||||
uvs,
|
uvs,
|
||||||
colors,
|
colors,
|
||||||
|
material_ids,
|
||||||
texture_manager,
|
texture_manager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -94,34 +116,61 @@ impl Renderer2D {
|
|||||||
/// Render the current frame.
|
/// Render the current frame.
|
||||||
/// 渲染当前帧。
|
/// 渲染当前帧。
|
||||||
pub fn render(&mut self, gl: &WebGl2RenderingContext, texture_manager: &TextureManager) -> Result<()> {
|
pub fn render(&mut self, gl: &WebGl2RenderingContext, texture_manager: &TextureManager) -> Result<()> {
|
||||||
|
use super::batch::BatchKey;
|
||||||
|
|
||||||
if self.sprite_batch.sprite_count() == 0 {
|
if self.sprite_batch.sprite_count() == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind shader | 绑定Shader
|
// Collect non-empty batch keys | 收集非空批次键
|
||||||
self.shader.bind(gl);
|
let batch_keys: Vec<BatchKey> = self.sprite_batch.batches()
|
||||||
|
|
||||||
// Set projection matrix | 设置投影矩阵
|
|
||||||
let projection = self.camera.projection_matrix();
|
|
||||||
self.shader.set_uniform_mat3(gl, "u_projection", &projection.to_cols_array());
|
|
||||||
|
|
||||||
// Set texture sampler | 设置纹理采样器
|
|
||||||
self.shader.set_uniform_i32(gl, "u_texture", 0);
|
|
||||||
|
|
||||||
// Render each texture batch | 渲染每个纹理批次
|
|
||||||
// Only collect non-empty batches | 只收集非空批次
|
|
||||||
let texture_ids: Vec<u32> = self.sprite_batch.texture_batches()
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, vertices)| !vertices.is_empty())
|
.filter(|(_, vertices)| !vertices.is_empty())
|
||||||
.map(|(id, _)| *id)
|
.map(|(key, _)| *key)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for texture_id in texture_ids {
|
// Track current state to minimize state changes | 跟踪当前状态以最小化状态切换
|
||||||
// Bind texture for this batch | 绑定此批次的纹理
|
let mut current_material_id: u32 = u32::MAX;
|
||||||
texture_manager.bind_texture(texture_id, 0);
|
let mut current_texture_id: u32 = u32::MAX;
|
||||||
|
|
||||||
// Flush this texture's sprites | 刷新此纹理的精灵
|
// Get projection matrix once | 一次性获取投影矩阵
|
||||||
self.sprite_batch.flush_for_texture(gl, texture_id);
|
let projection = self.camera.projection_matrix();
|
||||||
|
|
||||||
|
for batch_key in batch_keys {
|
||||||
|
// Switch material if needed | 如需切换材质
|
||||||
|
if batch_key.material_id != current_material_id {
|
||||||
|
current_material_id = batch_key.material_id;
|
||||||
|
|
||||||
|
// Get material (fallback to default if not found) | 获取材质(未找到则回退到默认)
|
||||||
|
let material = self.material_manager.get_material(batch_key.material_id)
|
||||||
|
.unwrap_or_else(|| self.material_manager.get_default_material());
|
||||||
|
|
||||||
|
// Bind shader | 绑定Shader
|
||||||
|
let shader = self.shader_manager.get_shader(material.shader_id)
|
||||||
|
.unwrap_or_else(|| self.shader_manager.get_default_shader());
|
||||||
|
shader.bind(gl);
|
||||||
|
|
||||||
|
// Apply blend mode | 应用混合模式
|
||||||
|
MaterialManager::apply_blend_mode(gl, material.blend_mode);
|
||||||
|
|
||||||
|
// Set projection matrix | 设置投影矩阵
|
||||||
|
shader.set_uniform_mat3(gl, "u_projection", &projection.to_cols_array());
|
||||||
|
|
||||||
|
// Set texture sampler | 设置纹理采样器
|
||||||
|
shader.set_uniform_i32(gl, "u_texture", 0);
|
||||||
|
|
||||||
|
// Apply material uniforms | 应用材质uniform
|
||||||
|
material.uniforms.apply_to_shader(gl, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch texture if needed | 如需切换纹理
|
||||||
|
if batch_key.texture_id != current_texture_id {
|
||||||
|
current_texture_id = batch_key.texture_id;
|
||||||
|
texture_manager.bind_texture(batch_key.texture_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush this batch | 刷新此批次
|
||||||
|
self.sprite_batch.flush_for_batch(gl, &batch_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear batch for next frame | 清空批处理以供下一帧使用
|
// Clear batch for next frame | 清空批处理以供下一帧使用
|
||||||
@@ -161,4 +210,123 @@ impl Renderer2D {
|
|||||||
pub fn resize(&mut self, width: f32, height: f32) {
|
pub fn resize(&mut self, width: f32, height: f32) {
|
||||||
self.camera.set_viewport(width, height);
|
self.camera.set_viewport(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============= Shader Management =============
|
||||||
|
// ============= 着色器管理 =============
|
||||||
|
|
||||||
|
/// Compile and register a custom shader.
|
||||||
|
/// 编译并注册自定义着色器。
|
||||||
|
///
|
||||||
|
/// # Returns | 返回
|
||||||
|
/// The shader ID for referencing this shader | 用于引用此着色器的ID
|
||||||
|
pub fn compile_shader(
|
||||||
|
&mut self,
|
||||||
|
gl: &WebGl2RenderingContext,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<u32> {
|
||||||
|
self.shader_manager.compile_shader(gl, vertex_source, fragment_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile a shader with a specific ID.
|
||||||
|
/// 使用特定ID编译着色器。
|
||||||
|
pub fn compile_shader_with_id(
|
||||||
|
&mut self,
|
||||||
|
gl: &WebGl2RenderingContext,
|
||||||
|
shader_id: u32,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.shader_manager.compile_shader_with_id(gl, shader_id, vertex_source, fragment_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a shader exists.
|
||||||
|
/// 检查着色器是否存在。
|
||||||
|
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||||
|
self.shader_manager.has_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a shader.
|
||||||
|
/// 移除着色器。
|
||||||
|
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||||
|
self.shader_manager.remove_shader(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get shader manager reference.
|
||||||
|
/// 获取着色器管理器引用。
|
||||||
|
pub fn shader_manager(&self) -> &ShaderManager {
|
||||||
|
&self.shader_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable shader manager reference.
|
||||||
|
/// 获取可变着色器管理器引用。
|
||||||
|
pub fn shader_manager_mut(&mut self) -> &mut ShaderManager {
|
||||||
|
&mut self.shader_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Material Management =============
|
||||||
|
// ============= 材质管理 =============
|
||||||
|
|
||||||
|
/// Register a custom material.
|
||||||
|
/// 注册自定义材质。
|
||||||
|
///
|
||||||
|
/// # Returns | 返回
|
||||||
|
/// The material ID for referencing this material | 用于引用此材质的ID
|
||||||
|
pub fn register_material(&mut self, material: super::material::Material) -> u32 {
|
||||||
|
self.material_manager.register_material(material)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a material with a specific ID.
|
||||||
|
/// 使用特定ID注册材质。
|
||||||
|
pub fn register_material_with_id(&mut self, material_id: u32, material: super::material::Material) {
|
||||||
|
self.material_manager.register_material_with_id(material_id, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a material by ID.
|
||||||
|
/// 按ID获取材质。
|
||||||
|
pub fn get_material(&self, material_id: u32) -> Option<&super::material::Material> {
|
||||||
|
self.material_manager.get_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable material by ID.
|
||||||
|
/// 按ID获取可变材质。
|
||||||
|
pub fn get_material_mut(&mut self, material_id: u32) -> Option<&mut super::material::Material> {
|
||||||
|
self.material_manager.get_material_mut(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a material exists.
|
||||||
|
/// 检查材质是否存在。
|
||||||
|
pub fn has_material(&self, material_id: u32) -> bool {
|
||||||
|
self.material_manager.has_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a material.
|
||||||
|
/// 移除材质。
|
||||||
|
pub fn remove_material(&mut self, material_id: u32) -> bool {
|
||||||
|
self.material_manager.remove_material(material_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a material's float uniform.
|
||||||
|
/// 设置材质的浮点uniform。
|
||||||
|
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
|
||||||
|
self.material_manager.set_material_float(material_id, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set 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 {
|
||||||
|
self.material_manager.set_material_vec4(material_id, name, x, y, z, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get material manager reference.
|
||||||
|
/// 获取材质管理器引用。
|
||||||
|
pub fn material_manager(&self) -> &MaterialManager {
|
||||||
|
&self.material_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable material manager reference.
|
||||||
|
/// 获取可变材质管理器引用。
|
||||||
|
pub fn material_manager_mut(&mut self) -> &mut MaterialManager {
|
||||||
|
&mut self.material_manager
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
172
packages/engine/src/renderer/shader/manager.rs
Normal file
172
packages/engine/src/renderer/shader/manager.rs
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
//! Shader manager for runtime shader compilation and caching.
|
||||||
|
//! 着色器管理器,用于运行时着色器编译和缓存。
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use web_sys::WebGl2RenderingContext;
|
||||||
|
|
||||||
|
use crate::core::error::Result;
|
||||||
|
use super::program::ShaderProgram;
|
||||||
|
use super::builtin::{SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
||||||
|
|
||||||
|
/// Reserved shader IDs for built-in shaders.
|
||||||
|
/// 内置着色器的保留ID。
|
||||||
|
pub const SHADER_ID_DEFAULT_SPRITE: u32 = 0;
|
||||||
|
|
||||||
|
/// Shader manager for compiling and caching shader programs.
|
||||||
|
/// 着色器管理器,用于编译和缓存着色器程序。
|
||||||
|
///
|
||||||
|
/// Manages multiple shader programs, allowing runtime compilation of custom shaders.
|
||||||
|
/// 管理多个着色器程序,允许运行时编译自定义着色器。
|
||||||
|
pub struct ShaderManager {
|
||||||
|
/// Compiled shader programs indexed by ID.
|
||||||
|
/// 按ID索引的已编译着色器程序。
|
||||||
|
shaders: HashMap<u32, ShaderProgram>,
|
||||||
|
|
||||||
|
/// Next available shader ID for custom shaders.
|
||||||
|
/// 下一个可用的自定义着色器ID。
|
||||||
|
next_shader_id: u32,
|
||||||
|
|
||||||
|
/// Shader source cache for hot-reloading (optional).
|
||||||
|
/// 着色器源代码缓存,用于热重载(可选)。
|
||||||
|
shader_sources: HashMap<u32, (String, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShaderManager {
|
||||||
|
/// Create a new shader manager with built-in shaders.
|
||||||
|
/// 创建带有内置着色器的新着色器管理器。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||||
|
pub fn new(gl: &WebGl2RenderingContext) -> Result<Self> {
|
||||||
|
let mut manager = Self {
|
||||||
|
shaders: HashMap::new(),
|
||||||
|
next_shader_id: 100, // Reserve 0-99 for built-in shaders
|
||||||
|
shader_sources: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compile built-in sprite shader | 编译内置精灵着色器
|
||||||
|
let default_shader = ShaderProgram::new(gl, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER)?;
|
||||||
|
manager.shaders.insert(SHADER_ID_DEFAULT_SPRITE, default_shader);
|
||||||
|
manager.shader_sources.insert(
|
||||||
|
SHADER_ID_DEFAULT_SPRITE,
|
||||||
|
(SPRITE_VERTEX_SHADER.to_string(), SPRITE_FRAGMENT_SHADER.to_string()),
|
||||||
|
);
|
||||||
|
|
||||||
|
log::info!("ShaderManager initialized with {} built-in shaders | 着色器管理器初始化完成,内置着色器数量: {}",
|
||||||
|
manager.shaders.len(), manager.shaders.len());
|
||||||
|
|
||||||
|
Ok(manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile and register a custom shader program.
|
||||||
|
/// 编译并注册自定义着色器程序。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||||
|
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||||
|
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||||
|
///
|
||||||
|
/// # Returns | 返回
|
||||||
|
/// The shader ID for referencing this shader | 用于引用此着色器的ID
|
||||||
|
pub fn compile_shader(
|
||||||
|
&mut self,
|
||||||
|
gl: &WebGl2RenderingContext,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<u32> {
|
||||||
|
let shader = ShaderProgram::new(gl, vertex_source, fragment_source)?;
|
||||||
|
let shader_id = self.next_shader_id;
|
||||||
|
self.next_shader_id += 1;
|
||||||
|
|
||||||
|
self.shaders.insert(shader_id, shader);
|
||||||
|
self.shader_sources.insert(
|
||||||
|
shader_id,
|
||||||
|
(vertex_source.to_string(), fragment_source.to_string()),
|
||||||
|
);
|
||||||
|
|
||||||
|
log::debug!("Custom shader compiled with ID: {} | 自定义着色器编译完成,ID: {}", shader_id, shader_id);
|
||||||
|
|
||||||
|
Ok(shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile and register a shader with a specific ID.
|
||||||
|
/// 使用特定ID编译并注册着色器。
|
||||||
|
///
|
||||||
|
/// # Arguments | 参数
|
||||||
|
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||||
|
/// * `shader_id` - Desired shader ID | 期望的着色器ID
|
||||||
|
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||||
|
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||||
|
pub fn compile_shader_with_id(
|
||||||
|
&mut self,
|
||||||
|
gl: &WebGl2RenderingContext,
|
||||||
|
shader_id: u32,
|
||||||
|
vertex_source: &str,
|
||||||
|
fragment_source: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let shader = ShaderProgram::new(gl, vertex_source, fragment_source)?;
|
||||||
|
|
||||||
|
// Remove old shader if exists | 如果存在则移除旧着色器
|
||||||
|
self.shaders.remove(&shader_id);
|
||||||
|
|
||||||
|
self.shaders.insert(shader_id, shader);
|
||||||
|
self.shader_sources.insert(
|
||||||
|
shader_id,
|
||||||
|
(vertex_source.to_string(), fragment_source.to_string()),
|
||||||
|
);
|
||||||
|
|
||||||
|
log::debug!("Shader compiled with ID: {} | 着色器编译完成,ID: {}", shader_id, shader_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a shader program by ID.
|
||||||
|
/// 按ID获取着色器程序。
|
||||||
|
#[inline]
|
||||||
|
pub fn get_shader(&self, shader_id: u32) -> Option<&ShaderProgram> {
|
||||||
|
self.shaders.get(&shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the default sprite shader.
|
||||||
|
/// 获取默认精灵着色器。
|
||||||
|
#[inline]
|
||||||
|
pub fn get_default_shader(&self) -> &ShaderProgram {
|
||||||
|
self.shaders.get(&SHADER_ID_DEFAULT_SPRITE)
|
||||||
|
.expect("Default shader should always exist | 默认着色器应该始终存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a shader exists.
|
||||||
|
/// 检查着色器是否存在。
|
||||||
|
#[inline]
|
||||||
|
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||||
|
self.shaders.contains_key(&shader_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a shader program.
|
||||||
|
/// 移除着色器程序。
|
||||||
|
///
|
||||||
|
/// Note: Cannot remove built-in shaders (ID < 100).
|
||||||
|
/// 注意:无法移除内置着色器(ID < 100)。
|
||||||
|
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||||
|
if shader_id < 100 {
|
||||||
|
log::warn!("Cannot remove built-in shader: {} | 无法移除内置着色器: {}", shader_id, shader_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.shader_sources.remove(&shader_id);
|
||||||
|
self.shaders.remove(&shader_id).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all shader IDs.
|
||||||
|
/// 获取所有着色器ID。
|
||||||
|
pub fn shader_ids(&self) -> Vec<u32> {
|
||||||
|
self.shaders.keys().copied().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get shader count.
|
||||||
|
/// 获取着色器数量。
|
||||||
|
#[inline]
|
||||||
|
pub fn shader_count(&self) -> usize {
|
||||||
|
self.shaders.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
mod program;
|
mod program;
|
||||||
mod builtin;
|
mod builtin;
|
||||||
|
mod manager;
|
||||||
|
|
||||||
pub use program::ShaderProgram;
|
pub use program::ShaderProgram;
|
||||||
pub use builtin::{SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
pub use builtin::{SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
||||||
|
pub use manager::{ShaderManager, SHADER_ID_DEFAULT_SPRITE};
|
||||||
|
|||||||
Reference in New Issue
Block a user