Repository navigation
Why coverage uses fixed point
The rasterizer snaps vertices to a 1/16 pixel grid and evaluates the edge function in integers. Floating point left one-pixel cracks along shared edges.

Two triangles that share an edge test it from opposite corner orders. One asks edge(A, B, p), the other edge(B, A, p). In floating point those results need not negate exactly. A pixel almost on the edge can come out negative for both, and neither triangle draws it.
That left one-pixel cracks along the diagonal of a quad: two in a large quad, forty-four with the camera inside a cube.
With coordinates snapped to a grid, the edge function is exact integer arithmetic. Reversing an edge negates the value exactly. No pixel can be missed.
Exactness opens the opposite problem: a pixel exactly on a shared edge is now claimed by both triangles. That is invisible under an opaque depth test. It doubles every shared edge once anything is blended.
The top-left fill rule gives such a pixel to one triangle: the one whose edge is a top edge or a left edge. tests/test_fillrule.mojo asserts that a shared edge is claimed exactly once.
render/fillrule.mojo allocates nothing, prints nothing and raises nothing, so it compiles for a device as readily as for the host. The GPU kernel calls the same functions. See Why the CPU and GPU share code.
A shared implementation means a parity test cannot catch a bug inside it, because both sides are wrong together. The fill-rule tests therefore pin the module against values derived from the definitions. That caught the horizontal half of the top-left rule reversed. A reversed rule is still a consistent tie-break, so no crack test sees it. It silently lost a triangle's top row when that edge landed on pixel centers.
Tutorials
How-to
Reference
- Scene graph
- Rotations
- Cameras
- Geometry
- Geometry addons
- Lofts and clipping groups
- Sculptor
- Procedural generators
- Meshes and assets
- Lines
- Points and sprites
- Helpers
- Scene objects
- Animated objects
- Raycasting
- Curves and paths
- Animation
- Skinning
- Materials
- Node materials
- TSL functions
- Lights
- Lighting addons
- Fog
- Textures
- Renderer
- Renderer hooks and material flags
- Rasterization
- GPU backend
- Render target
- Post-processing
- GPU computation
- Compute nodes
- Progressive light map
- Gaussian splats
- Voxel global illumination
- SVG renderer
- Image files
- Image decode queue
- Model files
- More model files
- Exporters
- Scene JSON
- Windowing and controls
- Math
- Norm consumers
- Math addons
- Units
- Coverage tool
- Commands
- Examples
- Benchmarks
- Extensions
- Shared physics
- Physics query snapshots
- Continuous collision
- Tick force restoration
- Water
- Animals
- Buildings
- CARLA
- Femur
- Tibia
- Fibula
- Patella
- Knee
- Muscles
- Vessels
- Lymph
- Nerves
- Integument
- Leg
- Foot
- Pelvis
- Torso
- Arm
- Hand
- Head
- Genome
- Game humanoid
- Humanoid fidelity
- Audio-aligned game faces
- Converted assets
- Mesh quality
- Segment inertia
Explanation
- Software rasterizer
- Scene graph as an array
- Linear color
- Normals are not colors
- Perspective correction
- Fixed-point coverage
- Per-fragment shading
- Mipmaps
- Sorted transparency
- Types and checks
- Render hooks as a trait
- Shared CPU and GPU code
- Bands and threads
- PNG structure
- Extensions beside the port
- CUDA teardown hang
- Mojo compiler hang