I am working with the OGL framework and using a looping path to move sphere geometries along it.
The movement starts off well, but slowly morphs the path shape in to a circle. There is a lerp function in the requestAnimationFrame, but looks like each sphere is moving only a percentage towards the +1 index before changing to the one after that, i.e. +2 and so on.
Why is this happening?
Sandbox link: https://codesandbox.io/s/cool-shirley-wddd8v
import { Renderer, Camera, Orbit, Transform, Program, Mesh, Sphere, Polyline, Vec3, Color, Path } from 'https://unpkg.com/ogl';
const vertex = /* glsl */ `
attribute vec3 position;
attribute vec3 normal;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
varying vec3 vNormal;
void main() {
vNormal = normalize(normalMatrix * normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}`;
const fragmentColor = /* glsl */ `
precision highp float;
varying vec3 vNormal;
void main() {
vec3 normal = normalize(vNormal);
float lighting = dot(normal, normalize(vec3(-0.3, 0.8, 0.6)));
gl_FragColor.rgb = vec3(0.24, 0.84, 1.0) + lighting * 0.1;
gl_FragColor.a = 1.0;
}`;
const renderer = new Renderer({ dpr: 2 });
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
gl.clearColor(.1, .1, .1, 1);
const camera = new Camera(gl, { fov: 75 });
camera.position.set(0, 0, 2);
const controls = new Orbit(camera, {
target: new Vec3(0, 0, 0)
});
function resize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.perspective({ aspect: gl.canvas.width / gl.canvas.height });
}
window.addEventListener('resize', resize, false);
resize();
const scene = new Transform();
const sphereGeom = new Sphere(gl);
const sphereProg = new Program(gl, { vertex, fragment: fragmentColor });
// First three is for moveTo command, rest for bezierCurveTo command
const pathCoords = [-1.0, 0.0, 0.0, -0.9368709325790405, 0.1762027144432068, 0.04529910162091255, -0.7061498761177063, 0.089231938123703, 0.19381383061408997, -0.6332840919494629, 0.2674865424633026, 0.1930660903453827, -0.5615311861038208, 0.4430185854434967, 0.1923297792673111, -0.7734173536300659, 0.5522762537002563, 0.08718681335449219, -0.7070468664169312, 0.7070468664169312, 0.0, -0.6498651504516602, 0.8403899073600769, -0.07511603832244873, -0.5399253368377686, 0.8584117889404297, -0.16668838262557983, -0.38917776942253113, 0.921392560005188, -0.1677459478378296, -0.23391252756118774, 0.9862607717514038, -0.16883520781993866, -0.14611071348190308, 1.0727460384368896, -0.04093937203288078, 0.0, 1.0, 0.0, 0.1674281358718872, 0.9166403412818909, 0.046912387013435364, 0.07777689397335052, 0.6478093862533569, -0.06732462346553802, 0.2400655597448349, 0.5683639645576477, 0.0, 0.4298238456249237, 0.4754713177680969, 0.07872024923563004, 0.49316900968551636, 0.7766210436820984, 0.32597726583480835, 0.7070468664169312, 0.7070468664169312, 0.3101717531681061, 0.8896822333335876, 0.647635817527771, 0.29667505621910095, 0.8556811809539795, 0.5579423308372498, 0.06533028930425644, 0.921392560005188, 0.38917776942253113, 0.0, 0.9742976427078247, 0.2533031702041626, -0.05259828269481659, 1.0508142709732056, 0.14183028042316437, -0.036462459713220596, 1.0, 0.0, 0.0, 0.9368709325790405, -0.1762027144432068, 0.04529910162091255, 0.7061498761177063, -0.089231938123703, 0.19381383061408997, 0.6332840919494629, -0.2674865424633026, 0.1930660903453827, 0.5615311861038208, -0.4430185854434967, 0.1923297792673111, 0.7734173536300659, -0.5522762537002563, 0.08718681335449219, 0.7070468664169312, -0.7070468664169312, 0.0, 0.6498651504516602, -0.8403899073600769, -0.07511603832244873, 0.5399253368377686, -0.8584117889404297, -0.16668838262557983, 0.38917776942253113, -0.921392560005188, -0.1677459478378296, 0.23391252756118774, -0.9862607717514038, -0.16883520781993866, 0.14611071348190308, -1.0727460384368896, -0.04093937203288078, 0.0, -1.0, 0.0, -0.1674281358718872, -0.9166403412818909, 0.046912387013435364, -0.07777689397335052, -0.6478093862533569, -0.06732462346553802, -0.2400655597448349, -0.5683639645576477, 0.0, -0.4298238456249237, -0.4754713177680969, 0.07872024923563004, -0.49316900968551636, -0.7766210436820984, 0.32597726583480835, -0.7070468664169312, -0.7070468664169312, 0.3101717531681061, -0.8896822333335876, -0.647635817527771, 0.29667505621910095, -0.8556811809539795, -0.5579423308372498, 0.06533028930425644, -0.921392560005188, -0.38917776942253113, 0.0, -0.9742976427078247, -0.2533031702041626, -0.05259828269481659, -1.0508142709732056, -0.14183028042316437, -0.036462459713220596, -1.0, 0.0, 0.0];
// Constructing path from cubic Bezier segments.
// Also available `quadraticCurveTo` and `lineTo` commands
const path = new Path();
path.moveTo(new Vec3(pathCoords[0], pathCoords[1], pathCoords[2]));
for (let i = 3; i < pathCoords.length; i += 9) {
const cp1 = new Vec3(pathCoords[i + 0], pathCoords[i + 1], pathCoords[i + 2]);
const cp2 = new Vec3(pathCoords[i + 3], pathCoords[i + 4], pathCoords[i + 5]);
const p = new Vec3(pathCoords[i + 6], pathCoords[i + 7], pathCoords[i + 8]);
path.bezierCurveTo(cp1, cp2, p);
}
const pathSubdivisions = 256;
const points = path.getPoints(pathSubdivisions);
let spheres = [];
for (let i = 0; i < points.length - 1; i++) {
const point = points[i];
const sphere = new Mesh(gl, {
geometry: sphereGeom,
program: sphereProg
});
sphere.scale.set(0.006);
sphere.position = point;
sphere.setParent(scene);
spheres.push(sphere);
}
function update(now) {
const progress = (now * 0.00001) % 1;
// take current Frenet frame
const frameIndex = Math.floor(progress * pathSubdivisions);
const frameProgress = progress * pathSubdivisions % 1;
spheres.forEach((sphere, idx) => {
let nextIdx = (idx + 1) % (points.length -1 );
sphere.position
.copy(points[idx])
.lerp(points[nextIdx], 0.06);
})
renderer.render({ scene, camera });
controls.update();
requestAnimationFrame(update);
}
requestAnimationFrame(update);