SHA256
113 lines
4.0 KiB
WebGPU Shading Language
113 lines
4.0 KiB
WebGPU Shading Language
// Stage 2 helper: cubemap -> equirect (NEAREST, for binary masks).
|
|
//
|
|
// The exact inverse of `equirect_to_cubemap.wgsl`'s `xyzcube` geometry, using a
|
|
// gnomonic (tangent) projection: the cube-surface coordinate for a face is
|
|
// 0.5 * (in-plane component / face-normal component), which inverts the linear
|
|
// cube-surface grid used by e2c. For each equirect output pixel we compute the
|
|
// 3D direction from (lon, lat), pick the dominant-axis cube face (F/R/B/L/U/D),
|
|
// invert that face's `xyzcube` mapping to a face pixel (j, i), and nearest-
|
|
// sample the matching face mask texture. This is the consistent inverse of our
|
|
// e2c kernel (round-trip e2c -> c2e reproduces the source within edge loss),
|
|
// and is close to py360convert.c2e(..., mode="nearest").
|
|
//
|
|
// Bindings 1..6 are the six face mask textures in FACES order [F,R,B,L,U,D],
|
|
// each `face_n x face_n`, RGBA8 (mask value replicated across RGB).
|
|
|
|
struct Params {
|
|
out_w: u32,
|
|
out_h: u32,
|
|
face_n: u32,
|
|
pad: u32,
|
|
}
|
|
|
|
@group(0) @binding(0) var<uniform> params: Params;
|
|
@group(0) @binding(1) var faceF: texture_2d<f32>;
|
|
@group(0) @binding(2) var faceR: texture_2d<f32>;
|
|
@group(0) @binding(3) var faceB: texture_2d<f32>;
|
|
@group(0) @binding(4) var faceL: texture_2d<f32>;
|
|
@group(0) @binding(5) var faceU: texture_2d<f32>;
|
|
@group(0) @binding(6) var faceD: texture_2d<f32>;
|
|
@group(0) @binding(7) var out_tex: texture_storage_2d<rgba8unorm, write>;
|
|
|
|
const PI: f32 = 3.141592653589793;
|
|
|
|
fn sample_face(id: u32, j: i32, i: i32) -> vec4<f32> {
|
|
let n = i32(params.face_n);
|
|
let cj = clamp(j, 0, n - 1);
|
|
let ci = clamp(i, 0, n - 1);
|
|
switch id {
|
|
case 0u: { return textureLoad(faceF, vec2<i32>(cj, ci), 0); }
|
|
case 1u: { return textureLoad(faceR, vec2<i32>(cj, ci), 0); }
|
|
case 2u: { return textureLoad(faceB, vec2<i32>(cj, ci), 0); }
|
|
case 3u: { return textureLoad(faceL, vec2<i32>(cj, ci), 0); }
|
|
case 4u: { return textureLoad(faceU, vec2<i32>(cj, ci), 0); }
|
|
case 5u: { return textureLoad(faceD, vec2<i32>(cj, ci), 0); }
|
|
default: { return vec4<f32>(0.0); }
|
|
}
|
|
}
|
|
|
|
@compute @workgroup_size(8, 8, 1)
|
|
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let w = params.out_w;
|
|
let h = params.out_h;
|
|
if (gid.x >= w || gid.y >= h) { return; }
|
|
|
|
let px = f32(gid.x);
|
|
let py = f32(gid.y);
|
|
let u_ = ((px + 0.5) / f32(w) - 0.5) * 2.0 * PI; // lon
|
|
let v_ = -((py + 0.5) / f32(h) - 0.5) * PI; // lat
|
|
let cv = cos(v_);
|
|
let dx = cv * sin(u_);
|
|
let dy = sin(v_);
|
|
let dz = cv * cos(u_);
|
|
|
|
let ax = abs(dx);
|
|
let ay = abs(dy);
|
|
let az = abs(dz);
|
|
let nm1 = f32(params.face_n - 1u);
|
|
|
|
var face_id: u32;
|
|
var jf: f32;
|
|
var if_: f32;
|
|
if (ay >= ax && ay >= az) {
|
|
if (dy > 0.0) {
|
|
// U: j=0.5*(x/y+1)*nm1, i=0.5*(z/y+1)*nm1
|
|
face_id = 4u;
|
|
jf = 0.5 * (dx / dy + 1.0) * nm1;
|
|
if_ = 0.5 * (dz / dy + 1.0) * nm1;
|
|
} else {
|
|
// D: j=0.5*(1-x/y)*nm1, i=0.5*(1+z/y)*nm1
|
|
face_id = 5u;
|
|
jf = 0.5 * (1.0 - dx / dy) * nm1;
|
|
if_ = 0.5 * (1.0 + dz / dy) * nm1;
|
|
}
|
|
} else if (ax >= az) {
|
|
if (dx > 0.0) {
|
|
// R: j=0.5*(1-z/x)*nm1, i=0.5*(1-y/x)*nm1
|
|
face_id = 1u;
|
|
jf = 0.5 * (1.0 - dz / dx) * nm1;
|
|
if_ = 0.5 * (1.0 - dy / dx) * nm1;
|
|
} else {
|
|
// L: j=0.5*(1-z/x)*nm1, i=0.5*(1+y/x)*nm1
|
|
face_id = 3u;
|
|
jf = 0.5 * (1.0 - dz / dx) * nm1;
|
|
if_ = 0.5 * (1.0 + dy / dx) * nm1;
|
|
}
|
|
} else {
|
|
if (dz > 0.0) {
|
|
// F: j=0.5*(x/z+1)*nm1, i=0.5*(1-y/z)*nm1
|
|
face_id = 0u;
|
|
jf = 0.5 * (dx / dz + 1.0) * nm1;
|
|
if_ = 0.5 * (1.0 - dy / dz) * nm1;
|
|
} else {
|
|
// B: j=0.5*(x/z+1)*nm1, i=0.5*(1+y/z)*nm1
|
|
face_id = 2u;
|
|
jf = 0.5 * (dx / dz + 1.0) * nm1;
|
|
if_ = 0.5 * (1.0 + dy / dz) * nm1;
|
|
}
|
|
}
|
|
|
|
let color = sample_face(face_id, i32(round(jf)), i32(round(if_)));
|
|
textureStore(out_tex, vec2<i32>(gid.xy), vec4<f32>(color.rgb, 1.0));
|
|
}
|