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] = [
|
const HAND_TIP_MATRICES: [HandTipMatrix; 5] = [
|
||||||
HandTipMatrix {
|
HandTipMatrix {
|
||||||
center_px: [260.0, 490.0],
|
center_px: [265.0, 495.0],
|
||||||
size_px: [70.0, 120.0],
|
size_px: [70.0, 120.0],
|
||||||
angle_rad: -0.45,
|
angle_rad: -0.40,
|
||||||
},
|
},
|
||||||
HandTipMatrix {
|
HandTipMatrix {
|
||||||
center_px: [360.0, 255.0],
|
center_px: [359.0, 260.0],
|
||||||
size_px: [70.0, 120.0],
|
size_px: [70.0, 120.0],
|
||||||
angle_rad: -0.05,
|
angle_rad: -0.17,
|
||||||
},
|
},
|
||||||
HandTipMatrix {
|
HandTipMatrix {
|
||||||
center_px: [485.0, 225.0],
|
center_px: [482.0, 228.0],
|
||||||
size_px: [70.0, 120.0],
|
size_px: [70.0, 120.0],
|
||||||
angle_rad: 0.0,
|
angle_rad: -0.03,
|
||||||
},
|
},
|
||||||
HandTipMatrix {
|
HandTipMatrix {
|
||||||
center_px: [595.0, 260.0],
|
center_px: [596.0, 265.0],
|
||||||
size_px: [70.0, 120.0],
|
size_px: [70.0, 120.0],
|
||||||
angle_rad: 0.12,
|
angle_rad: 0.10,
|
||||||
},
|
},
|
||||||
HandTipMatrix {
|
HandTipMatrix {
|
||||||
center_px: [705.0, 385.0],
|
center_px: [693.0, 370.0],
|
||||||
size_px: [70.0, 120.0],
|
size_px: [70.0, 120.0],
|
||||||
angle_rad: 0.28,
|
angle_rad: 0.22,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const HAND_PALM_CHIPS: [HandPalmChip; 2] = [
|
const HAND_PALM_CHIPS: [HandPalmChip; 2] = [
|
||||||
HandPalmChip {
|
HandPalmChip {
|
||||||
center_px: [538.0, 608.0],
|
center_px: [530.0, 593.0],
|
||||||
size_px: [248.0, 82.0],
|
size_px: [224.0, 68.0],
|
||||||
angle_rad: 0.06,
|
angle_rad: 0.12,
|
||||||
rows: 5,
|
rows: 5,
|
||||||
cols: 14,
|
cols: 14,
|
||||||
},
|
},
|
||||||
HandPalmChip {
|
HandPalmChip {
|
||||||
center_px: [606.0, 780.0],
|
center_px: [610.0, 778.0],
|
||||||
size_px: [72.0, 214.0],
|
size_px: [60.0, 190.0],
|
||||||
angle_rad: 0.05,
|
angle_rad: 0.05,
|
||||||
rows: 11,
|
rows: 11,
|
||||||
cols: 4,
|
cols: 4,
|
||||||
@@ -90,6 +90,7 @@ const HAND_PALM_CHIPS: [HandPalmChip; 2] = [
|
|||||||
const HAND_FINGER_SENSOR_CELLS: usize = 12 * 7;
|
const HAND_FINGER_SENSOR_CELLS: usize = 12 * 7;
|
||||||
const HAND_PALM_HORIZONTAL_OFFSET: usize = HAND_FINGER_SENSOR_CELLS * 5;
|
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_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.
|
// 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.
|
// 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| {
|
.map(|tip| {
|
||||||
let uv_x = tip.center_px[0] / image_width.max(1.0);
|
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 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 {
|
GlyphInstance {
|
||||||
// Membrane shaders read xy as hand.png UV.
|
// 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.
|
// 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_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.
|
// Rotate the local matrix so it follows the direction of the finger.
|
||||||
let x = tip.center_px[0] + local_x * cos - local_y * sin;
|
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);
|
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(
|
fn fingertip_film_alpha(
|
||||||
local: vec2f,
|
local: vec2f,
|
||||||
half_width: f32,
|
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 {
|
fn fs_hand_membrane(in: HandMembraneVertexOutput) -> @location(0) vec4f {
|
||||||
let p = in.local;
|
let p = in.local;
|
||||||
|
|
||||||
let halo_shape = fingertip_film_alpha(p, 0.72, -0.39, 0.060);
|
let halo_shape = fingertip_film_alpha(p, 0.72, -0.20, 0.055);
|
||||||
let panel = fingertip_film_alpha(p, 0.66, -0.38, 0.040);
|
let panel = fingertip_film_alpha(p, 0.66, -0.22, 0.035);
|
||||||
let rim_inner = fingertip_film_alpha(p, 0.60, -0.36, 0.040);
|
let inner = fingertip_film_alpha(p, 0.58, -0.25, 0.045);
|
||||||
let clear_inner = fingertip_film_alpha(p, 0.49, -0.31, 0.180);
|
let clear_inner = fingertip_film_alpha(p, 0.48, -0.24, 0.160);
|
||||||
|
|
||||||
let halo = clamp(halo_shape - panel, 0.0, 1.0);
|
let halo = clamp(halo_shape - panel, 0.0, 1.0);
|
||||||
let border = clamp(panel - rim_inner, 0.0, 1.0);
|
let rim = clamp(panel - inner, 0.0, 1.0);
|
||||||
let edge_fade = pow(clamp(1.0 - clear_inner, 0.0, 1.0), 1.15) * panel;
|
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.
|
// Micro lattice.
|
||||||
let uv = clamp(
|
let uv = clamp(
|
||||||
@@ -437,56 +456,58 @@ fn fs_hand_membrane(in: HandMembraneVertexOutput) -> @location(0) vec4f {
|
|||||||
|
|
||||||
let grid = vec2f(18.0, 34.0);
|
let grid = vec2f(18.0, 34.0);
|
||||||
let cell_uv = fract(uv * grid) - vec2f(0.5, 0.5);
|
let cell_uv = fract(uv * grid) - vec2f(0.5, 0.5);
|
||||||
|
let dot_dist = length(cell_uv * vec2f(1.0, 1.06));
|
||||||
let node = 1.0 - smoothstep(
|
let dot_aa = max(fwidth(dot_dist) * 1.35, 0.006);
|
||||||
0.070,
|
let dots = (1.0 - smoothstep(0.105 - dot_aa, 0.105 + dot_aa, dot_dist)) * inner;
|
||||||
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 sheen_axis = p.x * 0.88 + p.y * 0.22 + 0.16;
|
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 sheen = (1.0 - smoothstep(0.018, 0.105, abs(sheen_axis))) * panel;
|
||||||
let scan = (0.5 + 0.5 * sin((uv.y * 76.0 + uv.x * 9.0) * 6.28318)) * 0.025;
|
let shell_sheen = sheen * (0.26 + edge_fade * 0.74);
|
||||||
|
|
||||||
// Temporary synthetic pressure hotspot. Real hand pressure dots are drawn above this pass.
|
// Temporary synthetic pressure hotspot. Real hand pressure dots are drawn above this pass.
|
||||||
let pressure_center = vec2f(-0.10, -0.15);
|
let pressure_center = vec2f(-0.08, -0.12);
|
||||||
let pressure_dist = length((p - pressure_center) * vec2f(1.0, 0.72));
|
let pressure_dist = length((p - pressure_center) * vec2f(1.0, 0.74));
|
||||||
let pressure = (1.0 - smoothstep(0.04, 0.37, pressure_dist)) * rim_inner;
|
let pressure = (1.0 - smoothstep(0.05, 0.36, pressure_dist)) * inner;
|
||||||
let pressure_hot = (1.0 - smoothstep(0.015, 0.13, pressure_dist)) * rim_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 glass_base = vec3f(0.006, 0.055, 0.105);
|
||||||
let inner_cyanblue = vec3f(0.012, 0.110, 0.320);
|
let glass_cyan = vec3f(0.025, 0.42, 0.58);
|
||||||
let lattice_color = vec3f(0.040, 0.420, 0.760);
|
let rim_color = vec3f(0.10, 0.88, 1.00);
|
||||||
let rim_color = vec3f(0.120, 0.720, 0.950);
|
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 color = extrusion_color * extrusion * 0.90
|
||||||
let pressure_lime = vec3f(0.18, 1.00, 0.50);
|
+ extrusion_edge_color * extrusion * halo_shape * 0.32
|
||||||
|
+ glass_base * panel * 0.26
|
||||||
let color = membrane_color * panel * (0.36 + top_light * 0.08 + scan)
|
+ glass_cyan * edge_fade * 0.46
|
||||||
+ inner_cyanblue * edge_fade * 0.72
|
+ glass_cyan * broad_bevel * 0.24
|
||||||
+ lattice_color * lattice * 0.66
|
+ rim_color * rim * 0.88
|
||||||
+ rim_color * (border * 0.90 + edge_fade * 0.16 + halo * 0.16 + side_glow * 0.08 + sheen * 0.10)
|
+ bevel_highlight * bevel_light * 1.35
|
||||||
+ pressure_green * pressure * 0.70
|
+ bevel_dark_color * bevel_dark * 0.95
|
||||||
+ pressure_lime * pressure_hot * 0.82;
|
+ 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(
|
let alpha = clamp(
|
||||||
panel * 0.08
|
extrusion * 0.44
|
||||||
+ edge_fade * 0.43
|
+ panel * 0.055
|
||||||
+ border * 0.20
|
+ edge_fade * 0.30
|
||||||
+ halo * 0.04
|
+ rim * 0.34
|
||||||
+ lattice * 0.055
|
+ bevel_light * 0.34
|
||||||
+ pressure * 0.05,
|
+ bevel_dark * 0.20
|
||||||
|
+ shell_sheen * 0.09
|
||||||
|
+ halo * 0.045
|
||||||
|
+ dots * 0.09
|
||||||
|
+ dots * pressure * 0.10,
|
||||||
0.0,
|
0.0,
|
||||||
0.78,
|
0.90,
|
||||||
);
|
);
|
||||||
|
|
||||||
return output_color(color, alpha);
|
return output_color(color, alpha);
|
||||||
@@ -561,32 +582,47 @@ fn vs_hand_palm_chip(vertex: DotVertexInput, instance: DotInstanceInput) -> Hand
|
|||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_hand_palm_chip(in: HandPalmChipVertexOutput) -> @location(0) vec4f {
|
fn fs_hand_palm_chip(in: HandPalmChipVertexOutput) -> @location(0) vec4f {
|
||||||
// Dark rounded tile: this is the inset chip body sitting inside the palm surface.
|
// Inactive palm matrix: only independent dots, with no filled patch underneath.
|
||||||
let panel = rounded_rect_alpha(in.local, 0.10, 0.040);
|
let panel = rounded_rect_alpha(in.local, 0.11, 0.040);
|
||||||
let inset = rounded_rect_alpha(in.local * vec2f(1.10, 1.08), 0.08, 0.052);
|
let inner = rounded_rect_alpha(in.local * vec2f(1.08, 1.08), 0.09, 0.052);
|
||||||
let rim = clamp(panel - inset * 0.72, 0.0, 1.0);
|
|
||||||
|
|
||||||
// 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 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 patch_mask = smoothstep(0.0, 0.36, inner) * panel;
|
||||||
let micro_pixel = 1.0 - smoothstep(0.105, 0.178, length(cell * vec2f(1.04, 0.94)));
|
|
||||||
|
|
||||||
let top_bevel = smoothstep(-0.96, -0.18, -in.local.y) * 0.16;
|
let grid = max(in.grid * 1.70, vec2f(1.0, 1.0));
|
||||||
let lower_shadow = smoothstep(0.20, 0.92, in.local.y) * 0.22;
|
let cell_uv = fract(uv * grid) - vec2f(0.5, 0.5);
|
||||||
let side_bevel = smoothstep(0.58, 0.96, abs(in.local.x)) * 0.12;
|
let dot_dist = length(cell_uv);
|
||||||
let scan = (0.5 + 0.5 * sin((uv.y * 36.0 + uv.x * 7.0) * 6.28318)) * 0.026;
|
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);
|
// Synthetic low-level pressure only changes nearby dots; it does not fill the patch.
|
||||||
let glass = vec3f(0.012, 0.048, 0.064);
|
let horizontal = step(in.grid.y, in.grid.x);
|
||||||
let pixel_color = vec3f(0.075, 0.300, 0.360);
|
let pressure_center = mix(vec2f(0.0, 0.0), vec2f(-0.10, 0.0), horizontal);
|
||||||
let rim_color = vec3f(0.060, 0.560, 0.670);
|
let pressure_scale = mix(vec2f(1.00, 0.82), vec2f(0.82, 1.00), horizontal);
|
||||||
let color = base * (0.92 - lower_shadow)
|
let pressure_dist = length((in.local - pressure_center) * pressure_scale);
|
||||||
+ glass * (0.52 + top_bevel + side_bevel + scan)
|
let pressure = (1.0 - smoothstep(0.06, 0.32, pressure_dist)) * patch_mask;
|
||||||
+ pixel_color * micro_pixel * 0.70
|
let pressure_hot = (1.0 - smoothstep(0.02, 0.14, pressure_dist)) * patch_mask;
|
||||||
+ rim_color * rim * 0.60;
|
|
||||||
|
|
||||||
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);
|
return output_color(color, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user