ThreeJS - How do I scale down intersected object o

2019-08-03 10:53发布

I have n+1 hexshapes in a honeycomb grid. The objects are stacked close together. With this code:

// Get intersected objects, a.k.a objects "hit" by mouse, a.k.a objects that are mouse-overed
const intersects = raycaster.intersectObjects(hexObjects);

// If there is one (or more) intersections
let scaleTween = null;
if (intersects.length > 0) {
  // If mouse is not currently over an object

  // Set cursor to pointer so that the user can see that the object is clickable
  document.body.style.cursor = 'pointer';

  // Get the last intersected object, it's most likely that object we are currently hovering
  const is = intersects.length > 0 ? intersects.length - 1 : 0;

  // Is the object hovered over for the first time?
  if (INTERSECTED === null) {
    // Save current hovered object
    INTERSECTED = intersects[is].object;
    // HIGHLIGHT
    // Save current color
    INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
    // Set highlight color
    INTERSECTED.material.color.setHex(COLOR_HIGHLIGHT);

    // SCALE UP
    // Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
    try {
      scaleTween.stop();
    } catch (e) {}

    // Create tween, save it so we can try to stop it, if needed
    scaleTween = scale_tween(
      INTERSECTED,
      INTERSECTED.scale.clone(),
      {
        x: 1.5,
        y: 1.5
      },
      100
    );
    scaleTween.start();

    // SET Z-INDEX
    INTERSECTED.position.z = 10;
  } else {
    // If the mouse is over an object

    // Do we have a previous hovered item?
    if (INTERSECTED !== null) {
      // Revert color
      INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
      // SCALE DOWN
      // Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
      try {
        scaleTween.stop();
      } catch (e) {}

      // Create tween, save it so we can try to stop it, if needed
      scaleTween = scale_tween(
        INTERSECTED,
        INTERSECTED.scale.clone(),
        {
          x: 1,
          y: 1
        },
        100
      );
      scaleTween.start();

      // REVERT Z-INDEX
      INTERSECTED.position.z = 1;
    }

    // Save current intersected object
    INTERSECTED = intersects[is].object;

    // HIGHLIGHT
    // Save current color
    INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
    // Set highlight color
    INTERSECTED.material.color.setHex(COLOR_HIGHLIGHT);

    // SCALE UP
    // Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
    try {
      scaleTween.stop();
    } catch (e) {}

    // Create tween, save it so we can try to stop it, if needed
    scaleTween = scale_tween(
      INTERSECTED,
      INTERSECTED.scale.clone(),
      {
        x: 1.5,
        y: 1.5
      },
      100
    );
    scaleTween.start();

    // SET Z-INDEX
    INTERSECTED.position.z = 10;
  }
} else {
  // If there are no intersections

  // Reset cursor
  document.body.style.cursor = 'default';

  // Restore previous intersection object (if it exists) to its original color
  if (INTERSECTED !== null) {
    // REVERT COLOR
    INTERSECTED.material.color.setHex(INTERSECTED.currentHex);

    // SCALE DOWN
    // Try to stop the current tween, if any, in progress, so we can proceed with the next, if any, tween
    try {
      scaleTween.stop();
    } catch (e) {}

    // Create tween, save it so we can try to stop it, if needed
    scaleTween = scale_tween(
      INTERSECTED,
      INTERSECTED.scale.clone(),
      {
        x: 1,
        y: 1
      },
      100
    );
    scaleTween.start();

    // REVERT "Z-INDEX"
    INTERSECTED.position.z = 1;
  }

  // Remove previous intersection object reference  by setting current intersection object to "nothing"
  INTERSECTED = null;
}

I've managed to highlight the object and scale it up with a tween quite nicely, but when I move the mouse out of the object onto the next object (the scaled object is scaled over the next object a bit), the highlight is gone, but the scale persists. How do I manage to scale the object down? And preferably with a tween?

A pen for this code can be found here: https://codepen.io/phun-ky/pen/erBZZy, the relevant part is at about line 1284 or search for INTERSECTED.

1条回答
Bombasti
2楼-- · 2019-08-03 11:16

I wrote my own one. It's hell imperfect, but, at least, it scales up and down the hexagons:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x101010);
document.body.appendChild(renderer.domElement);

var hexes = [];

var colCount = 5;
var rowCount = 4;
var hexDiameter = 3;

var xStart = -(colCount) * hexDiameter * 0.5;
var rowSpace = Math.sqrt(3) * hexDiameter * 0.5;
var yStart = (rowCount - 1) * rowSpace * 0.5;
var hexGeom = new THREE.CylinderGeometry(hexDiameter * 0.5, hexDiameter * 0.5, 0.0625, 6, 1);
hexGeom.rotateX(Math.PI * 0.5);
for (let j = 0; j < rowCount; j++) {
  for (let i = 0; i < colCount + (j % 2 === 0 ? 0 : 1); i++) {
    let hex = new THREE.Mesh(hexGeom, new THREE.MeshBasicMaterial({
      color: Math.random() * 0x7e7e7e + 0x7e7e7e,
      wireframe: false
    }));
    hex.position.set(xStart + i * hexDiameter + (j % 2 === 0 ? 0.5 * hexDiameter : 0), yStart - j * rowSpace, 0);
    hex.userData.scaleUp = function(h) {
      if (h.userData.scaleDownTween) h.userData.scaleDownTween.stop();
      let initScale = h.scale.clone();
      let finalScale = new THREE.Vector3().setScalar(2);
      h.userData.scaleUpTween = new TWEEN.Tween(initScale).to(finalScale, 500).onUpdate(function(obj) {
        h.scale.copy(obj)
      }).start();
    }
    hex.userData.scaleDown = function(h) {
      if (h.userData.scaleUpTween) h.userData.scaleUpTween.stop();
      let initScale = h.scale.clone();
      let finalScale = new THREE.Vector3().setScalar(1);
      h.userData.scaleUpTween = new TWEEN.Tween(initScale).to(finalScale, 500).onUpdate(function(obj) {
        h.scale.copy(obj)
      }).start();
    }
    scene.add(hex);
    hexes.push(hex);
  }
}

window.addEventListener("mousemove", onMouseMove, false);

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

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.intersectObjects(hexes);
  if (intersects.length > 0) {
    if (intersected != intersects[0].object) {
      if (intersected) intersected.userData.scaleDown(intersected);
      intersected = intersects[0].object;
      intersected.userData.scaleUp(intersected);
    }
  } else {
    if (intersected) intersected.userData.scaleDown(intersected);
    intersected = null;
  }
}

render();

function render() {
  requestAnimationFrame(render);
  TWEEN.update();
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>

查看更多
登录 后发表回答