Three.js:如何在鼠标悬停时将立方体变形为球体?

5

我想知道如何通过鼠标的移入移出来控制几何图形的变形。例如,当鼠标悬停在立方体上时,它会变形为一个球体,但是当鼠标离开对象时,它会恢复为立方体。

类似于此处将该立方体进行球化的动画:https://threejs.org/examples/#webgl_buffergeometry_morphtargets


3
我支持重新开放这个有用的问题,我不理解为什么它被关闭为“范围过大”。问题明确描述了一个非常具体的问题,可能受到广泛关注,并在3小时内得到了有效的答案。 - skomisa
您还可以在顶点着色器中混合/插值立方体和球体函数,使用鼠标作为t值。 - Felipe Gutierrez
@FelipeGutierrez 当你使用morphTargets时,着色器在内部发生的情况就是这样:https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl.js - prisoner849
1个回答

5

THREE.Raycaster()Tween.js 库结合使用可以解决问题。

这里只是一个例子,不是最终的解决方案:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(5, 7, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var boxGeom = new THREE.BoxBufferGeometry(7, 7, 7, 10, 10, 10);

// this is the shortened part from the official example to create the sphere morph targets
var pos = boxGeom.attributes.position;
boxGeom.morphAttributes.position = [];
var spherePositions = [];
var v3 = new THREE.Vector3();
for (var i = 0; i < pos.count; i++) {
  v3.fromBufferAttribute(pos, i).setLength((3.5 * Math.sqrt(3) + 3.5) * 0.5);
  spherePositions.push(v3.x, v3.y, v3.z);
}
boxGeom.morphAttributes.position[0] = new THREE.Float32BufferAttribute(spherePositions, 3);

var boxMat = new THREE.MeshBasicMaterial({
  color: "aqua",
  wireframe: true,
  morphTargets: true
});
var box = new THREE.Mesh(boxGeom, boxMat);
scene.add(box);

// user's custom properties and methods
box.userData.isHovering = false;
box.userData.currentAction = null;
box.userData.toSphere = () => {
  action(1);
}
box.userData.toBox = () => {
  action(0);
}

// tweening function
function action(influence) {

  if (box.userData.currentAction) box.userData.currentAction.stop();
  
  box.userData.currentAction = new TWEEN.Tween(box.morphTargetInfluences).to({
    "0": influence
  }, 1000).start();
  
}

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects = [];

window.addEventListener("mousemove", onMouseMove);

function onMouseMove(event) {

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  
  raycaster.setFromCamera(mouse, camera);
  
  intersects = raycaster.intersectObject(box);
  
  if (intersects.length > 0) {
  
    if (!box.userData.isHovering) {
    
      box.userData.toSphere();
      box.userData.isHovering = true;
      
    };
  } else {
  
    if (box.userData.isHovering) {
    
      box.userData.toBox();
      box.userData.isHovering = false;
      
    }
  }
}

renderer.setAnimationLoop(() => {

  TWEEN.update();
  renderer.render(scene, camera)
  
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.4.0/Tween.min.js"></script>


你为什么说这不是“最终解决方案”,考虑到你的代码恰好满足了OP的要求? - skomisa
@skomisa 是的,它可以,但总有改进的空间 :) - prisoner849
@prisoner849 你好,我想知道如何将几何图形居中放置在网页的中间? - panman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接