Last active
September 24, 2023 16:46
-
-
Save yiwenl/d7af349a659472a974871421bf4f6414 to your computer and use it in GitHub Desktop.
Bezier Curve with gl-matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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