forked from 1b-agent/opencadstudio-upstream
feat(render): Flat/Gouraud shading, WithEdges overlay, paper-viewport mode
Faz 3 — FlatShaded vs GouraudShaded
- Uniforms.flat_shade (f32, 0/1) + mesh shader fragment derivative
bazlı per-triangle face normal hesabı; GouraudShaded ise interpolate
edilen vertex normalini kullanıyor.
Faz 4 — *WithEdges varyantları
- Pipeline::render.show_3d_edges parametresi:
- FlatShaded / GouraudShaded → 3DFACE edge pass'i atlanıyor
- *WithEdges varyantları → shaded fill'in üstüne mesh_wireframe
pipeline ile triangle-edge overlay (LessEqual depth test ile)
- face3d_edges pass'i show_3d_edges ile gate'lendi
Faz 5 — Paper-space viewport entity round-trip
- build_viewport_primitive / build_active_viewport_primitive artık
render_mode parametresi almıyor; viewport entity'sinin kendi
render_mode alanından okuyor. PaperViewportPane'dan render_mode
field'i kaldırıldı. Model layout'taki tab.render_mode hala
pick_list ile yönetiliyor.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
56834dfba6
commit
132efe6574
6 files changed
+141
-56
No files matched your search
+32
-12
@@ -2,13 +2,23 @@
|
||||
//
|
||||
// Vertex layout: position [f32;3], normal [f32;3], color [f32;4] (40 bytes)
|
||||
//
|
||||
// Lighting: simple half-Lambert with a fixed directional light so solids look
|
||||
// solid regardless of camera angle. Selection highlight overrides color.
|
||||
// Lighting: simple half-Lambert with a fixed directional light. Two
|
||||
// shading paths share this shader, picked per-frame via `u.flat_shade`:
|
||||
// - 0.0 → per-vertex normals interpolated to the fragment (Gouraud).
|
||||
// - 1.0 → per-triangle face normal from screen-space derivatives
|
||||
// `cross(dpdx(pos), dpdy(pos))`, so each triangle reads as a single
|
||||
// flat shade (FlatShaded).
|
||||
|
||||
struct Uniforms {
|
||||
view_proj: mat4x4<f32>,
|
||||
viewport: vec2<f32>,
|
||||
_pad: vec2<f32>,
|
||||
view_proj: mat4x4<f32>,
|
||||
camera_pos: vec4<f32>,
|
||||
viewport_size: vec2<f32>,
|
||||
world_per_pixel: f32,
|
||||
lwdisplay_enable: f32,
|
||||
flat_shade: f32,
|
||||
_pad0: f32,
|
||||
_pad1: f32,
|
||||
_pad2: f32,
|
||||
};
|
||||
|
||||
@group(0) @binding(0)
|
||||
@@ -21,17 +31,19 @@ struct VertexIn {
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@location(0) color: vec4<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) world_pos: vec3<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(v: VertexIn) -> VertexOut {
|
||||
var out: VertexOut;
|
||||
out.clip_pos = u.view_proj * vec4<f32>(v.position, 1.0);
|
||||
out.color = v.color;
|
||||
out.normal = v.normal;
|
||||
out.clip_pos = u.view_proj * vec4<f32>(v.position, 1.0);
|
||||
out.color = v.color;
|
||||
out.normal = v.normal;
|
||||
out.world_pos = v.position;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -39,7 +51,15 @@ fn vs_main(v: VertexIn) -> VertexOut {
|
||||
fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
|
||||
// Fixed directional light (world space, tilted toward the viewer).
|
||||
let light_dir = normalize(vec3<f32>(0.4, 0.8, 0.6));
|
||||
let n = normalize(in.normal);
|
||||
var n: vec3<f32>;
|
||||
if (u.flat_shade > 0.5) {
|
||||
// Per-triangle face normal: derivatives of the interpolated
|
||||
// world position are constant across the primitive, so every
|
||||
// fragment in the same triangle sees the same normal.
|
||||
n = normalize(cross(dpdx(in.world_pos), dpdy(in.world_pos)));
|
||||
} else {
|
||||
n = normalize(in.normal);
|
||||
}
|
||||
// Half-Lambert: [0.5, 1.0] so the dark side isn't fully black.
|
||||
let diff = clamp(dot(n, light_dir), 0.0, 1.0) * 0.5 + 0.5;
|
||||
let rgb = in.color.rgb * diff;
|
||||
|
||||
Reference in new issue
Block a user