@sveltejs/gl
Version:
A (very experimental) project to bring WebGL to Svelte
159 lines (132 loc) • 3.19 kB
JavaScript
import Geometry from './Geometry.mjs';
import { memoize, normalize } from '../internal/utils.mjs';
const p = 0.85065080835204;
const q = 0.5257311121191336;
const position = new Float32Array([
-q, +p, 0,
+q, +p, 0,
-q, -p, 0,
+q, -p, 0,
0, -q, +p,
0, +q, +p,
0, -q, -p,
0, +q, -p,
+p, 0, -q,
+p, 0, +q,
-p, 0, -q,
-p, 0, +q
]);
const index = new Uint16Array([
0, 11, 5,
0, 5, 1,
0, 1, 7,
0, 7, 10,
0, 10, 11,
1, 5, 9,
5, 11, 4,
11, 10, 2,
10, 7, 6,
7, 1, 8,
3, 9, 4,
3, 4, 2,
3, 2, 6,
3, 6, 8,
3, 8, 9,
4, 9, 5,
2, 4, 11,
6, 2, 10,
8, 6, 7,
9, 8, 1
]);
const smooth_geometry = [
new Geometry({
position: { data: position, size: 3 },
normal: { data: position, size: 3 }
}, { index })
];
function subdivide(geometry) {
const index = new Uint32Array(geometry.index.length * 4);
const old_position = geometry.attributes.position.data;
const new_positions = [];
const lookup = new Map();
function get_index(point) {
const hash = `${point[0].toPrecision(6)},${point[1].toPrecision(6)},${point[2].toPrecision(6)}`;
if (lookup.has(hash)) {
return lookup.get(hash);
}
const index = new_positions.length;
lookup.set(hash, index);
new_positions[index] = point;
return index;
}
function mid(a, b) {
return get_index([
(a[0] + b[0]) / 2,
(a[1] + b[1]) / 2,
(a[2] + b[2]) / 2
]);
}
for (let i = 0; i < geometry.index.length; i += 3) {
const c0 = geometry.index[i + 0];
const c1 = geometry.index[i + 1];
const c2 = geometry.index[i + 2];
const v0 = [
old_position[c0 * 3 + 0],
old_position[c0 * 3 + 1],
old_position[c0 * 3 + 2]
];
const v1 = [
old_position[c1 * 3 + 0],
old_position[c1 * 3 + 1],
old_position[c1 * 3 + 2]
];
const v2 = [
old_position[c2 * 3 + 0],
old_position[c2 * 3 + 1],
old_position[c2 * 3 + 2]
];
const a = mid(v0, v1);
const b = mid(v1, v2);
const c = mid(v2, v0);
// four new faces
const j = i * 4;
index[j + 0] = get_index(v0);
index[j + 1] = a;
index[j + 2] = c;
index[j + 3] = get_index(v1);
index[j + 4] = b;
index[j + 5] = a;
index[j + 6] = get_index(v2);
index[j + 7] = c;
index[j + 8] = b;
index[j + 9] = a
index[j + 10] = b;
index[j + 11] = c;
}
const position = new Float32Array(new_positions.length * 3);
for (let i = 0; i < new_positions.length; i += 1) {
const vector = normalize(new_positions[i]);
position[i * 3 + 0] = vector[0];
position[i * 3 + 1] = vector[1];
position[i * 3 + 2] = vector[2];
}
return new Geometry({
position: { data: position, size: 3 },
normal: { data: position, size: 3 }
}, { index })
}
function create_smooth_geometry(subdivisions = 0) {
if (!smooth_geometry[subdivisions]) {
const geometry = create_smooth_geometry(subdivisions - 1);
smooth_geometry[subdivisions] = subdivide(geometry);
}
return smooth_geometry[subdivisions];
}
function create_flat_geometry(subdivisions) {
throw new Error(`TODO implement flat sphere geometry`);
}
export default memoize(({ subdivisions = 0, shading = 'smooth' } = {}) => {
return shading === 'smooth'
? create_smooth_geometry(subdivisions)
: create_flat_geometry(subdivisions);
});