Appearances in the viewport: per-face looks colour their faces, and see-through bodies and faces (opacity below 1) draw as glass: far sides first, then near sides, blended over the model
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
2b9ed16cc8
commit
a3d187ccd1
2 files changed
+59
-1
No files matched your search
@@ -22,6 +22,9 @@ pub struct GpuScene {
|
||||
/// Translucent triangles (alpha from the colour), drawn after the opaque ones without
|
||||
/// writing depth.
|
||||
pub trans: Vec<u8>,
|
||||
/// See-through bodies and faces (appearance opacity below 1), closed and outward-wound:
|
||||
/// their far sides are drawn first, then their near sides, so they read like glass.
|
||||
pub glass: Vec<u8>,
|
||||
/// Depth-tested lines.
|
||||
pub lines: Vec<u8>,
|
||||
/// Lines drawn over everything (active sketch, highlights).
|
||||
@@ -49,6 +52,12 @@ impl GpuScene {
|
||||
}
|
||||
self.trans.extend_from_slice(&c);
|
||||
}
|
||||
pub fn glass_tri(&mut self, p: [f32; 3], n: [f32; 3], c: [u8; 4]) {
|
||||
for v in p.iter().chain(&n) {
|
||||
self.glass.extend_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
self.glass.extend_from_slice(&c);
|
||||
}
|
||||
pub fn ghost_tri(&mut self, p: [f32; 3], n: [f32; 3], c: [u8; 4]) {
|
||||
for v in p.iter().chain(&n) {
|
||||
self.ghost.extend_from_slice(&v.to_le_bytes());
|
||||
@@ -151,6 +160,7 @@ struct Batches {
|
||||
key: Option<u64>,
|
||||
tris: Option<Batch>,
|
||||
trans: Option<Batch>,
|
||||
glass: Option<Batch>,
|
||||
lines: Option<Batch>,
|
||||
overlays: Option<Batch>,
|
||||
ghost: Option<Batch>,
|
||||
@@ -166,6 +176,7 @@ impl Batches {
|
||||
if let Some(sc) = slot.lock().ok().and_then(|mut s| s.take()) {
|
||||
self.tris = upload(device, "sc_tris", &sc.tris, TRI_SIZE);
|
||||
self.trans = upload(device, "sc_trans", &sc.trans, TRI_SIZE);
|
||||
self.glass = upload(device, "sc_glass", &sc.glass, TRI_SIZE);
|
||||
self.lines = upload(device, "sc_lines", &sc.lines, LINE_SIZE);
|
||||
self.overlays = upload(device, "sc_overlay", &sc.overlay, LINE_SIZE);
|
||||
self.ghost = upload(device, "sc_ghost", &sc.ghost, TRI_SIZE);
|
||||
@@ -181,6 +192,9 @@ struct Resources {
|
||||
/// Highlight triangles over the model (depth test ≤, no depth write).
|
||||
tri_hl: wgpu::RenderPipeline,
|
||||
trans: wgpu::RenderPipeline,
|
||||
/// Glass: far sides (front faces culled), then near sides (back faces culled).
|
||||
glass_far: wgpu::RenderPipeline,
|
||||
glass_near: wgpu::RenderPipeline,
|
||||
ghost: wgpu::RenderPipeline,
|
||||
xray: wgpu::RenderPipeline,
|
||||
line: wgpu::RenderPipeline,
|
||||
@@ -549,6 +563,29 @@ impl Resources {
|
||||
})
|
||||
};
|
||||
let alpha = Some(wgpu::BlendState::ALPHA_BLENDING);
|
||||
let glass = |label: &str, cull: wgpu::Face| {
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some(label),
|
||||
layout: Some(&layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &module,
|
||||
entry_point: Some("vs_tri"),
|
||||
buffers: &[Some(tri_layout())],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, cull_mode: Some(cull), ..Default::default() },
|
||||
depth_stencil: depth(wgpu::CompareFunction::LessEqual, false),
|
||||
multisample: wgpu::MultisampleState { count: t.samples.max(1), mask: !0, alpha_to_coverage_enabled: false },
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &module,
|
||||
entry_point: Some("fs_tri"),
|
||||
targets: &[Some(wgpu::ColorTargetState { format: t.format, blend: alpha, write_mask: wgpu::ColorWrites::ALL })],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
};
|
||||
let image_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("sc_image"),
|
||||
entries: &[
|
||||
@@ -659,6 +696,8 @@ impl Resources {
|
||||
access_version: 0,
|
||||
tri_hl: pipeline("sc_tris_hl", "vs_tri", "fs_tri", tri_layout(), depth(wgpu::CompareFunction::LessEqual, false), alpha),
|
||||
trans: pipeline("sc_trans", "vs_tri", "fs_tri", tri_layout(), depth(wgpu::CompareFunction::LessEqual, false), alpha),
|
||||
glass_far: glass("sc_glass_far", wgpu::Face::Front),
|
||||
glass_near: glass("sc_glass_near", wgpu::Face::Back),
|
||||
ghost: pipeline("sc_ghost", "vs_ghost", "fs_tri", tri_layout(), depth(wgpu::CompareFunction::LessEqual, false), alpha),
|
||||
xray: pipeline("sc_xray", "vs_tri", "fs_tri", tri_layout(), depth(wgpu::CompareFunction::Always, false), alpha),
|
||||
line: pipeline("sc_lines", "vs_line", "fs_line", line_layout(), depth(wgpu::CompareFunction::LessEqual, false), alpha),
|
||||
@@ -807,6 +846,8 @@ impl egui_wgpu::CallbackTrait for ViewportCallback {
|
||||
}
|
||||
}
|
||||
tris(pass, &res.ghost, &pv.ghost);
|
||||
tris(pass, &res.glass_far, &m.glass);
|
||||
tris(pass, &res.glass_near, &m.glass);
|
||||
tris(pass, &res.trans, &m.trans);
|
||||
tris(pass, &res.trans, &h.trans);
|
||||
tris(pass, &res.xray, &pv.xray);
|
||||
|
||||
@@ -226,12 +226,29 @@ fn build_scene(app: &SolveApp) -> GpuScene {
|
||||
_ => (true, true),
|
||||
};
|
||||
let edge_col = if shaded { c4(tk.body_edge) } else { c4(tk.text) };
|
||||
for t in m.triangles.iter().filter(|_| shaded) {
|
||||
// Appearances: the body's opacity, and faces with looks of their own.
|
||||
let opacity = s.doc.body_look(&b.name, b.feature).map_or(1.0, |l| l.opacity);
|
||||
let face_looks: std::collections::HashMap<usize, solvecraft_engine::doc::appearance::Look> =
|
||||
if shaded { s.doc.face_colors(b).into_iter().collect() } else { Default::default() };
|
||||
for (ti, t) in m.triangles.iter().enumerate().filter(|_| shaded) {
|
||||
let (mut col, a) = match m.tri_face.get(ti).and_then(|f| face_looks.get(&(*f as usize))) {
|
||||
Some(l) => {
|
||||
let c = Color32::from_rgb(l.color[0], l.color[1], l.color[2]);
|
||||
(if faded { c4(c.gamma_multiply(0.35)) } else { c4(c) }, l.opacity)
|
||||
}
|
||||
None => (col, opacity),
|
||||
};
|
||||
let glass = !faded && a < 0.999;
|
||||
if glass {
|
||||
col[3] = (a.clamp(0.05, 1.0) * 255.0).round() as u8;
|
||||
}
|
||||
for k in t {
|
||||
let i = *k as usize;
|
||||
if let (Some(p), Some(n)) = (m.positions.get(i), m.normals.get(i)) {
|
||||
if faded {
|
||||
sc.trans_tri(p.to_f32(), n.to_f32(), col);
|
||||
} else if glass {
|
||||
sc.glass_tri(p.to_f32(), n.to_f32(), col);
|
||||
} else {
|
||||
sc.tri(p.to_f32(), n.to_f32(), col);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user