Tune hand-tip and palm chip layout coordinates
Adjust HandTipMatrix / HandPalmChip center, angle, and size in render.rs and propagate the spacing tweak through shader.wgsl.
This commit is contained in:
@@ -44,43 +44,43 @@ pub struct HandGatewayMode {
|
||||
|
||||
const HAND_TIP_MATRICES: [HandTipMatrix; 5] = [
|
||||
HandTipMatrix {
|
||||
center_px: [260.0, 490.0],
|
||||
center_px: [265.0, 495.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: -0.45,
|
||||
angle_rad: -0.40,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [360.0, 255.0],
|
||||
center_px: [359.0, 260.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: -0.05,
|
||||
angle_rad: -0.17,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [485.0, 225.0],
|
||||
center_px: [482.0, 228.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.0,
|
||||
angle_rad: -0.03,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [595.0, 260.0],
|
||||
center_px: [596.0, 265.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.12,
|
||||
angle_rad: 0.10,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [705.0, 385.0],
|
||||
center_px: [693.0, 370.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.28,
|
||||
angle_rad: 0.22,
|
||||
},
|
||||
];
|
||||
|
||||
const HAND_PALM_CHIPS: [HandPalmChip; 2] = [
|
||||
HandPalmChip {
|
||||
center_px: [538.0, 608.0],
|
||||
size_px: [248.0, 82.0],
|
||||
angle_rad: 0.06,
|
||||
center_px: [530.0, 593.0],
|
||||
size_px: [224.0, 68.0],
|
||||
angle_rad: 0.12,
|
||||
rows: 5,
|
||||
cols: 14,
|
||||
},
|
||||
HandPalmChip {
|
||||
center_px: [606.0, 780.0],
|
||||
size_px: [72.0, 214.0],
|
||||
center_px: [610.0, 778.0],
|
||||
size_px: [60.0, 190.0],
|
||||
angle_rad: 0.05,
|
||||
rows: 11,
|
||||
cols: 4,
|
||||
@@ -90,6 +90,7 @@ const HAND_PALM_CHIPS: [HandPalmChip; 2] = [
|
||||
const HAND_FINGER_SENSOR_CELLS: usize = 12 * 7;
|
||||
const HAND_PALM_HORIZONTAL_OFFSET: usize = HAND_FINGER_SENSOR_CELLS * 5;
|
||||
const HAND_PALM_VERTICAL_OFFSET: usize = HAND_PALM_HORIZONTAL_OFFSET + 5 * 14;
|
||||
const HAND_TIP_DOT_LOCAL_Y_OFFSET_PX: f32 = 14.0;
|
||||
|
||||
// Each entry pins one miniature matrix to a fingertip in hand.png.
|
||||
// Coordinates are authored in source-image pixels so they are easy to tune by eye.
|
||||
@@ -1144,7 +1145,7 @@ fn build_hand_membrane_instances(image_width: f32, image_height: f32) -> Vec<Gly
|
||||
.map(|tip| {
|
||||
let uv_x = tip.center_px[0] / image_width.max(1.0);
|
||||
let uv_y = tip.center_px[1] / image_height.max(1.0);
|
||||
let membrane_size = [tip.size_px[0] * 1.62, tip.size_px[1] * 1.56];
|
||||
let membrane_size = [tip.size_px[0] * 1.44, tip.size_px[1] * 1.36];
|
||||
|
||||
GlyphInstance {
|
||||
// Membrane shaders read xy as hand.png UV.
|
||||
@@ -1202,7 +1203,9 @@ fn build_hand_dot_instances(
|
||||
|
||||
// Lay out a rows x cols matrix in fingertip-local pixel space.
|
||||
let local_x = (col as f32 - cols as f32 / 2.0 + 0.5) / cols as f32 * tip.size_px[0];
|
||||
let local_y = (row as f32 - rows as f32 / 2.0 + 0.5) / rows as f32 * tip.size_px[1];
|
||||
let local_y = (row as f32 - rows as f32 / 2.0 + 0.5) / rows as f32
|
||||
* tip.size_px[1]
|
||||
+ HAND_TIP_DOT_LOCAL_Y_OFFSET_PX;
|
||||
|
||||
// Rotate the local matrix so it follows the direction of the finger.
|
||||
let x = tip.center_px[0] + local_x * cos - local_y * sin;
|
||||
|
||||
@@ -382,6 +382,11 @@ fn rounded_rect_alpha(local: vec2f, radius: f32, softness: f32) -> f32 {
|
||||
return 1.0 - smoothstep(0.0, softness, dist);
|
||||
}
|
||||
|
||||
fn dot_matrix(uv: vec2f, grid: vec2f, dot_radius: f32, dot_softness: f32) -> f32 {
|
||||
let cell = fract(uv * grid) - vec2f(0.5, 0.5);
|
||||
return 1.0 - smoothstep(dot_radius, dot_radius + dot_softness, length(cell));
|
||||
}
|
||||
|
||||
fn fingertip_film_alpha(
|
||||
local: vec2f,
|
||||
half_width: f32,
|
||||
@@ -419,14 +424,28 @@ fn vs_hand_membrane(vertex: DotVertexInput, instance: DotInstanceInput) -> HandM
|
||||
fn fs_hand_membrane(in: HandMembraneVertexOutput) -> @location(0) vec4f {
|
||||
let p = in.local;
|
||||
|
||||
let halo_shape = fingertip_film_alpha(p, 0.72, -0.39, 0.060);
|
||||
let panel = fingertip_film_alpha(p, 0.66, -0.38, 0.040);
|
||||
let rim_inner = fingertip_film_alpha(p, 0.60, -0.36, 0.040);
|
||||
let clear_inner = fingertip_film_alpha(p, 0.49, -0.31, 0.180);
|
||||
let halo_shape = fingertip_film_alpha(p, 0.72, -0.20, 0.055);
|
||||
let panel = fingertip_film_alpha(p, 0.66, -0.22, 0.035);
|
||||
let inner = fingertip_film_alpha(p, 0.58, -0.25, 0.045);
|
||||
let clear_inner = fingertip_film_alpha(p, 0.48, -0.24, 0.160);
|
||||
|
||||
let halo = clamp(halo_shape - panel, 0.0, 1.0);
|
||||
let border = clamp(panel - rim_inner, 0.0, 1.0);
|
||||
let edge_fade = pow(clamp(1.0 - clear_inner, 0.0, 1.0), 1.15) * panel;
|
||||
let rim = clamp(panel - inner, 0.0, 1.0);
|
||||
let edge_fade = pow(clamp(1.0 - clear_inner, 0.0, 1.0), 1.20) * panel;
|
||||
|
||||
// Strong pseudo extrusion / bevel.
|
||||
let depth_offset = vec2f(0.045, 0.055);
|
||||
let back_shape_1 = fingertip_film_alpha(p - depth_offset * 0.55, 0.66, -0.22, 0.045);
|
||||
let back_shape_2 = fingertip_film_alpha(p - depth_offset, 0.66, -0.22, 0.060);
|
||||
let extrusion = clamp(max(back_shape_1, back_shape_2) - panel, 0.0, 1.0);
|
||||
|
||||
let bevel_offset = vec2f(0.028, 0.034);
|
||||
let shifted_down_right = fingertip_film_alpha(p - bevel_offset, 0.66, -0.22, 0.035);
|
||||
let bevel_light = clamp(panel - shifted_down_right, 0.0, 1.0);
|
||||
let shifted_up_left = fingertip_film_alpha(p + bevel_offset, 0.66, -0.22, 0.035);
|
||||
let bevel_dark = clamp(panel - shifted_up_left, 0.0, 1.0);
|
||||
|
||||
let broad_bevel = edge_fade * clamp(0.58 - p.x * 0.20 - p.y * 0.18, 0.0, 1.0);
|
||||
|
||||
// Micro lattice.
|
||||
let uv = clamp(
|
||||
@@ -437,56 +456,58 @@ fn fs_hand_membrane(in: HandMembraneVertexOutput) -> @location(0) vec4f {
|
||||
|
||||
let grid = vec2f(18.0, 34.0);
|
||||
let cell_uv = fract(uv * grid) - vec2f(0.5, 0.5);
|
||||
|
||||
let node = 1.0 - smoothstep(
|
||||
0.070,
|
||||
0.165,
|
||||
length(cell_uv * vec2f(1.0, 1.08)),
|
||||
);
|
||||
|
||||
let mesh_x = smoothstep(0.455, 0.495, abs(cell_uv.x));
|
||||
let mesh_y = smoothstep(0.455, 0.495, abs(cell_uv.y));
|
||||
let mesh = max(mesh_x, mesh_y);
|
||||
let lattice = (node * 0.90 + mesh * 0.10) * rim_inner;
|
||||
|
||||
// Blue glass highlights.
|
||||
let side_glow = smoothstep(0.28, 0.66, abs(p.x)) * panel;
|
||||
let top_light = smoothstep(0.10, 0.78, -p.y) * panel;
|
||||
let dot_dist = length(cell_uv * vec2f(1.0, 1.06));
|
||||
let dot_aa = max(fwidth(dot_dist) * 1.35, 0.006);
|
||||
let dots = (1.0 - smoothstep(0.105 - dot_aa, 0.105 + dot_aa, dot_dist)) * inner;
|
||||
|
||||
let sheen_axis = p.x * 0.88 + p.y * 0.22 + 0.16;
|
||||
let sheen = (1.0 - smoothstep(0.0, 0.11, abs(sheen_axis))) * panel;
|
||||
let scan = (0.5 + 0.5 * sin((uv.y * 76.0 + uv.x * 9.0) * 6.28318)) * 0.025;
|
||||
let sheen = (1.0 - smoothstep(0.018, 0.105, abs(sheen_axis))) * panel;
|
||||
let shell_sheen = sheen * (0.26 + edge_fade * 0.74);
|
||||
|
||||
// Temporary synthetic pressure hotspot. Real hand pressure dots are drawn above this pass.
|
||||
let pressure_center = vec2f(-0.10, -0.15);
|
||||
let pressure_dist = length((p - pressure_center) * vec2f(1.0, 0.72));
|
||||
let pressure = (1.0 - smoothstep(0.04, 0.37, pressure_dist)) * rim_inner;
|
||||
let pressure_hot = (1.0 - smoothstep(0.015, 0.13, pressure_dist)) * rim_inner;
|
||||
let pressure_center = vec2f(-0.08, -0.12);
|
||||
let pressure_dist = length((p - pressure_center) * vec2f(1.0, 0.74));
|
||||
let pressure = (1.0 - smoothstep(0.05, 0.36, pressure_dist)) * inner;
|
||||
let pressure_hot = (1.0 - smoothstep(0.02, 0.13, pressure_dist)) * inner;
|
||||
|
||||
let membrane_color = vec3f(0.006, 0.028, 0.110);
|
||||
let inner_cyanblue = vec3f(0.012, 0.110, 0.320);
|
||||
let lattice_color = vec3f(0.040, 0.420, 0.760);
|
||||
let rim_color = vec3f(0.120, 0.720, 0.950);
|
||||
let glass_base = vec3f(0.006, 0.055, 0.105);
|
||||
let glass_cyan = vec3f(0.025, 0.42, 0.58);
|
||||
let rim_color = vec3f(0.10, 0.88, 1.00);
|
||||
let extrusion_color = vec3f(0.004, 0.080, 0.110);
|
||||
let extrusion_edge_color = vec3f(0.015, 0.30, 0.38);
|
||||
let bevel_highlight = vec3f(0.48, 1.00, 1.00);
|
||||
let bevel_dark_color = vec3f(0.004, 0.035, 0.060);
|
||||
let dot_color = vec3f(0.08, 0.48, 0.58);
|
||||
let pressure_green = vec3f(0.01, 0.78, 0.23);
|
||||
let pressure_hot_color = vec3f(0.20, 1.00, 0.42);
|
||||
|
||||
let pressure_green = vec3f(0.00, 0.66, 0.22);
|
||||
let pressure_lime = vec3f(0.18, 1.00, 0.50);
|
||||
|
||||
let color = membrane_color * panel * (0.36 + top_light * 0.08 + scan)
|
||||
+ inner_cyanblue * edge_fade * 0.72
|
||||
+ lattice_color * lattice * 0.66
|
||||
+ rim_color * (border * 0.90 + edge_fade * 0.16 + halo * 0.16 + side_glow * 0.08 + sheen * 0.10)
|
||||
+ pressure_green * pressure * 0.70
|
||||
+ pressure_lime * pressure_hot * 0.82;
|
||||
let color = extrusion_color * extrusion * 0.90
|
||||
+ extrusion_edge_color * extrusion * halo_shape * 0.32
|
||||
+ glass_base * panel * 0.26
|
||||
+ glass_cyan * edge_fade * 0.46
|
||||
+ glass_cyan * broad_bevel * 0.24
|
||||
+ rim_color * rim * 0.88
|
||||
+ bevel_highlight * bevel_light * 1.35
|
||||
+ bevel_dark_color * bevel_dark * 0.95
|
||||
+ bevel_highlight * shell_sheen * 0.28
|
||||
+ rim_color * halo * 0.16
|
||||
+ dot_color * dots * 0.68
|
||||
+ pressure_green * dots * pressure * 0.82
|
||||
+ pressure_hot_color * dots * pressure_hot * 0.90;
|
||||
|
||||
let alpha = clamp(
|
||||
panel * 0.08
|
||||
+ edge_fade * 0.43
|
||||
+ border * 0.20
|
||||
+ halo * 0.04
|
||||
+ lattice * 0.055
|
||||
+ pressure * 0.05,
|
||||
extrusion * 0.44
|
||||
+ panel * 0.055
|
||||
+ edge_fade * 0.30
|
||||
+ rim * 0.34
|
||||
+ bevel_light * 0.34
|
||||
+ bevel_dark * 0.20
|
||||
+ shell_sheen * 0.09
|
||||
+ halo * 0.045
|
||||
+ dots * 0.09
|
||||
+ dots * pressure * 0.10,
|
||||
0.0,
|
||||
0.78,
|
||||
0.90,
|
||||
);
|
||||
|
||||
return output_color(color, alpha);
|
||||
@@ -561,32 +582,47 @@ fn vs_hand_palm_chip(vertex: DotVertexInput, instance: DotInstanceInput) -> Hand
|
||||
|
||||
@fragment
|
||||
fn fs_hand_palm_chip(in: HandPalmChipVertexOutput) -> @location(0) vec4f {
|
||||
// Dark rounded tile: this is the inset chip body sitting inside the palm surface.
|
||||
let panel = rounded_rect_alpha(in.local, 0.10, 0.040);
|
||||
let inset = rounded_rect_alpha(in.local * vec2f(1.10, 1.08), 0.08, 0.052);
|
||||
let rim = clamp(panel - inset * 0.72, 0.0, 1.0);
|
||||
// Inactive palm matrix: only independent dots, with no filled patch underneath.
|
||||
let panel = rounded_rect_alpha(in.local, 0.11, 0.040);
|
||||
let inner = rounded_rect_alpha(in.local * vec2f(1.08, 1.08), 0.09, 0.052);
|
||||
|
||||
// Inactive chip pixels use the chip's real hand layout:
|
||||
// horizontal 14 columns x 5 rows, or vertical 4 columns x 11 rows.
|
||||
let uv = clamp(in.local * 0.5 + vec2f(0.5, 0.5), vec2f(0.0, 0.0), vec2f(1.0, 1.0));
|
||||
let cell = abs(fract(uv * in.grid) - vec2f(0.5, 0.5));
|
||||
let micro_pixel = 1.0 - smoothstep(0.105, 0.178, length(cell * vec2f(1.04, 0.94)));
|
||||
let patch_mask = smoothstep(0.0, 0.36, inner) * panel;
|
||||
|
||||
let top_bevel = smoothstep(-0.96, -0.18, -in.local.y) * 0.16;
|
||||
let lower_shadow = smoothstep(0.20, 0.92, in.local.y) * 0.22;
|
||||
let side_bevel = smoothstep(0.58, 0.96, abs(in.local.x)) * 0.12;
|
||||
let scan = (0.5 + 0.5 * sin((uv.y * 36.0 + uv.x * 7.0) * 6.28318)) * 0.026;
|
||||
let grid = max(in.grid * 1.70, vec2f(1.0, 1.0));
|
||||
let cell_uv = fract(uv * grid) - vec2f(0.5, 0.5);
|
||||
let dot_dist = length(cell_uv);
|
||||
let dot_aa = max(fwidth(dot_dist) * 1.5, 0.008);
|
||||
let dots = 1.0 - smoothstep(0.135 - dot_aa, 0.135 + dot_aa, dot_dist);
|
||||
let dot_glow = 1.0 - smoothstep(0.14, 0.28, dot_dist);
|
||||
let visible_dots = dots * patch_mask;
|
||||
let visible_glow = dot_glow * patch_mask;
|
||||
|
||||
let base = vec3f(0.004, 0.012, 0.018);
|
||||
let glass = vec3f(0.012, 0.048, 0.064);
|
||||
let pixel_color = vec3f(0.075, 0.300, 0.360);
|
||||
let rim_color = vec3f(0.060, 0.560, 0.670);
|
||||
let color = base * (0.92 - lower_shadow)
|
||||
+ glass * (0.52 + top_bevel + side_bevel + scan)
|
||||
+ pixel_color * micro_pixel * 0.70
|
||||
+ rim_color * rim * 0.60;
|
||||
// Synthetic low-level pressure only changes nearby dots; it does not fill the patch.
|
||||
let horizontal = step(in.grid.y, in.grid.x);
|
||||
let pressure_center = mix(vec2f(0.0, 0.0), vec2f(-0.10, 0.0), horizontal);
|
||||
let pressure_scale = mix(vec2f(1.00, 0.82), vec2f(0.82, 1.00), horizontal);
|
||||
let pressure_dist = length((in.local - pressure_center) * pressure_scale);
|
||||
let pressure = (1.0 - smoothstep(0.06, 0.32, pressure_dist)) * patch_mask;
|
||||
let pressure_hot = (1.0 - smoothstep(0.02, 0.14, pressure_dist)) * patch_mask;
|
||||
|
||||
let alpha = panel * (0.64 + micro_pixel * 0.18 + rim * 0.20);
|
||||
let idle_dot_color = vec3f(0.18, 0.32, 0.38);
|
||||
let active_dot_color = vec3f(0.02, 0.88, 0.34);
|
||||
let hot_dot_color = vec3f(0.28, 1.00, 0.52);
|
||||
|
||||
let dot_color = mix(idle_dot_color, active_dot_color, pressure);
|
||||
|
||||
let color = dot_color * visible_dots * 1.25
|
||||
+ hot_dot_color * visible_dots * pressure_hot * 0.85
|
||||
+ active_dot_color * visible_glow * pressure * 0.14;
|
||||
|
||||
let alpha = clamp(
|
||||
visible_dots * (0.46 + pressure * 0.38)
|
||||
+ visible_dots * pressure_hot * 0.22
|
||||
+ visible_glow * pressure * 0.045,
|
||||
0.0,
|
||||
0.96,
|
||||
);
|
||||
return output_color(color, alpha);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user