@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
115 lines • 11.9 kB
JavaScript
import { TgdDataset } from "./../../dataset/index.js";
import { TgdGeometry } from "./../../geometry/index.js";
const TAU = 2 * Math.PI;
/**
* The capsule is a 3D shape made of a cylinder
* and two hemispheres, all of radius 1.
* The roundness gives use the number of faces around the cylinder.
* Every vertex has 4 coordinates: x, y, z, and a number that will
* be 0.0 for bottom tip, and 1.1 for top tip.
* The cylinder is aligned along Z axis.
*/
export function makeCapsule(roundness) {
roundness = Math.max(3, roundness);
const tips = [];
const offset = [];
const elements = [];
const angleStepCylinder = makeCylinder(roundness, offset, tips, elements);
makeTip(roundness, angleStepCylinder, offset, tips, elements);
const capsule = new TgdDataset({
attTip: "float",
POSITION: "vec3",
NORMAL: "vec3",
});
capsule.set("POSITION", new Float32Array(offset));
capsule.set("attTip", new Float32Array(tips));
const geometry = new TgdGeometry({
dataset: capsule,
elements: new Uint16Array(elements),
computeNormalsIfMissing: true,
attPosition: "POSITION",
});
const { set, get } = capsule.getAttribAccessor("NORMAL");
// The cylinder must be really flat
for (let idx = 0; idx < roundness * 2; idx += 2) {
set(0, idx, 2);
set(0, idx + 1, 2);
const x = (get(idx, 0) + get(idx + 1, 0)) / 2;
const y = (get(idx, 1) + get(idx + 1, 1)) / 2;
set(x, idx, 0);
set(y, idx, 1);
set(x, idx + 1, 0);
set(y, idx + 1, 1);
}
// We collapse the cylinder because it will
// be instantiated with two tips points and radii.
for (let idx = 0; idx < tips.length; idx++) {
const shiftZ = tips[idx] === 0 ? +1 : -1;
offset[idx * 3 + 2] += shiftZ;
}
capsule.set("POSITION", new Float32Array(offset));
capsule.set("attTip", new Float32Array(tips));
return geometry;
}
function makeTip(roundness, angleStepCylinder, offset, tips, elements) {
const rings = Math.max(2, Math.ceil(roundness / 2));
const angleStepRing = (0.5 * Math.PI) / rings;
for (let ring = 1; ring < rings; ring++) {
const phi = angleStepRing * ring;
const z = Math.sin(phi);
const radius = Math.cos(phi);
for (let face1 = 0; face1 < roundness; face1++) {
const angle = angleStepCylinder * face1;
const x = Math.cos(angle) * radius;
const y = Math.sin(angle) * radius;
offset.push(x, y, z + 1);
tips.push(1);
offset.push(x, y, -z - 1);
tips.push(0);
const face2 = (face1 + 1) % roundness;
const idx0 = (ring - 1) * roundness * 2;
const idx1 = ring * roundness * 2;
const top1r0 = idx0 + face1 * 2;
const top2r0 = idx0 + face2 * 2;
const top1r1 = idx1 + face1 * 2;
const top2r1 = idx1 + face2 * 2;
elements.push(top1r0, top2r0, top2r1);
elements.push(top2r1, top1r1, top1r0);
elements.push(top1r0 + 1, top2r1 + 1, top2r0 + 1);
elements.push(top2r1 + 1, top1r0 + 1, top1r1 + 1);
}
}
offset.push(0, 0, +2);
tips.push(1);
offset.push(0, 0, -2);
tips.push(0);
const baseIndex = tips.length - 2 * (roundness + 1);
const endIndex = tips.length - 2;
for (let face0 = 0; face0 < roundness; face0++) {
const face1 = (face0 + 1) % roundness;
const idx0 = face0 * 2 + baseIndex;
const idx1 = face1 * 2 + baseIndex;
elements.push(idx0 + 0, idx1 + 0, endIndex + 0);
elements.push(idx1 + 1, idx0 + 1, endIndex + 1);
}
}
function makeCylinder(roundness, offset, tips, elements) {
const angleStep = TAU / roundness;
for (let face = 0; face < roundness; face++) {
const angle = angleStep * face;
const x = Math.cos(angle);
const y = Math.sin(angle);
offset.push(x, y, +1);
tips.push(1);
offset.push(x, y, -1);
tips.push(0);
const top1 = face * 2;
const bottom1 = top1 + 1;
const top2 = ((face + 1) % roundness) * 2;
const bottom2 = top2 + 1;
elements.push(top2, top1, bottom1);
elements.push(top2, bottom1, bottom2);
}
return angleStep;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fwc3VsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wYWludGVyL3NlZ21lbnRzL2NhcHN1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUN6QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRTNDLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFBO0FBRXZCOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUFDLFNBQWlCO0lBQ3pDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQTtJQUNsQyxNQUFNLElBQUksR0FBYSxFQUFFLENBQUE7SUFDekIsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFBO0lBQzNCLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQTtJQUM3QixNQUFNLGlCQUFpQixHQUFHLFlBQVksQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQTtJQUN6RSxPQUFPLENBQUMsU0FBUyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDN0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUM7UUFDM0IsTUFBTSxFQUFFLE9BQU87UUFDZixRQUFRLEVBQUUsTUFBTTtRQUNoQixNQUFNLEVBQUUsTUFBTTtLQUNqQixDQUFDLENBQUE7SUFDRixPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxJQUFJLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFBO0lBQ2pELE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7SUFDN0MsTUFBTSxRQUFRLEdBQUcsSUFBSSxXQUFXLENB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