\chapter{Practical guidance} \label{ch:practical} \section{Choosing sample counts} The most common practical adjustment in this package is the choice of sample counts. A curve with \verb|usamples=8| may be sufficient to establish the shape of an arc, while a surface that is meant to carry lighting cleanly may need a denser tessellation. There is no universal rule, but there is a useful discipline: start with the coarsest tessellation that communicates the shape, then increase counts only where the figure demands it. That advice matters because more samples mean more simplices, and more simplices mean more work for partitioning, filtering, and occlusion sorting. Solids are especially expensive because three sample directions affect the boundary tessellation. \section{Writing source that remains readable} The package rewards a style of source code in which repeated objects are named, transformations are factored out, and filters are short enough to be read as mathematical statements. In practical terms, this usually means using \verb|\setobject| for recurring matrices or vectors, keeping draw and fill styles consistent within a figure, and separating logically distinct scene elements into their own append commands. It is also wise to keep the final call to \verb|\displaysimplices| visibly separate from the scene construction above it. That single line is the moment at which the scene is committed to the page. \section{Troubleshooting a figure} When a figure behaves unexpectedly, four checks usually resolve the issue. \begin{description} \item[Bracing] Make sure that Lua expressions containing commas are wrapped in braces. \item[Sample counts] Check that \verb|usamples|, \verb|vsamples|, and \verb|wsamples| are at least~2 where required. \item[Transformation order] Re-read composed matrices from left to right in the order applied to points. See Appendix~\ref{ch:linalg} for the composition convention. \item[Filter semantics] Remember that filters act on tessellated simplices, not on symbolic objects. \end{description} Two further behaviors are worth remembering because they can initially look like errors. Labels are drawn after the geometry, and lights are cleared after each display call. Both behaviors are intentional. \section{Illustration program for the manual} Since this document is intended to become an illustrated manual, the figures should do more than decorate the text. Each figure ought to settle a specific question in the reader's mind. The most useful illustrations are therefore not merely attractive scenes, but comparisons and decompositions: before-and-after occlusion, coarse versus fine tessellation, filtered versus unfiltered geometry, and the effect of changing the transformation order. \begin{figure}[tbp] \centering \begin{tikzpicture} \setobject[ name=view, object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))} ] \appendlight[v={return Vector:new{1,1,2,1}}] \appendsurface[ ustart=-1.5, ustop=1.5, usamples=12, vstart=-1.5, vstop=1.5, vsamples=12, v={return Vector:new{u, v, 0.4*u, 1}}, transformation={view}, fill options={fill=blue!60!ltdtbrightness, draw=blue!30!black, very thin} ] \appendsurface[ ustart=-1.5, ustop=1.5, usamples=12, vstart=-1.5, vstop=1.5, vsamples=12, v={return Vector:new{u, 0.4*v, v, 1}}, transformation={view}, fill options={fill=orange!60!ltdtbrightness, draw=orange!30!black, very thin} ] \displaysimplices \end{tikzpicture} \caption{Two intersecting tilted planes rendered with occlusion-aware sorting. The package partitions the simplices where the surfaces cross and draws them in the correct depth order. Without the pipeline, one surface would simply paint over the other.} \end{figure} \begin{figure}[tbp] \centering \begin{tikzpicture} \setobject[ name=view, object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))} ] \appendlight[v={return Vector:new{1,1,2,1}}] \appendsurface[ ustart=0, ustop=tau, usamples=6, vstart=0, vstop=pi, vsamples=4, v={return Vector:new{sin(v)*cos(u)-4, sin(v)*sin(u), cos(v), 1}}, transformation={view}, fill options={fill=ltdtbrightness, draw=black, thin} ] \appendsurface[ ustart=0, ustop=tau, usamples=12, vstart=0, vstop=pi, vsamples=8, v={return Vector:new{sin(v)*cos(u), sin(v)*sin(u), cos(v), 1}}, transformation={view}, fill options={fill=ltdtbrightness, draw=black, very thin} ] \appendsurface[ ustart=0, ustop=tau, usamples=24, vstart=0, vstop=pi, vsamples=16, v={return Vector:new{sin(v)*cos(u)+4, sin(v)*sin(u), cos(v), 1}}, transformation={view}, fill options={fill=ltdtbrightness, draw=black, ultra thin} ] \appendlabel[ v={return Vector:new{-4,-1.8,0,1}}, text={$6\times4$} ] \appendlabel[ v={return Vector:new{0,-1.8,0,1}}, text={$12\times8$} ] \appendlabel[ v={return Vector:new{4,-1.8,0,1}}, text={$24\times16$} ] \displaysimplices \end{tikzpicture} \caption{The same sphere at three sampling densities. At~$6\times4$ the shape is barely recognizable; at~$12\times8$ the sphere is clear but faceted; at~$24\times16$ the surface appears smooth. Higher sample counts produce more simplices for partitioning and sorting, so the tradeoff is visual fidelity against compile time.} \end{figure} \begin{figure}[tbp] \centering \begin{tikzpicture} \setobject[ name=view, object={Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))} ] \appendlight[v={return Vector:new{1,1,2,1}}] \appendsurface[ ustart=-1, ustop=1, usamples=16, vstart=-1, vstop=1, vsamples=16, v={return Vector:new{2*u, 2*v, 1.2*exp(-2*(u*u+v*v)), 1}}, transformation={view}, fill options={fill=cyan!30!ltdtbrightness, draw=black, very thin} ] \appendcurve[ ustart=0, ustop=tau, usamples=36, v={return Vector:new{0.7*cos(u), 0.7*sin(u), 1.2*exp(-2*0.49), 1}}, transformation={view}, draw options={thick, red, dashed} ] \appendpoint[ v={return Vector:new{0,0,1.2,1}}, transformation={view}, fill options={fill=black} ] \appendlabel[ v={return Vector:new{0.3,0.3,1.5,1}}, transformation={view}, text={peak} ] \appendlabel[ v={return Vector:new{1.0,0.6,0.2,1}}, transformation={view}, text={level curve} ] \displaysimplices \end{tikzpicture} \caption{A Gaussian bump with a labelled peak and a dashed level curve. Labels are emitted after the geometry and therefore appear as an annotation layer on top of the scene.} \end{figure} \begin{figure}[tbp] \centering \begin{tikzpicture} \setobject[ name = {view}, object = {Matrix.xrotation3(-pi/5):multiply(Matrix.zrotation3(pi/6))} ] \appendlight[v={return Vector:new{1, 1, 2, 1}}] \setobject[ name = {viewinverse}, object = {view:inverse()} ] % Sphere \appendsurface[ ustart = {0}, ustop = {tau}, usamples = {20}, vstart = {0}, vstop = {pi}, vsamples = {14}, v = {return Vector:new{ 1.5*sin(v)*cos(u), 1.5*sin(v)*sin(u), 1.5*cos(v), 1 }}, transformation = {view}, fill options = { preaction = {fill=blue!20!ltdtbrightness}, postaction = {draw=blue!30!black, line width=0.15pt, line join=round} } ] % Intersecting disc \appendsurface[ ustart = {-2}, ustop = {2}, usamples = {10}, vstart = {-2}, vstop = {2}, vsamples = {10}, v = {return Vector:new{u, v, 0.3*u + 0.2, 1}}, transformation = {view}, fill options = { preaction = {fill=orange!30!ltdtbrightness, fill opacity=0.65}, postaction = {draw=orange!50!black, line width=0.2pt, line join=round} }, filter = { local M = A:hadd(B):hadd(C):hscale(1/3):multiply(viewinverse) return M[1]*M[1] + M[2]*M[2] <= 4.01 } ] \displaysimplices \end{tikzpicture} \caption{A sphere intersected by a tilted disc. The package partitions both the sphere and the disc where they cross, producing fragments that are drawn in the correct depth order. The disc's filter clips it to a circular region, demonstrating how filtering and partitioning cooperate in a single scene.} \end{figure} \begin{figure}[tbp] \centering \begin{tikzpicture} \setobject[ name = {T}, object = { Matrix.zyzrotation3(pi/2, pi/3, 5.25*pi/6) :multiply(Matrix.translate3(0, 0, -5)) } ] \setobject[ name = {Tinv}, object = {T:inverse()} ] \appendlight[v={return Vector:new{1, 1, 1, 1}}] % Surface: z = u^4 + v^4 − 4uv + 1 \appendsurface[ ustart = {-2}, ustop = {2}, usamples = {20}, vstart = {-2}, vstop = {2}, vsamples = {20}, v = {return Vector:new{u, v, u^4 + v^4 - 4*u*v + 1, 1}}, transformation = {T}, fill options = { preaction = {fill=green, fill opacity=0.2}, postaction = {draw=blue, ultra thin, line join=round} }, filter = { local a = A:multiply(Tinv) local b = B:multiply(Tinv) local c = C:multiply(Tinv) return abs(a[3]) < 2.01 and abs(b[3]) < 2.01 and abs(c[3]) < 2.01 and abs(a[2]) < 2.01 and abs(b[2]) < 2.01 and abs(c[2]) < 2.01 and abs(a[1]) < 2.01 and abs(b[1]) < 2.01 and abs(c[1]) < 2.01 } ] % Wireframe box \appendsolid[ ustart = {-2}, ustop = {2}, usamples = {2}, vstart = {-2}, vstop = {2}, vsamples = {2}, wstart = {-2}, wstop = {2}, wsamples = {2}, v = {return Vector:new{u, v, w, 1}}, transformation = {T}, fill options = { preaction = {fill=none, fill opacity=0.5}, postaction = {draw=none, ultra thin, line join=round, line cap=round} } ] % Coordinate axes \appendcurve[ ustart = {0}, ustop = {4}, usamples = {2}, v = {return Vector:new{u, 0, 0, 1}}, transformation = {T}, arrow tip = {fill=black}, draw options = {draw, ultra thin, line cap=round} ] \appendlabel[ v = {return Vector:new{4.3, 0, 0, 1}}, transformation = {T}, text = {\(x\)} ] \appendcurve[ ustart = {0}, ustop = {4}, usamples = {2}, v = {return Vector:new{0, u, 0, 1}}, transformation = {T}, arrow tip = {fill=black}, draw options = {draw, ultra thin, line cap=round} ] \appendlabel[ v = {return Vector:new{0, 4.3, 0, 1}}, transformation = {T}, text = {\(y\)} ] \appendcurve[ ustart = {0}, ustop = {4}, usamples = {2}, v = {return Vector:new{0, 0, u, 1}}, transformation = {T}, arrow tip = {fill=black}, draw options = {draw, ultra thin, line cap=round} ] \appendlabel[ v = {return Vector:new{0, 0, 4.3, 1}}, transformation = {T}, text = {\(z\)} ] \displaysimplices \end{tikzpicture} \caption{The surface $z = u^4 + v^4 - 4uv + 1$ rendered inside a bounding box with labelled coordinate axes. The filter clips the surface to the box by transforming each triangle's vertices back to the local frame and testing all three coordinates against the box limits. Arrow-tipped curves serve as axes, and labels provide annotation. This style of figure---a surface, a bounding volume, axes, and labels---is a common pattern for mathematics illustrations.} \end{figure}