- 添加 README.md 项目文档 - 更新 .gitignore 排除 JE-Skin/、eskin-finger-sdk/ 及构建产物 - 从 git 跟踪中移除 JE-Skin 和 eskin-finger-sdk Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
111 lines
3.8 KiB
Rust
111 lines
3.8 KiB
Rust
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 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,
|
|
pressure: f32,
|
|
) -> ([f32; 4], f32) {
|
|
let normalized = pressure.clamp(0.0, 1.0);
|
|
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 + layout.label_float_offset,
|
|
MATRIX_OFFSET_Z + z,
|
|
1.0,
|
|
],
|
|
normalized,
|
|
)
|
|
}
|
|
|
|
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)
|
|
}
|