【问题标题】:Rotating meshes on an ellipse curve with mousewheel delta使用鼠标滚轮增量在椭圆曲线上旋转网格
【发布时间】:2022-02-04 01:36:56
【问题描述】:

我已经将一些平面网格均匀分布在一条椭圆曲线上。

在动画循环中,我用curve.getPointAt 和时间增量在椭圆曲线上移动它们,然后应用矩阵。

但是,我还尝试通过将 wheelY 增量添加到飞机已有的默认轨道来添加滚动功能。

但是添加 delta 值会使其“卡顿”,然后返回到与原始位置一致的位置。这不理想。

任何关于我如何实现这一目标的帮助将不胜感激!

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>

【问题讨论】:

    标签: javascript three.js lerp


    【解决方案1】:

    轮换是基于时间的,这就是为什么移位没有效果。并且位置根据当前时间重置。而不是时间,只需使用角度增量的变量。并对变量进行加/减以调整位置。
    在画布上而不是在正文上设置 onwheel 事件。

    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>

    【讨论】:

    • 我想我的问题可能不清楚。我没有尝试根据鼠标滚轮设置旋转速度。但实际上更快地添加旋转木马或向后滚动(在自动旋转的顶部),如下所示:dropbox.com/s/45lmtqr2mkrjfxe/on-wheel.mp4?dl=0(在此示例中,我能够实现这一点,因为形状是圆形,而不是椭圆,我可以控制父组的 y 旋转)
    • 我已经更新了答案。策略保持不变。通过一点点调整,您可以使其更平滑。如果你愿意,你可以试试 GreenSock demo
    猜你喜欢
    • 2022-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-29
    相关资源
    最近更新 更多