Skip to content

Instantly share code, notes, and snippets.

@yiwenl
Last active September 24, 2023 16:46
Show Gist options
  • Save yiwenl/d7af349a659472a974871421bf4f6414 to your computer and use it in GitHub Desktop.
Save yiwenl/d7af349a659472a974871421bf4f6414 to your computer and use it in GitHub Desktop.
Bezier Curve with gl-matrix
import { vec2 } from "gl-matrix";
export const bezier = (mPoints, t) => {
if (mPoints.length === 2) {
const p = vec2.create();
vec2.lerp(p, mPoints[0], mPoints[1], t);
return p;
}
const a = [];
for (let i = 0; i < mPoints.length - 1; i++) {
const p = vec2.create();
vec2.lerp(p, mPoints[i], mPoints[i + 1], t);
a.push(p);
}
return bezier(a, t);
};
import { vec3 } from "gl-matrix";
export const bezier = (mPoints, t) => {
if (mPoints.length === 2) {
const p = vec3.create();
vec3.lerp(p, mPoints[0], mPoints[1], t);
return p;
}
const a = [];
for (let i = 0; i < mPoints.length - 1; i++) {
const p = vec3.create();
vec3.lerp(p, mPoints[i], mPoints[i + 1], t);
a.push(p);
}
return bezier(a, t);
};
// Function to compute the distance between two 3D points
const distance = (a, b) => vec3.distance(a, b);
export const equidistantBezierPoints = (mPoints, numPoints) => {
const sampledPoints = [];
const arcLengths = [0];
// 1. Densely sample the curve
for (let i = 0; i <= 1; i += 0.01) {
sampledPoints.push(bezier(mPoints, i));
}
// 2. Compute cumulative distance
for (let i = 1; i < sampledPoints.length; i++) {
const d = distance(sampledPoints[i - 1], sampledPoints[i]);
arcLengths.push(arcLengths[i - 1] + d);
}
// 3. Determine desired spacing
const totalLength = arcLengths[arcLengths.length - 1];
const desiredSpacing = totalLength / (numPoints - 1);
const equidistantPoints = [sampledPoints[0]];
let currentArcLength = 0;
// 4. Find equidistant points
// 4. Find equidistant points
for (let i = 1; i < numPoints; i++) {
currentArcLength += desiredSpacing;
const idx = arcLengths.findIndex((len) => len > currentArcLength);
// Check if an index was found. If not, use the last point.
if (idx === -1 || idx === 0) {
equidistantPoints.push(sampledPoints[sampledPoints.length - 1]);
} else {
equidistantPoints.push(sampledPoints[idx - 1]);
// or interpolate between idx-1 and idx for more accuracy
}
}
return equidistantPoints;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment