Design tab: studio lighting and body edges in the 3D view

Reported: once extruded, a part is hard to read; the lighting says
little about its shape. Both lights of the object shaders sit near the
camera, so the sides of a part come out in almost the same tone, and
nothing marks where one face ends and the next begins.

- The phong shader gains a studio lighting model, chosen by a new
  lighting_model uniform: a sky/ground hemisphere in world space (up
  faces cool and bright, down faces warm and dark), a key light from the
  upper left and a weak fill from the right, a plastic-like highlight,
  and a darker base with a faint sheen toward the silhouette so curved
  faces read as round. GLCanvas3D::set_studio_lighting() makes a canvas
  draw its objects with it whatever the realistic-view preferences; only
  the Design canvas turns it on. Every canvas sets the uniform on each
  use, 0 for the slicer's, so they render as before.
- Every B-rep edge of a body is drawn as a thin dark line over it, depth
  tested and pulled a few pixels toward the eye so it wins against the
  faces meeting at it and hides behind the faces in front. The seam of a
  closed surface and degenerate edges are left out
  (GeometryEngine::display_edges). Edges are sampled once per shape and
  kept across recomputes that leave a body unchanged; bodies faded by
  body focus get fainter edges, and a dress-up previewing its result
  alone hides them with the bodies.

Tests: display_edges gives a box its 12 edges at their lengths, a
cylinder its two round rims without the seam, a cone its base rim
without the seam or the apex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QK4VgguuCAk2hZLWgcjJb9
This commit is contained in:
Claude
2026-09-30 08:34:46 +00:00
parent b060101707
commit b8d45c6bb1
11 changed files with 237 additions and 5 deletions
+28
View File
@@ -32,6 +32,8 @@
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <gp_Trsf.hxx>
#include <gp_Vec.hxx>
@@ -8920,3 +8922,29 @@ TEST_CASE("CadDocument: a profile on a body face touches it, one in free space d
CHECK(doc.body_touching_sketch(-1) == -1);
CHECK(doc.body_touching_sketch(base + 1) == -1); // the extrude: not a sketch
}
TEST_CASE("display edges: every real edge once, no seams, no degenerate apex", "[CadDocument][display]")
{
const auto box = GeometryEngine::display_edges(BRepPrimAPI_MakeBox(10., 20., 30.).Shape(), 0.01);
CHECK(box.size() == 12);
for (const auto& pl : box) {
REQUIRE(pl.size() >= 2);
const double len = (pl.back() - pl.front()).norm();
CHECK((std::abs(len - 10.) < 1e-6 || std::abs(len - 20.) < 1e-6 || std::abs(len - 30.) < 1e-6));
}
// A cylinder has three edges in OCCT: the two rims and the seam down its side. Only the rims
// are drawn, each sampled finely enough to look round and closed.
const auto cyl = GeometryEngine::display_edges(BRepPrimAPI_MakeCylinder(5., 8.).Shape(), 0.01);
REQUIRE(cyl.size() == 2);
for (const auto& pl : cyl) {
CHECK(pl.size() > 16);
CHECK((pl.front() - pl.back()).norm() < 1e-6);
for (const Vec3d& p : pl)
CHECK(std::abs(std::hypot(p.x(), p.y()) - 5.) < 0.02);
}
// A cone keeps its base rim; the apex is a degenerate edge and the side has a seam.
const auto cone = GeometryEngine::display_edges(BRepPrimAPI_MakeCone(5., 0., 8.).Shape(), 0.01);
CHECK(cone.size() == 1);
}