InternalCreates a new DrawTechnique.
Optionaledges?: booleanOptionalhasNormals?: booleanOptionalhasUVs?: booleanOptionallogDepth?: booleanPermutation flag. When true, the technique's vertex
shader rewrites gl_Position.z so the depth-buffer mapping
becomes logarithmic in view-space distance — same trick
Cesium / Three.js use to get usable depth resolution across
scenes that span huge distance ranges (UTM-scale terrain +
close-up BIM, archipelagos, infinite landscapes). Done
vertex-side so early-Z stays on; mid-triangle depth is
linearly interpolated (fine for typical BIM-shaped meshes).
Default false. Picking / snap / shadow-depth techniques
deliberately stay linear; their depth read-back math
would have to grow a log2 term to match.
Optionalpicking?: booleanOptionalsnap?: 0 | 1 | 2 | 3OptionalthickLines?: booleanOptionaltriplanar?: booleanProtected_programProtected_renderWhen true, the technique binds silhouette-related uniforms using "edge" material settings (edgeColor/edgeAlpha) instead of fill settings (fillColor/fillAlpha).
Used by silhouette-like techniques that can render both filled silhouettes and edge silhouettes.
Compilation errors encountered during program initialization.
Available after init() is called.
Fragment shader source code with comments included.
Note that comments are not supported in WebGL shader compilation, so this is for debugging/inspection purposes only.
Available after init() is called.
Fragment shader source code. Available after init() is called.
When true, the technique compiles a vertex normal sampler into its shaders
and reads smooth view-space normals from the batch's
BatchDataTextures.vertexNormalTexture. When false, the fragment
shader derives a flat face normal from dFdx/dFdy(vViewPos).
This is the per-batch axis the renderer dispatches on — only the Lambert
colour techniques are paired into {false, true} variants; edge,
silhouette, pick and snap techniques keep the single flat-shaded path.
When true, the technique compiles a vertex UV sampler into its shaders
and emits a vUV varying for downstream texture sampling. Independent
axis from hasNormals; combined into a 4-way variant lookup on
the Lambert colour techniques.
When true, the technique's compiled vertex shader rewrites
gl_Position.z for a logarithmic depth-buffer mapping. See
the constructor's logDepth config field for the
permutation contract and which techniques opt in.
When true, the technique binds uniforms for picking rendering (e.g., pickZNear/pickZFar) and uses picking-specific draw ranges from the batch's view data textures.
Used by the pick rendering pass to render meshes with unique pick colors and output depth for picking.
Snap-pass mode flag.
0 (default) — not a snap pass.3 — snap-init pass: triangles render to populate the
snap FBO's depth + view-position outputs (uses
gl.TRIANGLES, same index buffer as colour pass).2 — edge snap: edge-index buffer drawn as gl.LINES.1 — vertex snap: every unique vertex drawn as a
1-pixel gl.POINTS (no index buffer).Snap techniques bind the shared snap uniforms (drawing-buffer size, snap clip-pos centre, snap z-range — same shape as the picking uniforms) and write view-space position into an RGBA32F MRT target the renderer scans on read-back.
When true, line draws are quad-expanded in the vertex shader
(six vertices per line, two triangles forming a screen-space
aligned rectangle of width uLineWidth pixels) so they
render at user-controlled thickness across every WebGL2
implementation — including ones that clamp gl.LINES to a
single pixel (notably ANGLE on Windows).
Only consulted on the lines path of _draw: it
switches the LinesPrimitive draw call from
gl.drawArrays(gl.LINES, …, n * 2) to
gl.drawArrays(gl.TRIANGLES, …, n * 6). Triangle / edge /
snap / point draws are unaffected.
Mutually exclusive with edges / picking / snap for
now — the thick-line shader assumes a LinesPrimitive
index pair per primitive. Adding thick edges or thick pick
lines is mechanical but currently out of scope.
When true, the technique samples the per-batch albedo /
metallic-roughness / normal-map atlases via triplanar
world-space projection rather than the vertex vUV
attribute. Used for batches whose meshes have textured
materials but no UV coordinates — typical of BIM, sweeps and
lofted curve geometry.
Mutually exclusive with hasUVs: triplanar variants
are constructed with hasUVs: false. Independent axis from
hasNormals; combined into a 6-way variant lookup on
the Lambert colour techniques ((normals?, uvs?, triplanar?)
with uvs && triplanar excluded by construction).
Protected ReadonlyuseWhen false, vertex positions are addressed directly (no index-buffer lookup). Override to false in point-cloud techniques.
Vertex shader source code with comments included.
Note that comments are not supported in WebGL shader compilation, so this is for debugging/inspection purposes only.
Available after init() is called.
Vertex shader source code. Available after init() is called.
ReadonlyvertsNumber of vertices per primitive: 3 for triangles, 2 for legacy GL_LINES, 6 for thick-line quad expansion, 1 for points. Emitted as a compile-time constant into the vertex shader. Public so introspection tools (the shader inspector, the shaders panel) can surface it alongside the source.
ProtectedbuildAbstract method to build the fragment shader source code.
Subclasses must implement this method to define the fragment shader logic
based on their specific rendering requirements.
Called during init().
ProtectedbuildAbstract method to build the vertex shader source code.
Subclasses must implement this method to define the fragment shader logic
based on their specific rendering requirements.
Called during init().
Destroys the shader program and cleans up resources.
ProtectedfsAppends a raw GLSL snippet to the fragment shader source being built.
ProtectedfsDeclares the working color variable and the standard color output. Pick techniques declare their own MRT outputs and do NOT call this.
ProtectedfsDeclares the high-precision depth varying used for linearized depth rendering.
ProtectedfsProtectedGenerates fragment shader logic for depth rendering.
ProtectedfsDeclares the flat color varying read by flat-shaded color logic.
ProtectedfsAssigns the flat color varying to the working color variable.
ProtectedfsDeclares the SAO occlusion sampler and unpacking helpers.
ProtectedfsProtectedGenerates fragment shader logic for screen-space ambient occlusion (SAO).
ProtectedfsDeclares the shadow-map samplers (one per cascade), the per-cascade light-VP array, the cascade split distances, the scalar shadow params, and the PCF / slope-bias data.
Uniform layout:
uShadowMap0..3: sampler2DShadow per cascade. TEXTURE_COMPARE_MODE
is set on each depth texture so texture(sampler, vec3(uv, refDepth))
returns the hardware-bilinear PCF comparison (0 = shadow, 1 = lit).uShadowLightVPs[4]: mat4 per cascade, camera-view → cascade light-clip.uShadowCascadeSplits: view-space |z| boundaries between cascades;
entry i is the far edge of cascade i. Only entries
0 .. uShadowCascadeCount - 2 are meaningful.uShadowCascadeCount: number of populated cascades in [1, 4].uShadowParams: (intensity, depthBias, texelSize, normalOffsetBias).uShadowSlope: (dirViewX, dirViewY, dirViewZ, slopeBias).uShadowPcfRadius: half-width of the PCF kernel (0 = 1×1, 1 = 3×3…).Per-fragment cascade selection happens in fsDrawShadowLogic, so
there's no vShadowCoord varying — we transform vViewPos through the
chosen cascade's matrix at fragment time instead.
ProtectedfsSelects the best-fitting cascade for the current fragment (based on its
camera-view-space |z|), samples that cascade's shadow map with hardware
PCF, and darkens color.
Per-fragment steps:
-vViewPos.z against
uShadowCascadeSplits.vViewPos (plus the normal-offset push).uShadowPcfRadius).vViewPos must be in scope — the shadow-aware techniques always run with
Lambert shading which declares it.
ProtectedfsDeclares the fragment-side fade uniform and matching varying.
uEdgeFadeRange is vec2(startDist, endDist) in view-space units. The
CPU side derives both values from the active camera's far plane and the
view's Edges.edgeFadeStart / edgeFadeEnd knobs.
ProtectedfsMultiplies the working color.a by the fade factor.
smoothstep(start, end, dist) is 0 at dist <= start, 1 at
dist >= end. We invert it so near edges keep full alpha and far edges
fade to zero. Branch-free: when start >= end, smoothstep collapses to a
step at start, which means edges past start simply disappear — that's
the documented "set start >= end to disable" path. To keep edges
fully opaque always, ship start >= 1.0 AND end >= 1.0.
Must run AFTER fsSilhouetteLogic (which writes color = vColor) and
BEFORE fsOutputColor (which premultiplies and emits the final RGBA).
ProtectedfsAppends raw lines to the fragment shader source buffer. For subclasses that need to emit shader code not covered by the base-class helpers.
ProtectedfsDeclares the flat-in hatch varyings on the FS side. Emit
from a triangle-surface technique's buildFragmentShader
after fsLambertShadingDeclarations / colour decls.
ProtectedfsOverlays the hatch on the working color variable. For
every fragment whose screen-space position lies inside any
of the line families' ink lines, blends vHatchColor over
color.rgb using the hatch's alpha channel.
Emit AFTER the surface colour has been resolved (typically after fsLambertShadingLogic) and BEFORE fsOutputColor. Hatch is purely a visual overlay — the surface's alpha / depth is left untouched, and picking / snap shaders never call this helper.
ProtectedfsEmits the fragment shader version directive and identifying comment.
ProtectedfsDeclares the varyings and light uniforms required by Lambert shading in the fragment shader.
ProtectedfsProtectedGenerates fragment shader logic for Lambert shading.
ProtectedfsDeclare the FS-side inputs consumed by fsLogDepthLogic:
the vFragDepth varying produced by vsLogDepthLogic
and the per-frame uLogDepthCoef uniform.
No-op when logDepth is false. Emit AFTER fsHeader and before fsMainBegin.
ProtectedfsWrite gl_FragDepth per pixel using the canonical log-depth
formula — gl_FragDepth = log2(vFragDepth) * uLogDepthCoef * 0.5.
Derivation: the vertex-side scheme used
gl_Position.z = (log2(1 + w) * coef − 1) * w
which, after the GPU's /w divide, gives an NDC z of
log2(1 + w) * coef − 1 ∈ [-1, 1]
mapped to the depth buffer's [0, 1] via (z + 1) * 0.5. So
the equivalent per-pixel write is
gl_FragDepth = log2(1 + w) * coef * 0.5
with 1 + w carried in vFragDepth from the VS.
The max(1.0e-6, vFragDepth) clamp guards against fragments
whose interpolated 1 + w lands ≤ 0 — physically impossible
for a fragment in front of the camera, but cheap insurance
against a single bad triangle interpolant NaN-ing the depth
buffer for the rest of the primitive.
No-op when logDepth is false. Emit inside the FS main body, typically right before fsMainEnd — the value is independent of color, slicing, etc.
ProtectedfsOpens the fragment shader main() function.
ProtectedfsCloses the fragment shader main() function.
ProtectedfsWrites the accumulated color variable to the standard fragment output
using the premultiplied-alpha convention: (rgb * a, a).
Paired with the blend func (ONE, ONE_MINUS_SRC_ALPHA) during the
transparent pass, this gives correct blending at partial-coverage edges
and after any bilinear filtering. For fully-opaque fragments (a = 1),
rgb * 1 = rgb — so opaque output is unchanged.
Pick techniques write directly to MRT outputs and do NOT call this.
ProtectedfsDeclares the pick-pass MRT outputs, pick depth uniforms, and bit-packing helpers. Pick techniques call this instead of fsColorDeclarations.
ProtectedfsProtectedGenerates fragment shader logic for pick rendering.
ProtectedfsDeclares the round-points uniform used to discard fragments outside the point circle.
ProtectedfsProtectedGenerates fragment shader logic for point rendering.
ProtectedfsEmits precision qualifier declarations required by all fragment shaders.
ProtectedfsDeclares the flat color varying read by silhouette logic.
ProtectedfsAssigns the interpolated vertex color to the working color variable.
ProtectedfsDeclares section-plane varyings in the fragment shader (currently a stub pending section-plane support).
ProtectedfsDiscards the fragment if any active section plane clips it. The test is short-circuited two ways for performance —
vClippable == 0u skips the loop entirely for meshes
that opted out of clipping (always-visible labels,
anchor markers, etc.). The branch is on a flat
varying — uniform-coherent across a triangle, so the
GPU sees it as a single test per triangle.
uSectionPlaneCount == 0 skips the loop when no
planes are active. Branch is on a uniform, so all
scenes without active clipping pay one compare and
zero iterations.
Active planes are packed at indices 0..count-1, so the
loop bound is uniform and the compiler can emit straight-
line code rather than per-iteration active-flag tests.
ProtectedfsDeclares the snap-pass MRT outputs.
Snap techniques target a single RGBA32F render target carrying
view-space position. The init pass (snap === 3) fills the target
across triangle surfaces so the subsequent vertex/edge passes z-test
against real geometry; the snap pass itself (snap === 1 or 2)
only writes where points/lines pass that depth test, so JS can
read back and search outward from the cursor for the nearest
non-empty texel.
fsColorDeclarations() is intentionally NOT called by snap
techniques — they declare their MRT slot here.
ProtectedfsGenerates fragment-shader logic for the snap pass — emit the high-precision view-space position. The alpha channel is a kind tag so the JS read-back can tell apart:
snap === 3): alpha = 2.0 (surface depth-only)snap === 1): alpha = 1.0snap === 2): alpha = 1.0Read-back accepts alpha === 1.0 only, so init's surface texels
never get mistaken for vertex/edge hits — and crucially we don't
have to disable colour writes during init (some GL drivers
short-circuit fragment writes when the colour mask is fully off,
which also drops the depth-write side-effect).
Init pass also nudges the surface depth deeper by one pixel of
depth gradient (V2's length(vec2(dFdx, dFdy)) trick) so that
coplanar vertex/edge fragments in the snap pass reliably pass
LEQUAL against the rasterised surface depth. Without this bump,
interpolation noise occasionally pushes a visible vertex's
depth a hair past the surface's stored depth — the visible
vertex fails LEQUAL, doesn't write, and the read-back falls
back to whatever back-of-mesh vertices/edges managed to slip
through at the rasteriser's edge cases.
ProtectedfsSRGBEncodeInline gamma-2.2 sRGB encode on the working color.rgb. Use
when a technique writes straight to the default canvas
framebuffer without going through TonemapPipeline
(which is the usual sRGB encoder for the scene render) — for
example, the overlay-bin pass that runs after
PostProcessChain.composite so the gizmo / HUD layer doesn't
get tonemapped along with the rest of the scene.
Matches the same pow(c, 1/2.2) curve TonemapPipeline uses
when its uSRGBEncode uniform is set, so a colour authored as
(1, 0, 0) shows up identically whether it travelled through
tonemap or through this inline encoder. max(c, 0) guards
against negative inputs from bad source data — pow of a
negative is undefined and yields NaN on some GPUs.
Called between whichever chunk fills color (typically
fsDrawFlatColorLogic) and fsOutputColor.
ProtectedfsDeclares the thick-line fragment inputs. Call from a
thick-line technique's buildFragmentShader, after
fsPrecisionDeclarations and the colour-declaration
helpers it uses.
ProtectedfsDiscards fragments outside the thick-line's rounded-rectangle SDF,
without touching any color variable. Used by the pick and snap
passes — both rasterise the same quad expansion as the colour pass
but write a single MRT (IDs / view position) rather than a blended
colour, so the SDF coverage they want is binary "in / out" rather
than the soft 1-pixel falloff the colour pass uses.
Mirrors the SDF derivation in fsThickLineLogic (same
varyings, same joint-flag clamp skip) but uses sdf > 0.0 as the
discard threshold — keep every fragment whose coverage centre lies
within the rounded rectangle, drop the cap-extension corners that
sit outside it. Picking the rounded core (not the soft AA halo)
is what gives picking / snap a hit area that matches what the
user sees as the line's body.
Emit AFTER fsThickLineDeclarations so the varyings are declared, and BEFORE the pick/snap output is written.
ProtectedfsMultiplies color.a by signed-distance-field coverage
against a rounded rectangle: a line segment of length
lineLenPx swept to radius halfWidth. One SDF gives
round caps, smooth endpoint AA, and width-direction AA in
a single formula — and the clamp(0.5 - sdf, 0, 1) band
stays correct down to sub-pixel widths where a smoothstep
across |vSide| would collapse.
Emit AFTER the colour has been assigned to the working
color variable (typically after fsDrawFlatColorLogic)
and BEFORE fsOutputColor.
Initializes this draw technique by building and compiling the shader program.
Calls the abstract methods buildVertexShader and buildFragmentShader to generate the shader sources, then compiles the program and retrieves uniform/sampler locations.
ProtectedvsAppends a raw GLSL snippet to the vertex shader source being built.
ProtectedvsEmits uniforms, samplers, structs, and GPU data-texture helper functions shared by all techniques. Every vertex shader calls this once, right after vsHeader.
ProtectedvsDeclares the high-precision depth varying used for linearized depth rendering.
ProtectedvsProtectedGenerates vertex shader logic for depth rendering.
ProtectedvsDeclares the flat color varying used when each primitive carries a single solid color.
ProtectedvsProtectedGenerates vertex shader logic for flat color rendering.
ProtectedvsShadow-aware color pass: no-op under CSM. With N cascades the fragment
shader has to pick the right cascade per-fragment and transform
vViewPos on the fly — precomputing a single vShadowCoord in the
vertex stage would force a choice we can't make there. The required
varying (vViewPos) is already declared by Lambert shading.
Kept as a hook so technique subclasses that already call it don't break, and so future shadow techniques (e.g. non-Lambert receivers) can add their own vertex-side setup without changing callers.
ProtectedvsProtectedvsDeclares the flat color varying used when each vertex carries its own color.
ProtectedvsProtectedGenerates vertex shader logic for vertex color rendering.
ProtectedvsPulls the vertex a tiny fraction toward the camera in clip space so that
coplanar line/edge geometry wins depth-test ties against the triangle
surface it sits on. Subtracting eps * gl_Position.w from gl_Position.z
shifts NDC z by exactly eps regardless of vertex distance.
Kept small on purpose: the depth buffer is non-linear with perspective,
so a constant NDC offset covers proportionally more world distance at
the far plane than at the near plane. Too large an offset and distant
edges start poking through the front of foreground geometry. 2e-5 is
still hundreds of times the 24-bit depth-buffer quantum — plenty to
win ties from rasterisation noise — while leaving the world-space
leakage at the far plane negligible.
Emit AFTER vsMainBegin (which sets gl_Position) and before
vsMainEnd. Intended for edge/line techniques.
ProtectedvsDeclares the view-space depth varying consumed by fsEdgeFadeLogic.
Used only by edge techniques. Kept separate from vViewPos (the full
view-space position used by Lambert shading) because edge techniques
don't need the xy components — uploading just the linear distance halves
the varying interpolation cost.
ProtectedvsWrites positive view-space distance from the camera into the fade varying.
Camera looks down -Z, so the distance is -viewPos.z.
Emit AFTER vsMainBegin so viewPos is in scope, and before
vsMainEnd.
ProtectedvsAppends raw lines to the vertex shader source buffer.
ProtectedvsDeclares the screen-space hatch sampler + the flat varyings
the FS consumes. Call from a triangle-surface technique's
buildVertexShader after vsCommonDeclarations.
Five varyings — four vec4 line families + a vec4 ink
colour + a flat int count — keep the FS test branch-free
once the per-primitive resolution has run in the VS.
ProtectedvsResolves the per-mesh hatch slot into the flat varyings.
Emit AFTER vsMainBegin (so meshAttributeTexture is
in scope) and before vsMainEnd. Slot 0 means "no
hatch" — the resolution then writes zeros and vHatchCount
stays at 0, which the FS test short-circuits on.
ProtectedvsEmits the vertex shader version directive and identifying comment.
ProtectedvsDeclares the uniforms and varyings required by Lambert shading: three directional lights, ambient, the flat color varying, and the view-space position varying (used by the fragment shader for face-normal reconstruction via dFdx/dFdy).
ProtectedvsWrites the mesh's RGBA8 color into vColor and the view-space position into vViewPos, which the fragment shader uses for face-normal reconstruction (dFdx/dFdy).
ProtectedvsDeclare the vFragDepth varying that carries per-vertex
1.0 + gl_Position.w (i.e. view-space depth + 1) downstream
to the FS, where fsLogDepthLogic writes
gl_FragDepth per pixel.
No-op when logDepth is false on the technique, so a
technique that calls both this and vsLogDepthLogic
is identical to its non-log-depth sibling at the source
level — meaning no behavioural change until the technique
is constructed with logDepth: true.
Emit AFTER vsHeader (so the version directive is in place) and before vsMainBegin.
ProtectedvsPass view-space depth (1.0 + gl_Position.w) through to the
FS in the vFragDepth varying. The companion FS snippet
(fsLogDepthLogic) writes gl_FragDepth per pixel
using the exact log-depth formula, so the depth-buffer value
follows the true logarithmic curve regardless of how a
triangle stretches across view-space depth.
This replaces the previous "rewrite gl_Position.z in the
VS" implementation, which interpolated the log-depth value
linearly across each triangle. The linear interpolation
doesn't follow the log curve and produces visible artefacts
whenever a triangle's depth range is large — most painfully
around the camera plane during walkthroughs, where a single
floor/wall/ceiling triangle can span 50 cm to 30 m from the
eye and the per-fragment depth lands far enough off the
true curve to confuse the clipper. Writing the depth value
per pixel from the FS eliminates that interpolation error.
Trade-off: writing gl_FragDepth disables hardware early-Z
for these techniques (the GPU can't cull a fragment by depth
before running the FS that determines its depth).
No-op when logDepth is false.
Emit before vsMainEnd.
ProtectedvsOpens the vertex shader main() and emits the full mesh/geometry/transform pipeline (gl_VertexID → primitive → mesh → geometry → vertex → clip space). Technique-specific logic is appended after this call, before vsMainEnd.
ProtectedvsCloses the vertex shader main() function.
ProtectedvsDeclares the pick-pass uniforms, varyings, and the clip-space remapping helper used to render into the pick framebuffer.
ProtectedvsProtectedGenerates vertex shader logic for depth pick rendering.
ProtectedvsOpens the vertex shader main() for pick rendering. Identical to vsMainBegin but additionally reads and checks the per-mesh "pickable" render flag.
ProtectedvsProtectedGenerates vertex shader logic for pick rendering.
ProtectedvsDeclares uniforms that control point size and perspective attenuation.
ProtectedvsProtectedGenerates vertex shader logic for point size and intensity filtering.
ProtectedvsProtectedGenerates vertex shader logic for point size and intensity filtering.
ProtectedvsProtectedGenerates vertex shader logic for point size calculation.
ProtectedvsShadow-map depth pass: overrides gl_Position to use the light VP matrix.
Emitted AFTER vsMainBegin, which leaves viewPos in scope.
ProtectedvsDeclares the light view-projection matrix uniform used by both the shadow-map depth pass and the shadow-sampling color pass.
uShadowLightVP is expressed in CAMERA-VIEW space, not world space: it
maps camera-space positions to the light's clip space. This is so the
shader can apply it to viewPos (which is small, single-precision safe
and correct for every RTC tile) instead of worldPos (which is only
tile-local and has no true-world meaning for double-precision models).
ProtectedvsDeclares the silhouette color uniform and flat color varying.
ProtectedvsProtectedGenerates vertex shader logic for silhouette rendering.
ProtectedvsDeclares the varyings used by the universal section-plane clip test: world-space fragment position + a per-mesh clippability flag. Declared from every technique's VS so pick / snap / silhouette / edge / colour all share the same clip path — a fragment culled by the colour pass is also culled by the pick pass, the snap pass, etc.
vWorldPos is shared with the hatch and (optionally)
triplanar paths; they read the same varying.
ProtectedvsWrites the section-plane varyings — world-space position and the per-mesh clippable flag. Called from every technique's main() so the FS has a stable clip-test input.
ProtectedvsDeclares the snap-pass uniforms, varyings, and the clip-space remapping helper used to render into the snap framebuffer.
Mirrors vsPickDeclarations (snap reuses the same "render into
a small viewport centred on the cursor" trick) but only emits the
varying the snap fragment shader actually consumes — high-precision
view-space position. The helper remapSnapClipPos is byte-identical
to remapPickClipPos; declared separately so a snap technique can be
built without dragging in the pick-only varyings (vBatchIndex,
vMeshIndex) that would compile-error if both helpers shared the
same uniform names.
ProtectedvsSnap-pass vertex logic — exports view-space position and remaps
gl_Position into the small snap viewport. For vertex snap
(this.snap === 1) every vertex is rasterised as a 1-pixel point,
so gl_PointSize = 1.0 is set explicitly.
Emit AFTER vsMainBegin so viewPos and gl_Position are
in scope, and after vsSnapDeclarations so vSnapViewPosition
has been declared.
ProtectedvsDeclares the thick-line uniforms (uLineWidth,
drawingBufferSize) and the per-vertex AA varying. Call
once from a thick-line technique's buildVertexShader,
after vsCommonDeclarations.
The thick-line path expands each line into two triangles in
the vertex shader. drawingBufferSize converts the pixel
thickness into NDC; vSide carries the signed cross-line
coordinate (-1 at one edge, +1 at the other) to the
fragment shader for antialiasing.
When true, omit the
drawingBufferSize uniform declaration. Set this on
techniques that already declared the same uniform via
vsPickDeclarations or vsSnapDeclarations
— GLSL forbids re-declaring a uniform in the same scope.
ProtectedvsEmits the full thick-line main() body. Pulls both
endpoints of the current line, projects each to clip space,
computes a screen-space perpendicular, and offsets the
chosen endpoint by ±uLineWidth / 2 pixels.
Stands in for vsMainBegin; the technique's
buildVertexShader follows this with any colour / slicing /
varying logic the standard path emits AFTER vsMainBegin,
then closes with vsMainEnd.
vertsPerPrim must be 6 on the technique that calls this.
The standard _draw switch on LinesPrimitive then routes
to gl.TRIANGLES × 6 when this.thickLines is set.
Notifies draw technique that the WebGL context has been lost.
Notifies draw technique that the WebGL context has been restored.
This allows the technique to recreate its shaders after context loss.
Result indicating success or failure.
Draw technique for rendering colored point clouds.