Three.js - Extrude vertex / face tertentu dari BufferGeometry

Aug 16 2020

Saya membuat new THREE.PlaneBufferGeometry(100, 100, 100, 100);dan telah dapat memperbarui posisi simpul untuk mengubah bentuk mesh seperti berikut:

Saya mencapai ini dengan mengikuti diskusi ini: Titik tarik Threejs

Apa yang saya cari

Saya ingin dapat mengekstrusi wajah (ambil 4 simpul), jadi saya mencapai sesuatu seperti ini:

Saya ingin menyimpannya sebagai bagian dari mesh yang sama, agar tetap bersih, karena saya akan mengekspornya sebagai mesh tunggal dengan file ColladaExporter.

Edit

Untuk mencapai ini, saya perlu mengkloning vertex dan mendorongnya ke atas. Ini berarti, menambahkan 4 simpul baru dan menghubungkannya.

Saya mencoba ini:

var geo = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
geo.rotateX(-Math.PI * 0.5);
geo.translate(0,0.5,0);

//And the merge them together
var newplane = BufferGeometryUtils.mergeBufferGeometries([plane, geo]);
newplane = BufferGeometryUtils.mergeVertices(newplane,1);

Dan saya mendapatkan ini:

Saya berharap semua simpul bergabung dengan pesawat, meninggalkan bidang datar. Saya melakukan ini untuk tujuan pengujian, tetapi hanya menggabungkan satu sudut.

Saya mulai membuat "kubus" dengan beberapa dan menempatkannya di tempat yang benar, untuk kemudian menerapkannya lagi BufferGeometryUtils.mergeVertices, tetapi simpulnya sepertinya tidak bergabung dengan benar:

Edit 2 / Kemajuan

Saya berhasil membuat PlaneBufferGeometrydan mengekstrusi dengan memodifikasi simpul dan normal secara manual, seperti yang diceritakan di:https://threejs.org/docs/#api/en/core/BufferGeometry

Bidang yang diekstrusi memiliki semua simpul yang terhubung, jadi setiap kali saya menyeret satu simpul itu menyeret seluruh bagian, masalahnya sekarang adalah bahwa saya perlu menghubungkan simpul baru ini ke kisi asli untuk menghindari ini:

Tujuannya adalah untuk menggabungkan semua simpul, sekarang saya perlu menemukan cara untuk menggabungkan bidang dasar dengan bagian baru yang diekstrusi.

Edit 3 / Selesai

Saya berhasil, saya akan memposting jawaban ketika saya punya waktu. Saya menghabiskan sepanjang hari untuk ini hari ini, dan sudah sangat lelah.

Jawaban

MarekPiotrowski Aug 16 2020 at 02:32

Tidak yakin apakah itu yang Anda butuhkan, tetapi berikut adalah contoh modifikasi dari jawaban yang Anda rujuk (harap perhatikan perbedaan dalam implementasi mouseMove). Saya telah memperpanjangnya hanya untuk dua poin, tetapi saya yakin Anda harus mengerti:

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

var geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
geometry.rotateX(-Math.PI * 0.5);

var plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
  wireframe: true,
  color: "red"
}));
scene.add(plane);

var points = new THREE.Points(geometry, new THREE.PointsMaterial({
  size: 0.25,
  color: "yellow"
}));
scene.add(points);


var raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 0.25;
var mouse = new THREE.Vector2();
var intersects = null;
var plane = new THREE.Plane();
var planeNormal = new THREE.Vector3();
var currentIndex = null;
var planePoint = new THREE.Vector3();
var dragging = false;

window.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mousemove", mouseMove, false);
window.addEventListener("mouseup", mouseUp, false);

function mouseDown(event) {
  setRaycaster(event);
  getIndex();
  dragging = true;
}

function mouseMove(event) {
  if (dragging && currentIndex !== null) {
    setRaycaster(event);
    raycaster.ray.intersectPlane(plane, planePoint);
    var indicesToMoveUp = [currentIndex-1, currentIndex];
         var delta_x = geometry.attributes.position.getX(currentIndex) - planePoint.x;
      geometry.attributes.position.setXYZ(currentIndex, planePoint.x, planePoint.y, planePoint.z);
      geometry.attributes.position.needsUpdate = true;
     var old_x_neighbour = geometry.attributes.position.getX(currentIndex - 1);
    geometry.attributes.position.setY(currentIndex-1, planePoint.y);
    geometry.attributes.position.setZ(currentIndex-1, planePoint.z);
    geometry.attributes.position.setX(currentIndex-1, old_x_neighbour - delta_x);
    geometry.attributes.position.needsUpdate = true;
  }
}

function mouseUp(event) {
  dragging = false;
  currentIndex = null;
}

function getIndex() {
  intersects = raycaster.intersectObject(points);
  if (intersects.length === 0) {
    currentIndex = null;
    return;
  }
  currentIndex = intersects[0].index;
  setPlane(intersects[0].point);
}

function setPlane(point) {
  planeNormal.subVectors(camera.position, point).normalize();
  plane.setFromNormalAndCoplanarPoint(planeNormal, point);
}

function setRaycaster(event) {
  getMouse(event);
  raycaster.setFromCamera(mouse, camera);
}

function getMouse(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}

render();

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