1import type { MeshData } from './types'
3/**
4 * A torus with analytic normals and rainbow vertex colors — carries every
5 * attribute the richest format supports, so lossy export is easy to see.
6 */
7export function makeSampleMesh(): MeshData {
8 const R = 1.0
9 const r = 0.4
10 const nu = 64 // around the main ring
11 const nv = 32 // around the tube
13 const positions: number[] = []
14 const normals: number[] = []
15 const colors: number[] = []
16 const indices: number[] = []
18 for (let i = 0; i < nu; i++) {
19 const u = (i / nu) * 2 * Math.PI
20 for (let j = 0; j < nv; j++) {
21 const v = (j / nv) * 2 * Math.PI
22 positions.push(
23 (R + r * Math.cos(v)) * Math.cos(u),
24 r * Math.sin(v),
25 (R + r * Math.cos(v)) * Math.sin(u),
26 )
27 normals.push(Math.cos(v) * Math.cos(u), Math.sin(v), Math.cos(v) * Math.sin(u))
28 colors.push(...hslToRgb(i / nu, 0.8, 0.55))
29 }
30 }
31 for (let i = 0; i < nu; i++) {
32 for (let j = 0; j < nv; j++) {
33 const a = i * nv + j
34 const b = ((i + 1) % nu) * nv + j
35 const c = i * nv + ((j + 1) % nv)
36 const d = ((i + 1) % nu) * nv + ((j + 1) % nv)
37 indices.push(a, b, d, a, d, c)
38 }
39 }
41 return {
42 positions: new Float32Array(positions),
43 indices: new Uint32Array(indices),
44 normals: new Float32Array(normals),
45 colors: new Float32Array(colors),
46 }
47}
49function hslToRgb(h: number, s: number, l: number): [number, number, number] {
50 const f = (n: number) => {
51 const k = (n + h * 12) % 12
52 return l - s * Math.min(l, 1 - l) * Math.max(-1, Math.min(k - 3, 9 - k, 1))
53 }
54 return [f(0), f(8), f(4)]
55}