Three.js - Создание / Обновление сетки движением мыши и щелчком - PullRequest
0 голосов
/ 02 мая 2018

Я хочу иметь возможность создавать сетку из щелчков мышью пользователей. Каждый раз, когда пользователь щелкает, новая точка будет добавлена ​​в сетку. Также, когда пользователь перемещает свою мышь, последняя точка должна следовать за его курсором.

Мне удалось сделать это с помощью Линии, геометрия которой является BufferGeometry, где позиции заданы как атрибут BufferGeometry.

Затем, когда пользователь щелкает, я добавляю координаты x, y к массиву положений и затем устанавливаю диапазон рисования BufferGeometry. Когда пользователь перемещает свою мышь, я обновляю координаты x, y последней позиции и затем устанавливаю BufferGeometry.attributes.position.needsUpdate в значение true. Это также работает.

Однако теперь я хочу иметь возможность использовать сетку вместо линии, поскольку хочу иметь вложенную форму, но у меня возникают трудности с ее отображением / обновлением.

Существует ли простой способ обновления и добавления точек в сетку при щелчке мышью / перемещении мыши?

Пример

let scene, camera, renderer, raycaster, canvas;

let linePositions, lineGeometry, line, myMesh;

let count = 0;

init();
initScene();
animate();

function init() {
  document.addEventListener('click', onClick);
  document.addEventListener('mousemove', onMouseMove);
}

function initScene() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xf0f0f0);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

  camera.position.z = 5;

  raycaster = new THREE.Raycaster();

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  initCanvas();
}

/* Initialize the Canvas so we can raycast the mouse click and mouse move */
function initCanvas() {
  const geometry = new THREE.PlaneGeometry(7, 7, 1, 0);
  const material = new THREE.MeshBasicMaterial({
    visible: false
  });

  canvas = new THREE.Mesh(geometry, material);
  scene.add(canvas);

  addLineAndMesh();
}

function addLineAndMesh() {

  linePositions = new THREE.BufferAttribute(new Float32Array(25 * 3), 3).setDynamic(true);

  // geometry
  lineGeometry = new THREE.BufferGeometry();
  lineGeometry.addAttribute('position', linePositions);

  // material
  const lineMaterial = new THREE.LineBasicMaterial({
    color: 0xff0000,
    linewidth: 1
  });

  const material = new THREE.MeshLambertMaterial({
    color: 0xff0000,
    side: THREE.DoubleSide,
    opacity: 0.6
  });

  myMesh = new THREE.Mesh(lineGeometry, material);
  scene.add(myMesh);

  // line
  line = new THREE.Line(lineGeometry, lineMaterial);
  scene.add(line);
}

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};

function onClick(e) {
  const pos = getMousePosition(e);

  if (count === 0) {
    setPositions(pos, false);
    count++;
  }

  setPositions(pos, false);
  count++;

  lineGeometry.setDrawRange(0, count);
}

function onMouseMove(e) {
  const pos = getMousePosition(e);
  setPositions(pos, true);
}

function setPositions(pos, isUpdate) {
  const index = isUpdate ? count - 1 : count;

  linePositions.setXYZ(index, pos.x, pos.y, 0);

  linePositions.needsUpdate = true;
  line.frustumCulled = false;
  myMesh.frustumCulled = false;
}

function getMousePosition(e) {
  e.preventDefault();

  let mouse = {};
  mouse.x = (e.offsetX / renderer.domElement.width) * 2 - 1;
  mouse.y = -(e.offsetY / renderer.domElement.height) * 2 + 1;
  mouse.z = 0;

  raycaster.setFromCamera(mouse, camera);

  const intersects = raycaster.intersectObjects([canvas]);

  if (intersects.length > 0 && intersects[0]) {
    mouse = intersects[0].point;
  }

  return mouse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script>
...