Files
OCCT/tests/opengl/data
Pasukhin Dmitry a2e851b254 Visualization - Shader-based infinite grid for V3d (#1223)
The classical V3d_RectangularGrid / V3d_CircularGrid path generated all grid
lines on the CPU into a Graphic3d_Structure and recomputed them whenever any
parameter, the camera, or the privileged plane moved. Dense grids paid an
O(NxM) vertex rebuild per interaction and were effectively capped in extent;
there was no way to draw an infinite grid, a background (sky-plane) grid, or
a grid with sub-pixel line antialiasing.

This change promotes a shader-based grid to the single rendering path for
both rectangular and circular grids. Classical API, snap math and the vgrid
Draw command are preserved; only the presentation pipeline moves under the
shader.

Aspect layer:

- Add Aspect_GridParams: POD carrying shader-only appearance knobs (color,
  origin, Scale, ScaleY, LineThickness, RotationAngle, AngularDivisions,
  IsBackground, IsDrawAxis, IsInfinity, DrawMode, SizeX/SizeY, Radius,
  AngleStart/AngleEnd). EffectiveScaleY() returns ScaleY when non-zero and
  Scale() otherwise; IsCircular() is shorthand for AngularDivisions() > 0;
  IsBounded() / IsArc() report active clipping.
- Extend Aspect_RectangularGrid with SizeX/SizeY/ZOffset fields and
  accessors; extend Aspect_CircularGrid with Radius/ZOffset/AngleStart/
  AngleEnd and IsArc(). Snap math is unchanged.
- Add Graphic3d_CView::GridDisplay(Aspect_GridParams, gp_Ax3) and GridErase()
  virtuals with no-op defaults; include Aspect_GridParams.hxx and gp_Ax3.hxx
  from Graphic3d_CView.hxx.

Shader (Graphic3d_ShaderManager::getGridProgram):

- Full-screen triangle unprojected per-fragment to world-space Near/Far
  points, ray-plane intersection against an arbitrary plane supplied through
  uPlaneOrigin / uPlaneX / uPlaneY / uPlaneN uniforms. Per-fragment unproject
  avoids perspective-divide nonlinearity that plagues varying-based rays.
- Helper intersectPlane() uses a normalized direction for the parallel test,
  so GRID_PARALLEL_EPS = 1e-6 is a dimensionless |sin(angle)| threshold
  (~5.7e-5 deg) that stays scale-invariant under any world-depth range.
- gridLines2d / gridLines1d: fwidth-based AA plus per-axis Nyquist fade
  (smoothstep(1.0, 2.0, fwidth)). Once a grid period fits inside a single
  pixel, that axis fades to zero instead of smearing into a bright haze at
  grazing angles. Lines mode uses max() of per-axis alphas; points mode
  uses the product so only intersections light up.
- Bounded work area (rectangular SizeX/SizeY, circular Radius, optional arc
  range): hard discard and smoothstep endpoint are both extended by
  fwidth(coord), giving a single-screen-pixel AA transition instead of a
  binary staircase at the clipping edge.
- Stable-reference rebasing for the rectangular grid: CPU unprojects the
  screen center to the plane every frame and uploads the plane-local hit as
  uStableRefLocal + uHasStableRef. The shader subtracts
  floor(ref * scale) / scale before fract(), keeping the fract() argument
  bounded at far world offsets without changing the visible line pattern.
- Branch on uGridType (0 = rectangular, 1 = circular). Circular path uses
  polar coords (length, atan2) scaled by uScaleX and uAngularScale;
  plane-local X/Y axis colouring is applied uniformly in both modes so the
  red/green/blue cardinal lines stay straight.
- uDrawMode switches lines vs points (Aspect_GDM_Points); uIsBackground
  pins gl_FragDepth to 1.0 - 1e-5 for the sky-plane look. Explicit GL 3.2 /
  GLES 3.0 version headers; requires gl_VertexID and gl_FragDepth.

OpenGL plumbing:

- Add OpenGl_ShaderManager::BindGridProgram(): lazy Create + cache, routed
  through bindProgramWithState so the standard OCCT matrix uniforms
  (occProjectionMatrix, occWorldViewMatrix, occModelWorldMatrix and their
  inverses, occViewport) are pushed onto the grid program every bind.
  myGridProgram is nullified in clear() so context resets release the
  compiled program.
- Add OpenGl_View::GridDisplay / GridErase overrides and private
  renderGrid(). The renderer binds a dedicated VAO (core-profile safe) and
  saves/restores program, depth test / func / mask, blend enable,
  blend-func-separate, and depth-clamp. ProjectionState / WorldViewState are
  push/pop-guarded. Original ZNear/ZFar/ProjType are captured before any
  mutation so a mid-function ZFitAll cannot clobber user-set vzrange on
  restore.
- Background-mode pan/rotate compensation is derived from the view-matrix
  delta (currentView * refView^-1) captured at GridDisplay(); no public
  Graphic3d_Camera API change is needed.
- Compute the plane-local stable reference in renderGrid via
  Graphic3d_TransformUtils::UnProject on the viewport center; upload
  uStableRefLocal / uHasStableRef alongside the other uniforms.
- Insert renderGrid() between renderScene() and renderTrihedron() in the
  non-immediate draw pass; release myGridVao in ReleaseGlResources.

V3d layer:

- Add V3d_View::GridDisplay(params) / GridDisplay(params, plane) / GridErase
  as thin pass-throughs; the single-argument overload uses
  V3d_Viewer::PrivilegedPlane().
- Rewrite V3d_RectangularGrid and V3d_CircularGrid: drop the nested
  RectangularGridStructure / CircularGridStructure classes, myGroup,
  DefineLines, DefinePoints, and all myCur* caching flags. Display() /
  Erase() / UpdateDisplay() now call syncViews() which builds an
  Aspect_GridParams from the Aspect_{Rectangular,Circular}Grid state
  (XStep/YStep -> Scale/ScaleY, RadiusStep -> Scale, DivisionNumber ->
  AngularDivisions, XOrigin/YOrigin/OffSet -> Origin, RotationAngle ->
  RotationAngle, SizeX/SizeY/Radius/ArcRange -> bounds, DrawMode)
  and broadcasts it over V3d_Viewer::DefinedViews(). Snap math in
  Aspect_RectangularGrid / Aspect_CircularGrid is untouched.
- V3d_RectangularGrid is unbounded by default (SizeX = SizeY = 0). The grid
  renderer honours an explicit SetSizeX / SetSizeY to activate in-shader
  clipping with AA edges; applications that want the old bounded behaviour
  set the size explicitly.

Draw / tests:

- vgrid Draw command gains -type {rect|circ|inf|infinite}, -color R G B,
  -scale N, -lineThickness T, -background {0|1}, -drawAxis {0|1},
  -inf {0|1}. Existing -origin, -step, -rotAngle, -zoffset, -size, -radius,
  -mode flags are retained and now drive the shader path.
- tests/v3d/grid/ (new group) adds ortho, persp, inf_pan, inf_rotate,
  inf_plane, rect_shader, circ_shader, rect_points, inf_options,
  bounded_rect, bounded_circ Draw regressions covering background mode,
  matrix-derived pan/rotate stability, non-XY privileged planes,
  anisotropic rectangular cells, polar divisions, points draw mode, and
  in-shader bounded clipping. Registered in tests/v3d/grids.list.
- Add src/Visualization/TKService/GTests/Aspect_GridParams_Test.cxx covering
  defaults, round-trip, copy, EffectiveScaleY fallback, RotationAngle
  round-trip, AngularDivisions / IsCircular toggle, and DrawMode round-trip.
- Add src/Visualization/TKService/GTests/Aspect_Grid_Bounds_Test.cxx
  covering SizeX/SizeY/Radius/ArcRange on the base grid classes.

Behaviour notes:

- V3d_RectangularGrid and V3d_CircularGrid no longer rely on
  Graphic3d_Structure view affinity, so new views added to the viewer after
  V3d_Viewer::ActivateGrid() must trigger a re-broadcast (call
  Grid()->Display() on the viewer or re-activate) to pick up the grid.
- Aspect_GDM_Points is now rendered as dots at grid intersections through
  uDrawMode (not as the old CPU point markers). Applications that depended
  on point markers as selectable entities should present them through a
  dedicated AIS object.
- V3d_RectangularGrid is unbounded by default; the old behaviour of
  capping to 0.5 * DefaultViewSize() is available via an explicit
  SetSizeX / SetSizeY call.
- Aspect_GridParams::Origin is a plane-local offset; the plane itself is
  supplied as a gp_Ax3 (defaults to V3d_Viewer::PrivilegedPlane()).
2026-04-23 11:35:16 +01:00
..