feat: 添加 app/theme/ui/matrix/render 模块,重构 shader
This commit is contained in:
121
src/matrix.rs
Normal file
121
src/matrix.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
pub const MATRIX_ROWS: u32 = 12;
|
||||
pub const MATRIX_COLS: u32 = 7;
|
||||
|
||||
const BASE_MATRIX_SPAN: f32 = 24.0;
|
||||
const MATRIX_SPAN_GROWTH: f32 = 0.6;
|
||||
const MIN_MATRIX_SPAN: f32 = 24.0;
|
||||
const MAX_MATRIX_SPAN: f32 = 58.0;
|
||||
const MIN_CELL_SPACING: f32 = 0.52;
|
||||
const MAX_CELL_SPACING: f32 = 3.8;
|
||||
const MIN_BOARD_PADDING: f32 = 2.6;
|
||||
const MAX_BOARD_PADDING: f32 = 6.8;
|
||||
const MATRIX_OFFSET_Y: f32 = -2.4;
|
||||
const MATRIX_OFFSET_Z: f32 = 12.0;
|
||||
const HEIGHT_SCALE: f32 = 10.6;
|
||||
const BASE_HEIGHT: f32 = 0.12;
|
||||
const CAMERA_FOV: f32 = 36.0;
|
||||
const CAMERA_DISTANCE_MIN: f32 = 30.0;
|
||||
const CAMERA_DISTANCE_MAX: f32 = 122.0;
|
||||
const CAMERA_FIT_PADDING: f32 = 1.04;
|
||||
const CAMERA_ELEVATION_DEG: f32 = 64.0;
|
||||
const CAMERA_TARGET_X: f32 = 0.0;
|
||||
const CAMERA_TARGET_Y: f32 = MATRIX_OFFSET_Y + 0.2;
|
||||
const CAMERA_TARGET_Z: f32 = MATRIX_OFFSET_Z - 0.4;
|
||||
|
||||
pub struct MatrixLayout {
|
||||
pub cell_spacing: f32,
|
||||
pub board_width: f32,
|
||||
pub board_depth: f32,
|
||||
pub board_padding: f32,
|
||||
pub label_float_offset: f32,
|
||||
}
|
||||
|
||||
impl MatrixLayout {
|
||||
pub fn new(rows: u32, cols: u32) -> Self {
|
||||
let longest_edge = rows.max(cols).max(1) as f32;
|
||||
let edge_span = (longest_edge - 1.0).max(1.0);
|
||||
let target_span = (BASE_MATRIX_SPAN + edge_span * MATRIX_SPAN_GROWTH)
|
||||
.clamp(MIN_MATRIX_SPAN, MAX_MATRIX_SPAN);
|
||||
let cell_spacing = (target_span / edge_span).clamp(MIN_CELL_SPACING, MAX_CELL_SPACING);
|
||||
let board_width = cols.max(1) as f32 * cell_spacing;
|
||||
let board_depth = rows.max(1) as f32 * cell_spacing;
|
||||
let board_padding = (cell_spacing * 1.62).clamp(MIN_BOARD_PADDING, MAX_BOARD_PADDING);
|
||||
let label_float_offset = (cell_spacing * 0.42).clamp(0.36, 1.12);
|
||||
|
||||
Self {
|
||||
cell_spacing,
|
||||
board_width,
|
||||
board_depth,
|
||||
board_padding,
|
||||
label_float_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_view_projection(aspect: f32, layout: &MatrixLayout) -> [[f32; 4]; 4] {
|
||||
let camera_distance = fit_camera_distance(
|
||||
layout.board_width,
|
||||
layout.board_depth,
|
||||
layout.board_padding,
|
||||
aspect,
|
||||
);
|
||||
let elevation = CAMERA_ELEVATION_DEG.to_radians();
|
||||
let target = glam::Vec3::new(CAMERA_TARGET_X, CAMERA_TARGET_Y, CAMERA_TARGET_Z);
|
||||
let eye = glam::Vec3::new(
|
||||
CAMERA_TARGET_X,
|
||||
CAMERA_TARGET_Y + elevation.sin() * camera_distance,
|
||||
CAMERA_TARGET_Z + elevation.cos() * camera_distance,
|
||||
);
|
||||
let view = glam::Mat4::look_at_rh(eye, target, glam::Vec3::Y);
|
||||
let projection = glam::Mat4::perspective_rh(CAMERA_FOV.to_radians(), aspect, 0.1, 500.0);
|
||||
let open_gl_to_wgpu = glam::Mat4::from_cols_array(&[
|
||||
1.0, 0.0, 0.0, 0.0, //
|
||||
0.0, 1.0, 0.0, 0.0, //
|
||||
0.0, 0.0, 0.5, 0.0, //
|
||||
0.0, 0.0, 0.5, 1.0,
|
||||
]);
|
||||
|
||||
(open_gl_to_wgpu * projection * view).to_cols_array_2d()
|
||||
}
|
||||
|
||||
pub fn glyph_world_position(
|
||||
row: u32,
|
||||
col: u32,
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
layout: &MatrixLayout,
|
||||
time: f32,
|
||||
) -> ([f32; 4], f32) {
|
||||
let normalized = demo_pressure(row, col, time);
|
||||
let height = BASE_HEIGHT + normalized.powf(0.9) * HEIGHT_SCALE;
|
||||
let x = (col as f32 - cols as f32 / 2.0 + 0.5) * layout.cell_spacing;
|
||||
let z = (row as f32 - rows as f32 / 2.0 + 0.5) * layout.cell_spacing;
|
||||
|
||||
(
|
||||
[
|
||||
x,
|
||||
MATRIX_OFFSET_Y + height + layout.label_float_offset,
|
||||
MATRIX_OFFSET_Z + z,
|
||||
1.0,
|
||||
],
|
||||
normalized,
|
||||
)
|
||||
}
|
||||
|
||||
fn demo_pressure(row: u32, col: u32, time: f32) -> f32 {
|
||||
let seed = ((row * 17 + col * 31) as f32).sin() * 43_758.547;
|
||||
let phase = seed.fract() * std::f32::consts::TAU;
|
||||
let slow = 0.5 + 0.5 * (time * 1.35 + phase).sin();
|
||||
let row_wave = 0.5 + 0.5 * (time * 0.82 + row as f32 * 0.54 + col as f32 * 0.19).sin();
|
||||
(slow * row_wave).powf(0.72).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
fn fit_camera_distance(board_width: f32, board_depth: f32, board_padding: f32, aspect: f32) -> f32 {
|
||||
let padded_width = board_width + board_padding * 2.0;
|
||||
let padded_depth = board_depth + board_padding * 2.0;
|
||||
let safe_aspect = aspect.max(0.5);
|
||||
let effective_half_span = (padded_depth * 0.5).max((padded_width * 0.5) / safe_aspect);
|
||||
let fov_radians = (CAMERA_FOV * 0.5).to_radians();
|
||||
let fit_distance = (effective_half_span / fov_radians.tan()) * CAMERA_FIT_PADDING;
|
||||
fit_distance.clamp(CAMERA_DISTANCE_MIN, CAMERA_DISTANCE_MAX)
|
||||
}
|
||||
Reference in New Issue
Block a user