2

I have positioned some plane meshes distributed evenly on an ellipse curve line.

On the animation loop, i'm moving them around on the ellipse curve with curve.getPointAt and time delta, then applying the matrix.

however, im also trying to add a scroll functionality by adding on the wheelY delta to this default orbit the planes already have.

But adding the delta values makes it 'jank' and then moving back fall in line with the original posiition. Which isnt ideal.

Any help on how i can achieve this would be much appreciated!

var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById("canvas"), antialias: true });
renderer.setClearColor(0xffffff);
//  use device aspect ratio //
renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window
renderer.setSize(window.innerWidth, window.innerHeight);

// SCENE
var scene = new THREE.Scene();

// CAMERA
var camera = new THREE.PerspectiveCamera(2, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 220;
camera.position.y = 200;
camera.lookAt(0, 0, 0);


// ELLIPTIC CURVE 
let curve = new THREE.EllipseCurve(0, 0, 7, 5);
let line = new THREE.Line(
  new THREE.BufferGeometry().setFromPoints(curve.getSpacedPoints(100)),
  new THREE.LineBasicMaterial({
    color: "red",
  })
);
line.rotation.x = -Math.PI * 0.5;
line.position.x = 0;
scene.add(line);

// MESH
var geometry = new THREE.PlaneGeometry(1.3, 2.8);
var material = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.FrontSide });

const caro_group = new THREE.Group();
scene.add(caro_group);

var image_count = 11;
var image_meshes = [];

for (let i = 0; i < image_count; i++) {
  image_meshes[i] = new THREE.Mesh(geometry, material);
  caro_group.add(image_meshes[i]);
}

var delta_y = 0;
let target_delta = 0;
let current_delta = 0;
const ease_delta = 0.075;

window.onwheel = function (e) {
  // use wheel delta for lerping rotation of meshes
  target_delta = e.deltaY * 0.008;
};

let clock = new THREE.Clock();
let v = new THREE.Vector3();

// RENDER + ANIMATE
function animate() {
  // rotation to add from mousewheel delta lerp
  var rot_toadd = (target_delta - current_delta) * ease_delta;

  let t = (clock.getElapsedTime() * 0.01) % 1;

  for (let i = 0; i < image_count; i++) {
    var point = ((1 / image_count) * i + t + rot_toadd) % 1;
    image_meshes[i].position.copy(curve.getPointAt(point, v));
    image_meshes[i].position.applyMatrix4(line.matrixWorld);
  }

  /* render scene and camera */
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

// RESIZE EVENTS
window.addEventListener("resize", onResize);

function onResize() {
  width = window.innerWidth;
  height = window.innerHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}
html ,body {
overflow:hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <canvas id="canvas"></canvas>
President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
wsgg
  • 934
  • 1
  • 20
  • 43

1 Answers1

0

The rotation is time based that is why shifting has no effect. And the position resets back according to current time. Instead of time, just use a variable for the angle increment. And add/subtract to the variable to adjust the position.
Set onwheel event on canvas and not on body.

var renderer = new THREE.WebGLRenderer({
  canvas: document.getElementById("canvas"),
  antialias: true
});
renderer.setClearColor(0xffffff);
//  use device aspect ratio //
renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window
renderer.setSize(window.innerWidth, window.innerHeight);

// SCENE
var scene = new THREE.Scene();

// CAMERA
var camera = new THREE.PerspectiveCamera(2, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 220;
camera.position.y = 200;
camera.lookAt(0, 0, 0);


// ELLIPTIC CURVE 
let curve = new THREE.EllipseCurve(0, 0, 7, 5);
let line = new THREE.Line(
  new THREE.BufferGeometry().setFromPoints(curve.getSpacedPoints(100)),
  new THREE.LineBasicMaterial({
    color: "red",
  })
);
line.rotation.x = -Math.PI * 0.5;
line.position.x = 0;
scene.add(line);

// MESH
var geometry = new THREE.PlaneGeometry(1.3, 2.8);
var material = new THREE.MeshBasicMaterial({
  color: 0xff0000,
  side: THREE.FrontSide
});
var greenMaterial = new THREE.MeshBasicMaterial({
  color: 'orange',
  side: THREE.FrontSide
});

const caro_group = new THREE.Group();
scene.add(caro_group);

var image_count = 9;
var image_meshes = [];

for (let i = 0; i < image_count; i++) {
  if (i == 0)
    image_meshes[i] = new THREE.Mesh(geometry, greenMaterial);
  else
    image_meshes[i] = new THREE.Mesh(geometry, material);
  caro_group.add(image_meshes[i]);
}

var delta_y = 0;
let target_delta = 0;
let current_delta = 0;
const ease_delta = 0.075;
let shift = 0;
let shiftBy = (1 / 180);
let timeout = 10;

// set the event on canvas so that entire html page won't scroll
canvas.onwheel = function(e) {
  // cancel the event propagation
  // we just want delta and no other effects of scrolling
  e.preventDefault();

  // use wheel delta for lerping rotation of meshes
  shift = (e.deltaY > 0) ? shiftBy * -6 : shiftBy * 2;
};

let clock = new THREE.Clock();
let v = new THREE.Vector3();
let ad = 0; // arc distance

// RENDER + ANIMATE
function animate() {
  // rotation to add from mousewheel delta lerp
  var rot_toadd = (target_delta - current_delta) * ease_delta;

  ad += (1 / 360) % 1;
  if (shift < 0 && ad < shift) {
    ad = 1 + shift;
  } else {
    if (shift < 0)
      timeout = 100;
    ad = (ad + shift) % 1;
  }
  shift = 0;


  for (let i = 0; i < image_count; i++) {
    var point = ((1 / image_count) * i + ad + rot_toadd) % 1;
    image_meshes[i].position.copy(curve.getPointAt(point, v));
    image_meshes[i].position.applyMatrix4(line.matrixWorld);
  }

  /* render scene and camera */
  renderer.render(scene, camera);

  // throttle update frequency
  setTimeout(() => {
    requestAnimationFrame(animate);
    timeout = 10;
  }, timeout);
}

requestAnimationFrame(animate);

// RESIZE EVENTS
window.addEventListener("resize", onResize);

function onResize() {
  width = window.innerWidth;
  height = window.innerHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}
html,
body {
  overflow: hidden;
}

#info {
  position: fixed;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<div id=info>Use mousewheel to shift positions.</div>
<canvas id="canvas"></canvas>
the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • i think perhaps my question was not clear. im not trying to set the speed the speed of the rotation based on mouse wheel. but actually add spin the carousel faster or scroll back (on top of the automated spin) like so: https://www.dropbox.com/s/45lmtqr2mkrjfxe/on-wheel.mp4?dl=0 (in this example, i was able to achieve this as the shape was a circle, not an ellipse, i could control the y rotation of the parent group) – wsgg Feb 03 '22 at 17:04
  • I've updated the answer. Strategy remains the same. With little bit of tweaking you can make it smoother. If you want you can try GreenSock [demo](https://codepen.io/bananafarma00/full/yLNNYJM) – the Hutt Feb 04 '22 at 07:06