forked from 1b-agent/opencadstudio-upstream
perf(render): instance block geometry
Share source buffers across block placements and render nested content with GPU instance transforms.\n\nChunk silhouettes and compact mesh material data so large drawings stay under device buffer limits and remain responsive.
This commit is contained in:
1 parent
7bfb617745
commit
4fd9b98da4
68 files changed
+3417
-547
No files matched your search
@@ -0,0 +1,48 @@
|
||||
struct Uniforms {
|
||||
viewport_size: vec2<f32>,
|
||||
world_per_pixel: f32,
|
||||
lwdisplay_enable: f32,
|
||||
flat_shade: f32,
|
||||
transparency_enable: f32,
|
||||
_pad: vec2<f32>,
|
||||
view_rot: mat4x4<f32>,
|
||||
eye_high: vec3<f32>,
|
||||
_pad_eh: f32,
|
||||
eye_low: vec3<f32>,
|
||||
_pad_el: f32,
|
||||
}
|
||||
@group(0) @binding(0) var<uniform> u: Uniforms;
|
||||
|
||||
struct VertexIn {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) color: vec4<f32>,
|
||||
@location(2) source_depth: f32,
|
||||
@location(3) position_low: vec3<f32>,
|
||||
@location(4) translation: vec3<f32>,
|
||||
@location(5) translation_low: vec3<f32>,
|
||||
@location(6) instance_depth: f32,
|
||||
}
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
}
|
||||
|
||||
const DRAW_ORDER_BIAS: f32 = 0.001;
|
||||
|
||||
@vertex
|
||||
fn vs_main(v: VertexIn) -> VertexOut {
|
||||
var out: VertexOut;
|
||||
let rel = (v.position + v.translation - u.eye_high)
|
||||
+ (v.position_low + v.translation_low - u.eye_low);
|
||||
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
|
||||
out.clip_pos.z = out.clip_pos.z
|
||||
- (v.source_depth + v.instance_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
|
||||
out.color = v.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
return in.color;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
struct Uniforms {
|
||||
viewport_size: vec2<f32>,
|
||||
world_per_pixel: f32,
|
||||
lwdisplay_enable: f32,
|
||||
flat_shade: f32,
|
||||
transparency_enable: f32,
|
||||
_pad: vec2<f32>,
|
||||
view_rot: mat4x4<f32>,
|
||||
eye_high: vec3<f32>,
|
||||
_pad_eh: f32,
|
||||
eye_low: vec3<f32>,
|
||||
_pad_el: f32,
|
||||
}
|
||||
@group(0) @binding(0) var<uniform> u: Uniforms;
|
||||
@group(1) @binding(0) var atlas_tex: texture_2d<f32>;
|
||||
@group(1) @binding(1) var atlas_samp: sampler;
|
||||
|
||||
struct VertIn {
|
||||
@location(0) pos: vec3<f32>,
|
||||
@location(1) pos_low: vec3<f32>,
|
||||
@location(2) uv: vec2<f32>,
|
||||
@location(3) color: vec4<f32>,
|
||||
@location(4) source_depth: f32,
|
||||
@location(5) translation: vec3<f32>,
|
||||
@location(6) translation_low: vec3<f32>,
|
||||
@location(7) instance_depth: f32,
|
||||
}
|
||||
|
||||
struct VertOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) uv: vec2<f32>,
|
||||
@location(1) color: vec4<f32>,
|
||||
}
|
||||
|
||||
const DRAW_ORDER_BIAS: f32 = 0.001;
|
||||
|
||||
@vertex
|
||||
fn vs_main(v: VertIn) -> VertOut {
|
||||
var out: VertOut;
|
||||
let rel = (v.pos + v.translation - u.eye_high)
|
||||
+ (v.pos_low + v.translation_low - u.eye_low);
|
||||
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
|
||||
out.clip_pos.z = out.clip_pos.z
|
||||
- (v.source_depth + v.instance_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
|
||||
out.uv = v.uv;
|
||||
out.color = v.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertOut) -> @location(0) vec4<f32> {
|
||||
let sd = textureSample(atlas_tex, atlas_samp, in.uv).r;
|
||||
let aa = max(fwidth(sd), 1e-4);
|
||||
let alpha = smoothstep(0.5 - aa, 0.5 + aa, sd);
|
||||
if alpha <= 0.0 {
|
||||
discard;
|
||||
}
|
||||
return vec4<f32>(in.color.rgb, in.color.a * alpha);
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
struct Uniforms {
|
||||
viewport_size: vec2<f32>,
|
||||
world_per_pixel: f32,
|
||||
lwdisplay_enable: f32,
|
||||
flat_shade: f32,
|
||||
transparency_enable: f32,
|
||||
linetype_scale: f32,
|
||||
_pad: f32,
|
||||
view_rot: mat4x4<f32>,
|
||||
eye_high: vec3<f32>,
|
||||
_pad_eh: f32,
|
||||
eye_low: vec3<f32>,
|
||||
_pad_el: f32,
|
||||
}
|
||||
@group(0) @binding(0) var<uniform> u: Uniforms;
|
||||
|
||||
struct WireConst {
|
||||
color: vec4<f32>,
|
||||
pat0: vec4<f32>,
|
||||
pat1: vec4<f32>,
|
||||
half_width: f32,
|
||||
pattern_length: f32,
|
||||
draw_depth: f32,
|
||||
align_end: f32,
|
||||
align_total: f32,
|
||||
world_half_width: f32,
|
||||
_pad1: f32,
|
||||
_pad2: f32,
|
||||
}
|
||||
@group(1) @binding(0) var<uniform> wire_const: WireConst;
|
||||
|
||||
struct VertexIn {
|
||||
@location(0) pos_a: vec3<f32>,
|
||||
@location(1) pos_b: vec3<f32>,
|
||||
@location(2) pos_a_low: vec3<f32>,
|
||||
@location(3) pos_b_low: vec3<f32>,
|
||||
@location(4) distances: vec2<f32>,
|
||||
@location(5) taper_ratio: vec2<f32>,
|
||||
@location(6) translation: vec3<f32>,
|
||||
@location(7) translation_low: vec3<f32>,
|
||||
@location(8) depth: vec2<f32>,
|
||||
}
|
||||
|
||||
const DRAW_ORDER_BIAS: f32 = 0.001;
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
@location(1) distance: f32,
|
||||
@location(2) pattern_length: f32,
|
||||
@location(3) pat0: vec4<f32>,
|
||||
@location(4) pat1: vec4<f32>,
|
||||
@location(5) @interpolate(flat) min_elem: f32,
|
||||
@location(6) @interpolate(flat) align_end: f32,
|
||||
@location(7) @interpolate(flat) align_total: f32,
|
||||
@location(8) cap: vec2<f32>,
|
||||
@location(9) @interpolate(flat) cap_ends: vec3<f32>,
|
||||
}
|
||||
|
||||
fn resolve_hw(taper_ratio: f32, world_hw: f32, px_hw: f32) -> f32 {
|
||||
if taper_ratio > 0.0 {
|
||||
return max((taper_ratio * world_hw) / u.world_per_pixel, 0.5);
|
||||
}
|
||||
if world_hw > 0.0 {
|
||||
return max(world_hw / u.world_per_pixel, 0.5);
|
||||
}
|
||||
return select(0.5, px_hw, u.lwdisplay_enable > 0.5);
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut {
|
||||
let corner = vertex_index % 6u;
|
||||
let which_end_arr = array<f32, 6>(0.0, 1.0, 1.0, 0.0, 1.0, 0.0);
|
||||
let side_arr = array<f32, 6>(-1.0, -1.0, 1.0, -1.0, 1.0, 1.0);
|
||||
let which_end = which_end_arr[corner];
|
||||
let side = side_arr[corner];
|
||||
|
||||
let rel_a = (in.pos_a + in.translation - u.eye_high)
|
||||
+ (in.pos_a_low + in.translation_low - u.eye_low);
|
||||
let rel_b = (in.pos_b + in.translation - u.eye_high)
|
||||
+ (in.pos_b_low + in.translation_low - u.eye_low);
|
||||
let clip_a = u.view_rot * vec4<f32>(rel_a, 1.0);
|
||||
let clip_b = u.view_rot * vec4<f32>(rel_b, 1.0);
|
||||
let screen_a = clip_a.xy / clip_a.w * u.viewport_size * 0.5;
|
||||
let screen_b = clip_b.xy / clip_b.w * u.viewport_size * 0.5;
|
||||
let segment = screen_b - screen_a;
|
||||
let segment_length = length(segment);
|
||||
var direction = vec2<f32>(1.0, 0.0);
|
||||
if segment_length > 1e-4 {
|
||||
direction = segment / segment_length;
|
||||
}
|
||||
let perpendicular = vec2<f32>(-direction.y, direction.x);
|
||||
let clip_position = mix(clip_a, clip_b, which_end);
|
||||
let half_width_a = resolve_hw(
|
||||
in.taper_ratio.x,
|
||||
wire_const.world_half_width,
|
||||
wire_const.half_width,
|
||||
);
|
||||
let half_width_b = resolve_hw(
|
||||
in.taper_ratio.y,
|
||||
wire_const.world_half_width,
|
||||
wire_const.half_width,
|
||||
);
|
||||
let half_width = mix(half_width_a, half_width_b, which_end);
|
||||
let extension = which_end * 2.0 - 1.0;
|
||||
let offset_px = perpendicular * half_width * side
|
||||
+ direction * half_width * extension;
|
||||
let ndc_offset = offset_px / (u.viewport_size * 0.5);
|
||||
let final_clip = clip_position
|
||||
+ vec4<f32>(ndc_offset * clip_position.w, 0.0, 0.0);
|
||||
|
||||
let scale = u.linetype_scale;
|
||||
var min_element = wire_const.pattern_length * scale;
|
||||
let elements = array<f32, 8>(
|
||||
wire_const.pat0.x * scale,
|
||||
wire_const.pat0.y * scale,
|
||||
wire_const.pat0.z * scale,
|
||||
wire_const.pat0.w * scale,
|
||||
wire_const.pat1.x * scale,
|
||||
wire_const.pat1.y * scale,
|
||||
wire_const.pat1.z * scale,
|
||||
wire_const.pat1.w * scale,
|
||||
);
|
||||
for (var i = 0u; i < 8u; i++) {
|
||||
let value = abs(elements[i]);
|
||||
if value > 0.0 && value < min_element {
|
||||
min_element = value;
|
||||
}
|
||||
}
|
||||
|
||||
var out: VertexOut;
|
||||
out.clip_pos = final_clip;
|
||||
out.clip_pos.z -= in.depth.x * DRAW_ORDER_BIAS * out.clip_pos.w;
|
||||
out.color = wire_const.color;
|
||||
out.distance = mix(in.distances.x, in.distances.y, which_end)
|
||||
+ extension * half_width * u.world_per_pixel;
|
||||
out.pattern_length = wire_const.pattern_length * scale;
|
||||
out.pat0 = wire_const.pat0 * scale;
|
||||
out.pat1 = wire_const.pat1 * scale;
|
||||
out.min_elem = min_element;
|
||||
out.align_end = wire_const.align_end * scale;
|
||||
out.align_total = wire_const.align_total;
|
||||
out.cap = vec2<f32>(
|
||||
which_end * segment_length + extension * half_width,
|
||||
half_width * side,
|
||||
);
|
||||
out.cap_ends = vec3<f32>(segment_length, half_width_a, half_width_b);
|
||||
return out;
|
||||
}
|
||||
|
||||
fn in_dash(
|
||||
distance: f32,
|
||||
pattern_length: f32,
|
||||
pat0: vec4<f32>,
|
||||
pat1: vec4<f32>,
|
||||
align_end: f32,
|
||||
align_total: f32,
|
||||
) -> bool {
|
||||
let elements = array<f32, 8>(
|
||||
pat0.x, pat0.y, pat0.z, pat0.w,
|
||||
pat1.x, pat1.y, pat1.z, pat1.w,
|
||||
);
|
||||
var count = 0u;
|
||||
for (var i = 0u; i < 8u; i++) {
|
||||
if elements[i] != 0.0 {
|
||||
count = i + 1u;
|
||||
}
|
||||
}
|
||||
var value: f32;
|
||||
if align_total > 0.0 {
|
||||
if distance <= align_end || distance >= align_total - align_end {
|
||||
return true;
|
||||
}
|
||||
var first_dash = 0.0;
|
||||
for (var i = 0u; i < count; i++) {
|
||||
if elements[i] > 0.0 {
|
||||
first_dash = elements[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = ((distance - align_end + first_dash) % pattern_length
|
||||
+ pattern_length) % pattern_length;
|
||||
} else {
|
||||
value = ((distance % pattern_length) + pattern_length) % pattern_length;
|
||||
}
|
||||
var position = 0.0;
|
||||
let dot_half = u.world_per_pixel * 0.75;
|
||||
for (var i = 0u; i < count; i++) {
|
||||
let element = elements[i];
|
||||
if element == 0.0 {
|
||||
let delta = abs(value - position);
|
||||
if min(delta, pattern_length - delta) <= dot_half {
|
||||
return true;
|
||||
}
|
||||
} else if element > 0.0 {
|
||||
if value >= position && value < position + element {
|
||||
return true;
|
||||
}
|
||||
position += element;
|
||||
} else {
|
||||
position -= element;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn clipped_cap(cap: vec2<f32>, ends: vec3<f32>) -> bool {
|
||||
if cap.x < 0.0 {
|
||||
return length(cap) > ends.y;
|
||||
}
|
||||
if cap.x > ends.x {
|
||||
return length(vec2<f32>(cap.x - ends.x, cap.y)) > ends.z;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn visible_fragment(in: VertexOut) -> bool {
|
||||
if clipped_cap(in.cap, in.cap_ends) {
|
||||
return false;
|
||||
}
|
||||
if in.pattern_length > 0.0 && in.min_elem >= u.world_per_pixel {
|
||||
return in_dash(
|
||||
in.distance,
|
||||
in.pattern_length,
|
||||
in.pat0,
|
||||
in.pat1,
|
||||
in.align_end,
|
||||
in.align_total,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
if !visible_fragment(in) {
|
||||
discard;
|
||||
}
|
||||
let alpha = select(1.0, in.color.a, u.transparency_enable > 0.5);
|
||||
return vec4<f32>(in.color.rgb, alpha);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_black(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
if !visible_fragment(in) {
|
||||
discard;
|
||||
}
|
||||
let alpha = select(1.0, in.color.a, u.transparency_enable > 0.5);
|
||||
return vec4<f32>(0.0, 0.0, 0.0, alpha);
|
||||
}
|
||||
+11
-6
@@ -97,6 +97,10 @@ struct LineFamily {
|
||||
struct VIn {
|
||||
@location(0) local_xy: vec2<f32>,
|
||||
@location(1) instance_index: u32,
|
||||
@location(2) translation: vec2<f32>,
|
||||
@location(3) translation_low: vec2<f32>,
|
||||
@location(4) draw_depth: f32,
|
||||
@location(5) visible: u32,
|
||||
}
|
||||
|
||||
struct VOut {
|
||||
@@ -114,7 +118,7 @@ struct VOut {
|
||||
// frustum-culls the primitive and no fragment runs. (WGSL
|
||||
// forbids literal NaN so this out-of-NDC trick replaces the
|
||||
// usual NaN-degenerate-triangle.)
|
||||
if visibility[v.instance_index] == 0u {
|
||||
if visibility[v.instance_index] == 0u || v.visible == 0u {
|
||||
o.clip = vec4<f32>(2.0, 2.0, 2.0, 1.0);
|
||||
o.xz = vec2<f32>(0.0, 0.0);
|
||||
o.instance_index = v.instance_index;
|
||||
@@ -126,14 +130,15 @@ struct VOut {
|
||||
// against eye_high (Sterbenz); local + anchor low + (−eye_low) carry the
|
||||
// residual. `local` is small (boundary-relative), so adding it in the low
|
||||
// term keeps full precision at UTM-scale anchors.
|
||||
let hi = vec3<f32>(inst.world_origin.x - u.eye_high.x,
|
||||
inst.world_origin.y - u.eye_high.y,
|
||||
let hi = vec3<f32>(inst.world_origin.x + v.translation.x - u.eye_high.x,
|
||||
inst.world_origin.y + v.translation.y - u.eye_high.y,
|
||||
-u.eye_high.z);
|
||||
let lo = vec3<f32>(local.x + inst.world_origin_low.x - u.eye_low.x,
|
||||
local.y + inst.world_origin_low.y - u.eye_low.y,
|
||||
let lo = vec3<f32>(local.x + inst.world_origin_low.x + v.translation_low.x - u.eye_low.x,
|
||||
local.y + inst.world_origin_low.y + v.translation_low.y - u.eye_low.y,
|
||||
-u.eye_low.z);
|
||||
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
|
||||
o.clip.z = o.clip.z - inst.draw_depth * DRAW_ORDER_BIAS * o.clip.w;
|
||||
o.clip.z = o.clip.z
|
||||
- (inst.draw_depth + v.draw_depth) * DRAW_ORDER_BIAS * o.clip.w;
|
||||
o.xz = local;
|
||||
o.instance_index = v.instance_index;
|
||||
return o;
|
||||
|
||||
@@ -92,7 +92,12 @@ fn load_family(fi: u32) -> LineFamily {
|
||||
|
||||
// ── Vertex shader (identical to wipeout.wgsl) ──────────────────────────────
|
||||
|
||||
struct VIn { @location(0) pos: vec3<f32> }
|
||||
struct VIn {
|
||||
@location(0) pos: vec3<f32>,
|
||||
@location(1) translation: vec2<f32>,
|
||||
@location(2) translation_low: vec2<f32>,
|
||||
@location(3) draw_depth: f32,
|
||||
}
|
||||
struct VOut {
|
||||
@builtin(position) clip: vec4<f32>,
|
||||
@location(0) xz: vec2<f32>,
|
||||
@@ -102,13 +107,14 @@ struct VOut {
|
||||
var o: VOut;
|
||||
// Double-single relative-to-eye: anchor high cancels eye_high (Sterbenz);
|
||||
// boundary-local v.pos + anchor low + (−eye_low) carry the residual.
|
||||
let hi = vec3<f32>(h.origin.x - u.eye_high.x,
|
||||
h.origin.y - u.eye_high.y,
|
||||
let hi = vec3<f32>(h.origin.x + v.translation.x - u.eye_high.x,
|
||||
h.origin.y + v.translation.y - u.eye_high.y,
|
||||
-u.eye_high.z);
|
||||
let lo = vec3<f32>(v.pos.x + h.origin_low.x - u.eye_low.x,
|
||||
v.pos.y + h.origin_low.y - u.eye_low.y,
|
||||
let lo = vec3<f32>(v.pos.x + h.origin_low.x + v.translation_low.x - u.eye_low.x,
|
||||
v.pos.y + h.origin_low.y + v.translation_low.y - u.eye_low.y,
|
||||
v.pos.z - u.eye_low.z);
|
||||
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
|
||||
o.clip.z = o.clip.z - v.draw_depth * 0.001 * o.clip.w;
|
||||
o.xz = vec2<f32>(v.pos.x, v.pos.y);
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ struct VertIn {
|
||||
@location(0) pos: vec3<f32>,
|
||||
@location(1) uv: vec2<f32>,
|
||||
@location(2) pos_low: vec3<f32>,
|
||||
@location(3) translation: vec3<f32>,
|
||||
@location(4) translation_low: vec3<f32>,
|
||||
@location(5) draw_depth: f32,
|
||||
};
|
||||
|
||||
struct VertOut {
|
||||
@@ -51,9 +54,11 @@ struct VertOut {
|
||||
@vertex
|
||||
fn vs_main(in: VertIn) -> VertOut {
|
||||
var out: VertOut;
|
||||
let rel = (in.pos - u.eye_high) + (in.pos_low - u.eye_low);
|
||||
let rel = (in.pos + in.translation - u.eye_high)
|
||||
+ (in.pos_low + in.translation_low - u.eye_low);
|
||||
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
|
||||
out.clip_pos.z = out.clip_pos.z - img_params.draw_depth * DRAW_ORDER_BIAS * out.clip_pos.w;
|
||||
out.clip_pos.z = out.clip_pos.z
|
||||
- (img_params.draw_depth + in.draw_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
|
||||
out.uv = in.uv;
|
||||
return out;
|
||||
}
|
||||
|
||||
+41
-53
@@ -77,6 +77,17 @@ struct MaterialMaps {
|
||||
@group(1) @binding(13) var normal_sampler: sampler;
|
||||
@group(1) @binding(14) var<uniform> maps: MaterialMaps;
|
||||
|
||||
struct MeshSurface {
|
||||
face_color: vec4<f32>,
|
||||
material: vec4<f32>,
|
||||
specular: vec4<f32>,
|
||||
ambient: vec4<f32>,
|
||||
advanced: vec4<f32>,
|
||||
flags: vec4<u32>,
|
||||
};
|
||||
|
||||
@group(1) @binding(16) var<uniform> surface: MeshSurface;
|
||||
|
||||
struct MeshInstance {
|
||||
model_row_0: vec4<f32>,
|
||||
model_row_1: vec4<f32>,
|
||||
@@ -93,19 +104,8 @@ var<storage, read> mesh_instances: array<MeshInstance>;
|
||||
struct VertexIn {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) color: vec4<f32>,
|
||||
@location(3) position_low: vec3<f32>,
|
||||
// gloss, reflectivity, self illumination, luminance
|
||||
@location(4) material: vec4<f32>,
|
||||
// specular RGB, refraction index
|
||||
@location(5) specular: vec4<f32>,
|
||||
@location(6) uv_diffuse: vec2<f32>,
|
||||
// ambient RGB, translucence
|
||||
@location(7) ambient: vec4<f32>,
|
||||
// normal strength, bump scale, reflectance scale, transmittance scale
|
||||
@location(8) advanced: vec4<f32>,
|
||||
// illumination model, channel flags, material mode, luminance mode
|
||||
@location(9) flags: vec4<u32>,
|
||||
@location(10) uv_specular_reflection: vec4<f32>,
|
||||
@location(11) uv_opacity_bump: vec4<f32>,
|
||||
@location(12) uv_refraction_normal: vec4<f32>,
|
||||
@@ -113,21 +113,15 @@ struct VertexIn {
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) world_pos: vec3<f32>,
|
||||
@location(3) material: vec4<f32>,
|
||||
@location(4) specular: vec4<f32>,
|
||||
@location(5) uv_diffuse: vec2<f32>,
|
||||
@location(6) ambient: vec4<f32>,
|
||||
@location(7) advanced: vec4<f32>,
|
||||
@location(8) @interpolate(flat) flags: vec4<u32>,
|
||||
@location(9) uv_specular: vec2<f32>,
|
||||
@location(10) uv_reflection: vec2<f32>,
|
||||
@location(11) uv_opacity: vec2<f32>,
|
||||
@location(12) uv_bump: vec2<f32>,
|
||||
@location(13) uv_refraction: vec2<f32>,
|
||||
@location(14) uv_normal: vec2<f32>,
|
||||
@location(0) normal: vec3<f32>,
|
||||
@location(1) world_pos: vec3<f32>,
|
||||
@location(2) uv_diffuse: vec2<f32>,
|
||||
@location(3) uv_specular: vec2<f32>,
|
||||
@location(4) uv_reflection: vec2<f32>,
|
||||
@location(5) uv_opacity: vec2<f32>,
|
||||
@location(6) uv_bump: vec2<f32>,
|
||||
@location(7) uv_refraction: vec2<f32>,
|
||||
@location(8) uv_normal: vec2<f32>,
|
||||
};
|
||||
|
||||
struct EdgeVertexIn {
|
||||
@@ -168,19 +162,13 @@ fn vs_main(
|
||||
let instance = mesh_instances[instance_index];
|
||||
let rel = relative_position(v.position, v.position_low, instance);
|
||||
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
|
||||
out.color = v.color;
|
||||
out.normal = normalize(vec3<f32>(
|
||||
dot(instance.normal_row_0.xyz, v.normal),
|
||||
dot(instance.normal_row_1.xyz, v.normal),
|
||||
dot(instance.normal_row_2.xyz, v.normal),
|
||||
));
|
||||
out.world_pos = rel;
|
||||
out.material = v.material;
|
||||
out.specular = v.specular;
|
||||
out.uv_diffuse = v.uv_diffuse;
|
||||
out.ambient = v.ambient;
|
||||
out.advanced = v.advanced;
|
||||
out.flags = v.flags;
|
||||
out.uv_specular = v.uv_specular_reflection.xy;
|
||||
out.uv_reflection = v.uv_specular_reflection.zw;
|
||||
out.uv_opacity = v.uv_opacity_bump.xy;
|
||||
@@ -305,7 +293,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
);
|
||||
let strength = maps.blends1.z
|
||||
* map_weight(in.uv_normal, maps.tiling1.z)
|
||||
* max(in.advanced.x, 0.0);
|
||||
* max(surface.advanced.x, 0.0);
|
||||
n = normalize(mix(n, mapped, clamp(strength, 0.0, 1.0)));
|
||||
} else if (maps.present1.x != 0u) {
|
||||
let height = dot(
|
||||
@@ -321,7 +309,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
);
|
||||
}
|
||||
|
||||
var albedo = in.color.rgb;
|
||||
var albedo = surface.face_color.rgb;
|
||||
if (maps.present0.x != 0u) {
|
||||
let texel = textureSample(diffuse_map, diffuse_sampler, in.uv_diffuse).rgb;
|
||||
let blend = clamp(
|
||||
@@ -348,7 +336,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
}
|
||||
}
|
||||
|
||||
var specular_color = select(in.specular.rgb, albedo, in.flags.x == 1u);
|
||||
var specular_color = select(surface.specular.rgb, albedo, surface.flags.x == 1u);
|
||||
if (maps.present0.y != 0u) {
|
||||
let texel = textureSample(specular_map, specular_sampler, in.uv_specular).rgb;
|
||||
let blend = clamp(
|
||||
@@ -359,14 +347,14 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
specular_color = mix(specular_color, texel, blend);
|
||||
}
|
||||
let view = normalize(-in.world_pos);
|
||||
let gloss_exp = mix(2.0, 128.0, clamp(in.material.x, 0.0, 1.0));
|
||||
let gloss_exp = mix(2.0, 128.0, clamp(surface.material.x, 0.0, 1.0));
|
||||
let fresnel0 = pow(
|
||||
(max(in.specular.w, 1.0) - 1.0) / (max(in.specular.w, 1.0) + 1.0),
|
||||
(max(surface.specular.w, 1.0) - 1.0) / (max(surface.specular.w, 1.0) + 1.0),
|
||||
2.0,
|
||||
);
|
||||
let fresnel = fresnel0
|
||||
+ (1.0 - fresnel0) * pow(1.0 - abs(dot(n, view)), 5.0);
|
||||
let specular_strength = clamp(1.0 + in.material.y + fresnel, 0.0, 1.5);
|
||||
let specular_strength = clamp(1.0 + surface.material.y + fresnel, 0.0, 1.5);
|
||||
let viewport_highlight = select(
|
||||
1.0,
|
||||
max(u.visual_style.z, 0.0),
|
||||
@@ -441,10 +429,10 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
* pow(half_response, gloss_exp)
|
||||
* specular_strength
|
||||
* viewport_highlight
|
||||
* max(in.advanced.z, 0.0)
|
||||
* max(surface.advanced.z, 0.0)
|
||||
* strength;
|
||||
}
|
||||
let ambient_light = clamp(in.ambient.rgb, vec3<f32>(0.0), vec3<f32>(1.0))
|
||||
let ambient_light = clamp(surface.ambient.rgb, vec3<f32>(0.0), vec3<f32>(1.0))
|
||||
* clamp(u.lighting.yzw, vec3<f32>(0.0), vec3<f32>(1.0));
|
||||
var lit = ambient_light
|
||||
+ albedo * clamp(direct_light, vec3<f32>(0.0), vec3<f32>(2.0))
|
||||
@@ -473,7 +461,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
* specular_color
|
||||
* specular_strength
|
||||
* viewport_highlight
|
||||
* max(in.advanced.z, 0.0)
|
||||
* max(surface.advanced.z, 0.0)
|
||||
* max(u.environment_params.w, 0.0);
|
||||
}
|
||||
if (maps.present0.z != 0u) {
|
||||
@@ -488,8 +476,8 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
clamp(
|
||||
maps.blends0.z
|
||||
* map_weight(in.uv_reflection, maps.tiling0.z)
|
||||
* in.material.y
|
||||
* max(in.advanced.z, 0.0),
|
||||
* surface.material.y
|
||||
* max(surface.advanced.z, 0.0),
|
||||
0.0,
|
||||
1.0,
|
||||
),
|
||||
@@ -507,16 +495,16 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
clamp(
|
||||
maps.blends1.y
|
||||
* map_weight(in.uv_refraction, maps.tiling1.y)
|
||||
* in.ambient.a
|
||||
* max(in.advanced.w, 0.0),
|
||||
* surface.ambient.a
|
||||
* max(surface.advanced.w, 0.0),
|
||||
0.0,
|
||||
1.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
var rgb = mix(lit, albedo, clamp(in.material.z, 0.0, 1.0));
|
||||
if (in.flags.w == 1u) {
|
||||
rgb = lit + albedo * max(in.material.w, 0.0);
|
||||
var rgb = mix(lit, albedo, clamp(surface.material.z, 0.0, 1.0));
|
||||
if (surface.flags.w == 1u) {
|
||||
rgb = lit + albedo * max(surface.material.w, 0.0);
|
||||
}
|
||||
let contrast = 1.0 + clamp(u.view_tone.y, -1.0, 1.0);
|
||||
rgb = (rgb - vec3<f32>(0.5)) * contrast + vec3<f32>(0.5);
|
||||
@@ -533,7 +521,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
let fog_density = mix(u.fog_params.z, u.fog_params.w, fog_position);
|
||||
rgb = mix(rgb, u.fog_color.rgb, clamp(fog_density, 0.0, 1.0));
|
||||
}
|
||||
var material_alpha = in.color.a;
|
||||
var material_alpha = surface.face_color.a;
|
||||
if (maps.present0.w != 0u) {
|
||||
let opacity = textureSample(opacity_map, opacity_sampler, in.uv_opacity).r;
|
||||
let blend = clamp(
|
||||
@@ -543,7 +531,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
);
|
||||
material_alpha *= mix(1.0, opacity, blend);
|
||||
}
|
||||
material_alpha *= 1.0 - clamp(in.ambient.a * max(in.advanced.w, 0.0), 0.0, 0.95);
|
||||
material_alpha *= 1.0 - clamp(surface.ambient.a * max(surface.advanced.w, 0.0), 0.0, 0.95);
|
||||
material_alpha *= clamp(u.visual_style.y, 0.0, 1.0);
|
||||
let alpha = select(1.0, material_alpha, u.transparency_enable > 0.5);
|
||||
return vec4<f32>(rgb, alpha);
|
||||
@@ -553,7 +541,7 @@ fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
// wireframe and hidden-line edge passes so lines read at their true colour.
|
||||
@fragment
|
||||
fn fs_edge(in: EdgeVertexOut) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(in.color.rgb, 1.0);
|
||||
return vec4<f32>(surface.face_color.rgb, 1.0);
|
||||
}
|
||||
|
||||
// Edge fragment for filled render modes: force black so edges frame the shaded
|
||||
@@ -566,7 +554,7 @@ fn fs_edge_black(_in: EdgeVertexOut) -> @location(0) vec4<f32> {
|
||||
@fragment
|
||||
fn fs_highlight_selected(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(
|
||||
mix(in.color.rgb, vec3<f32>(0.15, 0.55, 1.0), 0.60),
|
||||
mix(surface.face_color.rgb, vec3<f32>(0.15, 0.55, 1.0), 0.60),
|
||||
0.90,
|
||||
);
|
||||
}
|
||||
@@ -574,7 +562,7 @@ fn fs_highlight_selected(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
@fragment
|
||||
fn fs_highlight_hover(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(
|
||||
mix(in.color.rgb, vec3<f32>(0.95, 0.55, 0.10), 0.35),
|
||||
mix(surface.face_color.rgb, vec3<f32>(0.95, 0.55, 0.10), 0.35),
|
||||
0.82,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
struct Uniforms {
|
||||
viewport_size: vec2<f32>,
|
||||
world_per_pixel: f32,
|
||||
lwdisplay_enable: f32,
|
||||
flat_shade: f32,
|
||||
transparency_enable: f32,
|
||||
_pad: vec2<f32>,
|
||||
view_rot: mat4x4<f32>,
|
||||
eye_high: vec3<f32>,
|
||||
_pad_eh: f32,
|
||||
eye_low: vec3<f32>,
|
||||
_pad_el: f32,
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<uniform> u: Uniforms;
|
||||
|
||||
struct VertexIn {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(2) color: vec4<f32>,
|
||||
@location(3) position_low: vec3<f32>,
|
||||
@location(4) translation: vec3<f32>,
|
||||
@location(5) translation_low: vec3<f32>,
|
||||
}
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(v: VertexIn) -> VertexOut {
|
||||
var out: VertexOut;
|
||||
let rel = (v.position + v.translation - u.eye_high)
|
||||
+ (v.position_low + v.translation_low - u.eye_low);
|
||||
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
|
||||
out.color = v.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
return in.color;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_black(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.0, 0.0, 0.0, in.color.a);
|
||||
}
|
||||
@@ -89,7 +89,12 @@ struct FamilyBatch {
|
||||
|
||||
// ── Vertex shader ──────────────────────────────────────────────────────────
|
||||
|
||||
struct VIn { @location(0) pos: vec3<f32> }
|
||||
struct VIn {
|
||||
@location(0) pos: vec3<f32>,
|
||||
@location(1) translation: vec2<f32>,
|
||||
@location(2) translation_low: vec2<f32>,
|
||||
@location(3) draw_depth: f32,
|
||||
}
|
||||
struct VOut {
|
||||
@builtin(position) clip: vec4<f32>,
|
||||
@location(0) xz: vec2<f32>,
|
||||
@@ -107,17 +112,17 @@ struct VOut {
|
||||
// pattern math doesn't catastrophically cancel.
|
||||
// Double-single relative-to-eye: anchor high cancels eye_high (Sterbenz);
|
||||
// boundary-local v.pos + anchor low + (−eye_low) carry the residual.
|
||||
let hi = vec3<f32>(h.origin.x - u.eye_high.x,
|
||||
h.origin.y - u.eye_high.y,
|
||||
let hi = vec3<f32>(h.origin.x + v.translation.x - u.eye_high.x,
|
||||
h.origin.y + v.translation.y - u.eye_high.y,
|
||||
-u.eye_high.z);
|
||||
let lo = vec3<f32>(v.pos.x + h.origin_low.x - u.eye_low.x,
|
||||
v.pos.y + h.origin_low.y - u.eye_low.y,
|
||||
let lo = vec3<f32>(v.pos.x + h.origin_low.x + v.translation_low.x - u.eye_low.x,
|
||||
v.pos.y + h.origin_low.y + v.translation_low.y - u.eye_low.y,
|
||||
v.pos.z - u.eye_low.z);
|
||||
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
|
||||
// Draw-order bias (see wire.wgsl): the mask erases what draws BELOW its
|
||||
// entity and loses to what draws above — including its own frame wire,
|
||||
// which rides a +half-rank override.
|
||||
o.clip.z = o.clip.z - h.draw_depth * 0.001 * o.clip.w;
|
||||
o.clip.z = o.clip.z - (h.draw_depth + v.draw_depth) * 0.001 * o.clip.w;
|
||||
o.xz = vec2<f32>(v.pos.x, v.pos.y);
|
||||
return o;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user