Skip to content
View source

rasterGenerated

Category: Packages · Manifest: use "kernels/";

Triangles turned into the surface a camera sees, drawn alike on every backend.

Triangles turned into the surface a camera sees, drawn alike on every backend: plain, tiled and through a cutout mask; and translucent triangles over it, in any order. native.rasterize, and native.cover for the keys alone, are its fast paths.

Layer: Graphics. Uses: parallel.

use "raster.entpkg";
  • kernels/clip.ent — Triangles cut at the near plane, before the rasterizer, which skips whole a triangle reaching behind it. Kernels: raster.clip_near@1, raster.clip_plane@1, raster.clip_faces@1.
  • kernels/cutout.ent — Triangles drawn through a mask. Kernels: raster.cover_cutout@3, raster.cover_cutout@4, raster.cover_cutout_tiles@2.
  • kernels/tile.ent — Triangles larger than a tile cut across many. Kernels: raster.boxes@1, raster.tiles@2, raster.offsets@1, raster.total@1, raster.cover_tiles@2.
  • kernels/triangle.ent — Rasterization as Kernels. Kernels: raster.cover@3, raster.cover@4, raster.resolve@2.
  • kernels/veil.ent — Translucent triangles over an opaque surface: the light they add and the share of the surface left showing, summed so any order of triangles gives the same pixel. Kernels: raster.unveiled@1, raster.veil@1, raster.veiled@1.
  • graphs/canvas.esn — The raster preset over a canvas.
  • graphs/cutout.esn — The raster preset with a cutout.
  • graphs/cutout_tiled.esn — The tiled form of cutout.esn.
  • graphs/cutout_tiled_window.esn — The tiled form of cutout_window.esn.
  • graphs/cutout_window.esn — The cutout preset at the window’s size, as window.esn is the plain one’s.
  • graphs/surface.esn — Vertex and triangle rows in, the surface out.
  • graphs/tiled.esn — The tiled form of surface.esn.
  • graphs/tiled_window.esn — The tiled form of window.esn.
  • graphs/veil.esn — Translucent triangles, their tints and the opaque surface in; the light and what shows through out.
  • graphs/window.esn — The raster preset at the window’s size.

tests/ holds scenes and their replays, run on every backend: clip.replay, degenerate.replay, near.replay, tiles.replay, veil.replay. Every Kernel of the package is reached by one of them.

Used by the animation, culled, mesh, mipmap, surface, voxel examples.

Kernel Mode Brief
raster.boxes@1 map Each triangle’s box on the canvas, found once: none for one that is skipped. Every later step reads it.
raster.clip_faces@1 map The two faces over each triangle’s four corners (domain = count(triangles) * 2).
raster.clip_near@1 map Each triangle’s four corners after the cut (domain = count(triangles) * 4): the polygon in front of the near plane in the triangle’s winding, its first corner again past its last (a triangle’s fourth is its third); a triangle wholly behind keeps corners at w -1, which the rasterizer skips.
raster.clip_plane@1 map Each triangle’s four corners cut by a plane (domain = count(triangles) * 4), as raster.clip_near cuts at the near plane: what lies on the side of plane (its first row, in clip space: a corner is kept where dot(plane, clip) is not below 0) a world plane drawn through the lens has (light.entpkg’s surface.lens_clip_plane); a mirror’s pass keeps what stands over the water, not the bed under it.
raster.cover@3 scatter into input 3 with min Every pixel’s nearest fragment as one key: each triangle walks its box and emits a key a pixel it covers. With a tile, only the triangles whose box is one tile or less; the larger ones are left to raster.cover_tiles@2, which takes these keys as its own start, so the least of both is kept.
raster.cover@4 scatter into input 2 with min Every pixel’s nearest fragment as one key, with no tiles: each triangle finds its own box and walks it, emitting a key a pixel it covers. No other step reads the box, so it is found here alone.
raster.cover_cutout@3 scatter into input 4 with min The same pair with a cutout: a fragment whose alpha in mask, read at its own uv as at_linear(mask, uv * size(mask)) reads it, is below cutout is not drawn — it emits no key, so it settles no depth and what is behind a leaf’s edge is seen through it.
raster.cover_cutout@4 scatter into input 3 with min The same with a cutout and no tiles: each triangle finds its own box, as raster.cover@4 does.
raster.cover_cutout_tiles@2 scatter into input 7 with min
raster.cover_tiles@2 scatter into input 6 with min Every pixel’s nearest fragment as one key, of the large triangles, a tile of one’s box at a time, so a triangle that fills the canvas is covered by as many invocations as it has tiles rather than by one. The node’s domain is a pool of invocations sized by the canvas, each taking every nth tile, so how many tiles there are this frame is read on the device and never waited for. It starts from the keys raster.cover@3 left, and keeps the least.
raster.offsets@1 prefix with sum Where each triangle’s tiles begin: an inclusive prefix of the counts, so triangle t’s tiles end before offsets[t].
raster.resolve@2 map The surface: at each covered pixel, the depth its key holds and the winner’s attributes interpolated at the pixel’s center, perspective-correct.
raster.tiles@2 map How many tiles each triangle’s box is cut into: none for one of a tile or less, which raster.cover@3 covers whole.
raster.total@1 map How many tiles there are, which sizes the next node: the last offset.
raster.unveiled@1 map The sums to start from: nothing drawn, one for each pixel of surface (or of the node’s domain, for sums of another size).
raster.veil@1 scatter into input 4 with sum Every pixel’s sums of light and absorption over the translucent triangles in front of surface, added to light.
raster.veiled@1 map The sums read back: the light the translucent triangles add (rgb) and the share of the opaque surface left showing through them (a). A picture is the surface’s color times a, plus rgb.
Function Brief
raster_clipped_row(id: Int) -> Int The triangle row a face row drawn from raster.clip_faces came from.
raster_clip_between(a: Corner, b: Corner, t: Float) -> Corner Corner a taken t of the way to b in clip space.
raster_clip_kept(a: Corner, b: Corner, c: Corner, da: Float, db: Float, dc: Float, k: Int) -> Corner Corner k (0 to 3) of what of the triangle a, b, c lies where a plane’s signed distance (da, db, dc at its corners, linear across it) is not below 0: the whole, a triangle or a quad in the triangle’s winding (a triangle’s fourth corner its third), or nothing (corners at w -1, which the rasterizer skips); a cut edge’s corner taken where the distance is 0.
tile_place(e: Int, counts: Rows<Int>, offsets: Rows<Int>, boxes: Rows<Box>, tile: Int) -> TilePlace
edge(a: Vec2, b: Vec2, p: Vec2) -> Float
face_weights(a: Vec2, b: Vec2, c: Vec2, q: Vec2, area: Float) -> Vec3
box_tile(box: Vec4, tile: Int, k: Int) -> IVec4
screen(v: Corner, size: Vec2) -> Vec4
usable(v: Corner) -> Bool
same(p: Vec4, q: Vec4) -> Bool
corners(face: Face, vertices: Rows<Corner>, size: Vec2) -> Corners
boxed(k: Corners, size: Vec2) -> Box
depth_at(k: Corners, px: Int, py: Int) -> Float
uv_at(k: Corners, va: Corner, vb: Corner, vc: Corner, px: Int, py: Int) -> Vec2
key_of(z: Float, t: Int) -> Long
large(b: Box, tile: Int) -> Bool
veil_scale() -> Float
tint_at(k: Corners, ta: Vec4, tb: Vec4, tc: Vec4, px: Int, py: Int) -> Vec4
veil_of(t: Vec4, fade: Float) -> IVec4
Name Syntax
TilePlace struct TilePlace { t: Int; x0: Int; y0: Int; w: Int; h: Int; }
Corner struct Corner { clip: Vec4; normal: Vec3; uv: Vec2; }
Face struct Face { a: Int; b: Int; c: Int; }
Corners struct Corners
Surface struct Surface { depth: Float; normal: Vec3; uv: Vec2; id: Int; }
Box struct Box { x0: Int; y0: Int; w: Int; h: Int; }
Name Interface Description
canvas input vertices: Rows<Corner>
input triangles: Rows<Face>
input canvas: Grid<Long>
output surface <- resolved.result
The raster preset over a canvas: as surface.esn, the surface the extent of canvas, an empty canvas (every key 9223372036854775807l, as surface.esn’s empty makes) another node sized, so a surface follows a size the scene computes. Place it with node raster: graph “../../packages/raster.entpkg/graphs/canvas.esn” { vertices <- project.result; triangles <- faces.result; canvas <- empty.result; } and read raster.surface where native.rasterize@3 gave surface.
cutout input vertices: Rows<Corner>
input triangles: Rows<Face>
input mask: Image
param cutout: Float = 0.5
param width: Int = 320
param height: Int = 240
output surface <- resolved.result
The raster preset with a cutout: as surface.esn, except that a fragment whose alpha in mask at its own uv is below cutout is not drawn, so what is behind it shows — leaves, fences, hair. Place it with node raster: graph “../../packages/raster.entpkg/graphs/cutout.esn” { vertices <- project.result; triangles <- faces.result; mask <- leaves; cutout = 0.5; } and read raster.surface where native.rasterize@2 gave surface.
cutout_tiled input vertices: Rows<Corner>
input triangles: Rows<Face>
input mask: Image
param cutout: Float = 0.5
param width: Int = 320
param height: Int = 240
param tile: Int = 16
param pool: Int = 4096
output surface <- resolved.result
The tiled form of cutout.esn: a triangle whose box is larger than a tile is covered a tile to an invocation, by a pool of pool invocations, so a mesh of few large triangles (a model close to the camera, a quad filling the screen) draws in parallel on a device. It costs a pass over every triangle, a prefix and a pass more, so a mesh of small triangles draws faster with cutout.esn.
cutout_tiled_window input vertices: Rows<Corner>
input triangles: Rows<Face>
input mask: Image
param cutout: Float = 0.5
param tile: Int = 16
param pool: Int = 4096
output surface <- resolved.result
The tiled form of cutout_window.esn: a triangle whose box is larger than a tile is covered a tile to an invocation, by a pool of pool invocations, so a mesh of few large triangles (a model close to the camera, a quad filling the screen) draws in parallel on a device. It costs a pass over every triangle, a prefix and a pass more, so a mesh of small triangles draws faster with cutout_window.esn.
cutout_window input vertices: Rows<Corner>
input triangles: Rows<Face>
input mask: Image
param cutout: Float = 0.5
output surface <- resolved.result
The cutout preset at the window’s size, as window.esn is the plain one’s: the surface follows the window when it is resized.
surface input vertices: Rows<Corner>
input triangles: Rows<Face>
param width: Int = 320
param height: Int = 240
output surface <- resolved.result
Vertex and triangle rows in, the surface out: for every pixel, the nearest triangle’s depth, normal and uv, perspective-correct, and its row as id. Place it with node raster: graph “../../packages/raster.entpkg/graphs/surface.esn” { vertices <- project.result; triangles <- faces.result; width = 320; height = 240; } and read raster.surface where native.rasterize@1 gave surface.
tiled input vertices: Rows<Corner>
input triangles: Rows<Face>
param width: Int = 320
param height: Int = 240
param tile: Int = 16
param pool: Int = 4096
output surface <- resolved.result
The tiled form of surface.esn: a triangle whose box is larger than a tile is covered a tile to an invocation, by a pool of pool invocations, so a mesh of few large triangles (a model close to the camera, a quad filling the screen) draws in parallel on a device. It costs a pass over every triangle, a prefix and a pass more, so a mesh of small triangles draws faster with surface.esn.
tiled_window input vertices: Rows<Corner>
input triangles: Rows<Face>
param tile: Int = 16
param pool: Int = 4096
output surface <- resolved.result
The tiled form of window.esn: a triangle whose box is larger than a tile is covered a tile to an invocation, by a pool of pool invocations, so a mesh of few large triangles (a model close to the camera, a quad filling the screen) draws in parallel on a device. It costs a pass over every triangle, a prefix and a pass more, so a mesh of small triangles draws faster with window.esn.
veil input vertices: Rows<Corner>
input triangles: Rows<Face>
input tints: Rows<Vec4>
input surface: Grid<Surface>
param soft: Float = 0.0
output light <- veiled.result
Translucent triangles over an opaque surface (kernels/veil.ent): the light they add and the share of the surface left showing, in any order. Place it with node glow: graph “../../packages/raster.entpkg/graphs/veil.esn” { vertices <- sparks.result; triangles <- spark_faces.result; tints <- spark_tints.result; surface <- raster.surface; } and read glow.light: a picture is the surface’s color times its a, plus its rgb.
window input vertices: Rows<Corner>
input triangles: Rows<Face>
output surface <- resolved.result
The raster preset at the window’s size: the surface is the window’s extent in pixels, and follows it when it is resized, as a node of domain = window(); does. Place it with node raster: graph “../../packages/raster.entpkg/graphs/window.esn” { vertices <- project.result; triangles <- faces.result; } and read raster.surface.

Each triangle’s box on the canvas, found once: none for one that is skipped. Every later step reads it.

Mode map
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, canvas: Grid<Long>
Params —
Outputs result: Rows<Box>
Source packages/raster.entpkg/kernels/tile.ent

The two faces over each triangle’s four corners (domain = count(triangles) * 2).

Mode map
Requires field.read, field.write
Inputs triangles: Rows<Face>
Params —
Outputs result: Rows<Face>
Source packages/raster.entpkg/kernels/clip.ent

Each triangle’s four corners after the cut (domain = count(triangles) * 4): the polygon in front of the near plane in the triangle’s winding, its first corner again past its last (a triangle’s fourth is its third); a triangle wholly behind keeps corners at w -1, which the rasterizer skips.

Mode map
Requires field.read, field.write
Inputs vertices: Rows<Corner>, triangles: Rows<Face>
Params —
Outputs result: Rows<Corner>
Source packages/raster.entpkg/kernels/clip.ent

Each triangle’s four corners cut by a plane (domain = count(triangles) * 4), as raster.clip_near cuts at the near plane: what lies on the side of plane (its first row, in clip space: a corner is kept where dot(plane, clip) is not below 0) a world plane drawn through the lens has (light.entpkg’s surface.lens_clip_plane); a mirror’s pass keeps what stands over the water, not the bed under it.

Mode map
Requires field.read, field.write
Inputs vertices: Rows<Corner>, triangles: Rows<Face>, plane: Rows<Vec4>
Params —
Outputs result: Rows<Corner>
Source packages/raster.entpkg/kernels/clip.ent

Every pixel’s nearest fragment as one key: each triangle walks its box and emits a key a pixel it covers. With a tile, only the triangles whose box is one tile or less; the larger ones are left to raster.cover_tiles@2, which takes these keys as its own start, so the least of both is kept.

Mode scatter into input 3 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, boxes: Rows<Box>, keys: Grid<Long>
Params tile: Int = 0
Outputs result: Grid<Long>
Source packages/raster.entpkg/kernels/triangle.ent

Every pixel’s nearest fragment as one key, with no tiles: each triangle finds its own box and walks it, emitting a key a pixel it covers. No other step reads the box, so it is found here alone.

Mode scatter into input 2 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, keys: Grid<Long>
Params —
Outputs result: Grid<Long>
Source packages/raster.entpkg/kernels/triangle.ent

The same pair with a cutout: a fragment whose alpha in mask, read at its own uv as at_linear(mask, uv * size(mask)) reads it, is below cutout is not drawn — it emits no key, so it settles no depth and what is behind a leaf’s edge is seen through it.

Mode scatter into input 4 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, boxes: Rows<Box>, mask: Image, keys: Grid<Long>
Params cutout: Float = 0.5, tile: Int = 0
Outputs result: Grid<Long>

The same with a cutout and no tiles: each triangle finds its own box, as raster.cover@4 does.

Mode scatter into input 3 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, mask: Image, keys: Grid<Long>
Params cutout: Float = 0.5
Outputs result: Grid<Long>
Mode scatter into input 7 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, boxes: Rows<Box>, counts: Rows<Int>, offsets: Rows<Int>, total: Rows<Int>, mask: Image, keys: Grid<Long>
Params cutout: Float = 0.5, tile: Int = 16
Outputs result: Grid<Long>

Every pixel’s nearest fragment as one key, of the large triangles, a tile of one’s box at a time, so a triangle that fills the canvas is covered by as many invocations as it has tiles rather than by one. The node’s domain is a pool of invocations sized by the canvas, each taking every nth tile, so how many tiles there are this frame is read on the device and never waited for. It starts from the keys raster.cover@3 left, and keeps the least.

Mode scatter into input 6 with min
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, boxes: Rows<Box>, counts: Rows<Int>, offsets: Rows<Int>, total: Rows<Int>, keys: Grid<Long>
Params tile: Int = 16
Outputs result: Grid<Long>
Source packages/raster.entpkg/kernels/tile.ent

Where each triangle’s tiles begin: an inclusive prefix of the counts, so triangle t’s tiles end before offsets[t].

Mode prefix with sum
Requires field.read, field.write
Inputs counts: Rows<Int>
Params —
Outputs result: Rows<Int>
Source packages/raster.entpkg/kernels/tile.ent

The surface: at each covered pixel, the depth its key holds and the winner’s attributes interpolated at the pixel’s center, perspective-correct.

Mode map
Requires field.read, field.write
Inputs keys: Grid<Long>, triangles: Rows<Face>, vertices: Rows<Corner>
Params —
Outputs result: Grid<Surface>
Source packages/raster.entpkg/kernels/triangle.ent

How many tiles each triangle’s box is cut into: none for one of a tile or less, which raster.cover@3 covers whole.

Mode map
Requires field.read, field.write
Inputs boxes: Rows<Box>
Params tile: Int = 16
Outputs result: Rows<Int>
Source packages/raster.entpkg/kernels/tile.ent

How many tiles there are, which sizes the next node: the last offset.

Mode map
Requires field.read, field.write
Inputs offsets: Rows<Int>
Params —
Outputs result: Rows<Int>
Source packages/raster.entpkg/kernels/tile.ent

The sums to start from: nothing drawn, one for each pixel of surface (or of the node’s domain, for sums of another size).

Mode map
Requires field.read, field.write
Inputs surface: Grid<Surface>
Params —
Outputs result: Grid<IVec4>
Source packages/raster.entpkg/kernels/veil.ent

Every pixel’s sums of light and absorption over the translucent triangles in front of surface, added to light.

Mode scatter into input 4 with sum
Requires field.read, field.write
Inputs triangles: Rows<Face>, vertices: Rows<Corner>, tints: Rows<Vec4>, surface: Grid<Surface>, light: Grid<IVec4>
Params soft: Float = 0.0
Outputs result: Grid<IVec4>
Source packages/raster.entpkg/kernels/veil.ent

The sums read back: the light the translucent triangles add (rgb) and the share of the opaque surface left showing through them (a). A picture is the surface’s color times a, plus rgb.

Mode map
Requires field.read, field.write
Inputs sums: Grid<IVec4>
Params —
Outputs result: Image
Source packages/raster.entpkg/kernels/veil.ent

clip.replay, degenerate.replay, near.replay, tiles.replay, veil.replay