(vertices: Float32Array)
| 8 | * @param vertices - vertex positions as x,y,z triplets |
| 9 | */ |
| 10 | export function normalizeVertices(vertices: Float32Array) { |
| 11 | const len = vertices.length; |
| 12 | let minX = Infinity; |
| 13 | let minY = Infinity; |
| 14 | let minZ = Infinity; |
| 15 | let maxX = -Infinity; |
| 16 | let maxY = -Infinity; |
| 17 | let maxZ = -Infinity; |
| 18 | |
| 19 | // single pass to find bounds — cache indexed reads |
| 20 | for (let i = 0; i < len; i += 3) { |
| 21 | const x = vertices[i]; |
| 22 | const y = vertices[i + 1]; |
| 23 | const z = vertices[i + 2]; |
| 24 | if (x < minX) { |
| 25 | minX = x; |
| 26 | } |
| 27 | if (x > maxX) { |
| 28 | maxX = x; |
| 29 | } |
| 30 | if (y < minY) { |
| 31 | minY = y; |
| 32 | } |
| 33 | if (y > maxY) { |
| 34 | maxY = y; |
| 35 | } |
| 36 | if (z < minZ) { |
| 37 | minZ = z; |
| 38 | } |
| 39 | if (z > maxZ) { |
| 40 | maxZ = z; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | const cx = (minX + maxX) * 0.5; |
| 45 | const cy = (minY + maxY) * 0.5; |
| 46 | const cz = (minZ + maxZ) * 0.5; |
| 47 | // precompute reciprocal to replace division with multiplication in the loop |
| 48 | const invScale = |
| 49 | 1.0 / Math.max(maxX - minX || 1, maxY - minY || 1, maxZ - minZ || 1); |
| 50 | |
| 51 | for (let i = 0; i < len; i += 3) { |
| 52 | vertices[i] = (vertices[i] - cx) * invScale; |
| 53 | vertices[i + 1] = (vertices[i + 1] - cy) * invScale; |
| 54 | vertices[i + 2] = (vertices[i + 2] - cz) * invScale; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Project 3D vertices through a 4x4 matrix with perspective divide, |
no outgoing calls
no test coverage detected