# Geomancy > Linear is nice, but slow. Those are naughty, but a bit faster. * All data types are monomorphic, unpacked and specialized. * `Mat4` and `Vec4` are `ByteArray#`. * `Mat4`x`Mat4` and `Mat4`x`Vec4` is done with SIMD. ## The Numbers Storing a list of transformations (e.g. rendering instance data): ``` poke 10 geomancy: OK 42.3 ns ± 1.4 ns, 0.47x linear: OK 90.5 ns ± 3.1 ns linear/T: OK 81.6 ns ± 2.7 ns ... 1000 geomancy: OK 2.85 μs ± 37 ns, 0.36x linear: OK 7.93 μs ± 132 ns linear/T: OK 7.08 μs ± 348 ns ``` Folding down a `gloss`-style scene tree is where it is all started: ``` multiply 2 geomancy: OK 12.3 ns ± 164 ps, 0.34x linear: OK 36.1 ns ± 1.3 ns ... 1000 geomancy: OK 7.71 μs ± 93 ns, 0.23x linear: OK 34.0 μs ± 1.3 μs ``` Add that time to the poking that'll follow. Sure, it is in the lower microseconds range, but this budget can be used elsewhere. ### Benchmarking and comparing ```sh stack bench --ba '--csv baseline.csv --stdev 2 --timeout 120' stack bench --ba '--baseline baseline.csv --fail-if-slower 5' ``` ## Conventions ### Matrix layout Transforms produced, composed, and applied to mimic the GLSL order (col-major): - `vec4 vPosOut = P * V * M * vPosIn;` - `vPosOut = (p <> v <> m) !* vPosIn` This way you don't have to transpose your transforms or fiddle with layout annotations. ### Projections / Views `Geomancy.Vulkan.Projection` is using the "reverse-depth" trick that remaps the vulkan default `[0; 1]` range to `[1; 0]`. This grants extra precision with one less parameter to specify (you only need "near" now), but makes handedness reasoning tricky. The default depth range the coordinate is left-handed (+X right, +Y down, +Z forward). But after reversing the depth it has to be paired with a right-handed view function like `Geomancy.Vulkan.View.lookAtRH`. The intended up vector is still `vec3 0 (-1) 0` -- +Y down. Silly as it sounds, this matches the XY plane of the window with XY plane in front of a "first person" camera. ### Rotations Axis rotations (using `rotateQ`) will appear clockwise when looking along the axis. Angle rotations follow Tait-Bryan angles (heading/elevation/bank or yaw/pitch/roll) in the y-x-z frame. - `rotateZ (time * rate)` will follow the clock hands in 2D scenes and roll in 3D. - `rotateX` will follow the sun from sunrise to sunset, increasing elevation / pitching UP. - `rotateY` will turn you right, increasing yaw/heading eastwards. Using `Geomancy.Quaternion.intrinsic roll pitch yaw` will make a rotation from the 3 angles in one go. You can use it to `rotate` a point directly (e.g `vec3 0 0 1` to get a direction vector from Quaternion) or commit to a matrix using `Transform.rotateQ`. ![yaw-pitch-roll](./yaw-pitch-roll.svg) You're of course free to define your own transforms, just copy the modules and tune to your liking. Just make sure that you use matching row/column constructors and the math layer will do the rest, fast. ## GLSL-like functions To further facilitate conversion between the host and shader code `Geomancy.Gl.Funs` provides common functions like `glFract` and `smoothstep`.