Три.js-создание новой сетки из определенных граней / вершин другой сетки
Я уже несколько дней борюсь с одной конкретной тройкой.JS проблема, и я не могу найти никакого способа сделать это. Это мой случай:
1) у меня есть плавающая сетка, образованная несколькими треугольными гранями. Эта сетка создается из геометрии, возвращаемой загрузчиком, после получения ее вершин и граней с помощью getAttribute ('position'): как сгладить треугольники сетки в STL loaded BufferGeometry2) теперь я хочу "спроецировать" нижнюю грань аж на пол падает.
3) позже, с добавлением этой новой грани, создайте результирующую сетку заполнения пространства между 3 вершинами обеих граней.
У меня уже есть проблемы в шаге 2... Чтобы создать новую грань, необходимо, чтобы ее 3 вершины уже были добавлены в геометрию.вершины. Я сделал это, клонируя исходные вершины граней. Я использую геометрию.вершины.push () результаты, чтобы узнать их новые индексы, и позже я использую эти индексы (-1), чтобы наконец, создайте новое лицо. Но его форма странная, а также положение и размер. Я думаю, что я не получаю правильную теорию эквивалентности мира / сцены / векторного положения: P
Я попытался применить это, но безуспешно: Как получить абсолютное положение вершины в трех.js? преобразование мировых координат в экранные координаты в три.Яш, используя Проекция http://barkofthebyte.azurewebsites.net/post/2014/05/05/three-js-projecting-mouse-clicks-to-a-3d-scene-how-to-do-it-and-how-it-works
Я обнаружил, что если я непосредственно клонирую полную исходную грань и просто добавляю ее в сетку, грань добавляется, но в том же положении, поэтому я не могу изменить ее вершины, чтобы поместить ее на пол (или, по крайней мере, без изменения исходных вершин граней!). Я имею в виду, что я могу изменить их свойства x, y, z, но они находятся в очень малая мера, которая не соответствует исходным размерам сетки.Может ли кто-нибудь помочь мне правильно понять эту концепцию?
Редактировать: исходный код
// Create geometry
var geo = new THREE.Geometry();
var geofaces = [];
var geovertices = [];
original_geometry.updateMatrixWorld();
for(var index in original_geometry.faces){
// Get original face vertexNormals to know its 3 vertices
var face = original_geometry[index];
var vertexNormals = face.vertexNormals;
// Create 3 new vertices, add it to the array and then create a new face using the vertices indexes
var vertexIndexes = [null, null, null];
for (var i = 0, l = vertexNormals.length; i < l; i++) {
var vectorClone = vertexNormals[i].clone();
vectorClone.applyMatrix4( original_geometry.matrixWorld );
//vectorClone.unproject(camera); // JUST TESTING
//vectorClone.normalize(); // JUST TESTING
var vector = new THREE.Vector3(vectorClone.x, vectorClone.z, vectorClone.y)
//vector.normalize(); // JUST TESTING
//vector.project(camera); // JUST TESTING
//vector.unproject(camera); // JUST TESTING
vertexIndexes[i] = geovertices.push( vector ) - 1;
}
var newFace = new THREE.Face3( vertexIndexes[0], vertexIndexes[1], vertexIndexes[2] );
geofaces.push(newFace);
}
// Assign filled arrays to the geometry
geo.faces = geofaces;
geo.vertices = geovertices;
geo.mergeVertices();
geo.computeVertexNormals();
geo.computeFaceNormals();
// Create a new mesh with resulting geometry and add it to scene (in this case, to the original mesh to keep the positions)
new_mesh = new THREE.Mesh( geo, new THREE.MeshFaceMaterial(material) ); // material is defined elsewhere
new_mesh.position.set(0, -100, 0);
original_mesh.add( new_mesh );
2 ответа:
Попробуйте это
original_geometry.updateMatrixWorld(); var vertexIndexes = [null, null, null]; for (var i = 0, l = vertexNormals.length; i < l; i++) { var position = original_geometry.geometry.vertices[i].clone(); position.applyMatrix4( original_geometry.matrixWorld ); var vector = new THREE.Vector3(position.x, position.y, position.z) vertexIndexes[i] = geovertices.push( vector ) - 1; }
Я создал полностью работоспособный JSFiddle с кейсом, чтобы попробовать вещи и увидеть проблему более ясно. С этим STL (меньшим, чем мой местный пример) я даже не могу видеть плохо клонированные лица, добавленные к сцене.. Может быть, они слишком малы или не в фокусе.
Взгляните на функцию calculateProjectedMesh (), здесь я попытался клонировать и разместить нижние грани (уже обнаруженные, потому что они имеют другой materialIndex):
JSFiddle: https://jsfiddle.net/tc39sgo1/
var container; var stlPath = 'https://dl.dropboxusercontent.com/s/p1xp4lhy4wxmf19/Handle_Tab_floating.STL'; var camera, controls, scene, renderer, model; var mouseX = 0, mouseY = 0; var test = true; var meshPlane = null, meshStl = null, meshCube = null, meshHang = null; var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; /*THREE.FrontSide = 0; THREE.BackSide = 1; THREE.DoubleSide = 2;*/ var materials = []; materials.push( new THREE.MeshPhongMaterial({color : 0x00FF00, side:0, shading: THREE.FlatShading, transparent: true, opacity: 0.9, overdraw : true, wireframe: false}) ); materials.push( new THREE.MeshPhongMaterial({color : 0xFF0000, transparent: true, opacity: 0.8, side:0, shading: THREE.FlatShading, overdraw : true, metal: false, wireframe: false}) ); materials.push( new THREE.MeshPhongMaterial({color : 0x0000FF, side:2, shading: THREE.FlatShading, overdraw : true, metal: false, wireframe: false}) ); var lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, transparent: true, opacity: 0.05 }); init(); animate(); function webglAvailable() { try { var canvas = document.createElement('canvas'); return !!(window.WebGLRenderingContext && ( canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))); } catch (e) { return false; } } function init() { container = document.createElement('div'); document.body.appendChild(container); camera = new THREE.PerspectiveCamera(25, window.innerWidth / window.innerHeight, 0.1, 100000000); camera.position.x = 1500; camera.position.z = -2000; camera.position.y = 1000; controls = new THREE.OrbitControls(camera); // scene scene = new THREE.Scene(); var ambient = new THREE.AmbientLight(0x101030); //0x101030 scene.add(ambient); var directionalLight = new THREE.DirectionalLight(0xffffff, 2); directionalLight.position.set(0, 3, 0).normalize(); scene.add(directionalLight); var directionalLight = new THREE.DirectionalLight(0xffffff, 2); directionalLight.position.set(0, 1, -2).normalize(); scene.add(directionalLight); if (webglAvailable()) { renderer = new THREE.WebGLRenderer(); } else { renderer = new THREE.CanvasRenderer(); } renderer.setClearColor( 0xCDCDCD, 1 ); // renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); document.addEventListener('mousemove', onDocumentMouseMove, false); window.addEventListener('resize', onWindowResize, false); createPlane(500, 500); createCube(500); loadStl(); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function onDocumentMouseMove(event) { mouseX = (event.clientX - windowHalfX) / 2; mouseY = (event.clientY - windowHalfY) / 2; } function animate() { requestAnimationFrame(animate); render(); } function render() { renderer.render(scene, camera); } function createPlane(width, height) { var planegeometry = new THREE.PlaneBufferGeometry(width, height, 0, 0); var material = new THREE.MeshLambertMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); planegeometry.computeBoundingBox(); planegeometry.center(); meshPlane = new THREE.Mesh(planegeometry, material); meshPlane.rotation.x = 90 * (Math.PI/180); //meshPlane.position.y = -height/2; scene.add(meshPlane); } function createCube(size) { var geometry = new THREE.BoxGeometry( size, size, size ); geometry.computeFaceNormals(); geometry.mergeVertices(); geometry.computeVertexNormals(); geometry.center(); var material = new THREE.MeshPhongMaterial({ color: 0xFF0000, opacity: 0.04, transparent: true, wireframe: true, side: THREE.DoubleSide }); meshCube = new THREE.Mesh(geometry, material); meshCube.position.y = size/2; scene.add(meshCube); } function loadStl() { var loader = new THREE.STLLoader(); loader.load( stlPath, function ( geometry ) { // Convert BufferGeometry to Geometry var geometry = new THREE.Geometry().fromBufferGeometry( geometry ); geometry.computeBoundingBox(); geometry.computeVertexNormals(); geometry.center(); var faces = geometry.faces; for(var index in faces){ var face = faces[index]; var faceNormal = face.normal; var axis = new THREE.Vector3(0,-1,0); var angle = Math.acos(axis.dot(faceNormal)); var angleReal = (angle / (Math.PI/180)); if(angleReal <= 70){ face.materialIndex = 1; } else{ face.materialIndex = 0; } } geometry.computeFaceNormals(); geometry.computeVertexNormals(); meshStl = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials)); meshStl.position.x = 0; meshStl.position.y = 400; scene.add( meshStl ); // Once loaded, calculate projections mesh calculateProjectedMesh(); }); } function calculateProjectedMesh(){ var geometry = meshStl.geometry; var faces = geometry.faces; var vertices = geometry.vertices; var geometry_projected = new THREE.Geometry(); var faces_projected = []; var vertices_projected = []; meshStl.updateMatrixWorld(); for(var index in faces){ var face = faces[index]; // This are the faces if(face.materialIndex == 1){ var vertexIndexes = [face.a, face.b, face.c]; for (var i = 0, l = vertexIndexes.length; i < l; i++) { var relatedVertice = vertices[ vertexIndexes[i] ]; var vectorClone = relatedVertice.clone(); console.warn(vectorClone); vectorClone.applyMatrix4( meshStl.matrixWorld ); //////////////////////////////////////////////////////////////// // TEST: draw line var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(vectorClone.x, vectorClone.y, vectorClone.z)); //geometry.vertices.push(new THREE.Vector3(vectorClone.x, vectorClone.y, vectorClone.z)); geometry.vertices.push(new THREE.Vector3(vectorClone.x, meshPlane.position.y, vectorClone.z)); var line = new THREE.Line(geometry, lineMaterial); scene.add(line); console.log("line added"); //////////////////////////////////////////////////////////////// vectorClone.y = 0; var vector = new THREE.Vector3(vectorClone.x, vectorClone.y, vectorClone.z); vertexIndexes[i] = vertices_projected.push( vector ) - 1; } var newFace = new THREE.Face3( vertexIndexes[0], vertexIndexes[1], vertexIndexes[2] ); newFace.materialIndex = 2; faces_projected.push(newFace); } } geometry_projected.faces = faces_projected; geometry_projected.vertices = vertices_projected; geometry_projected.mergeVertices(); console.info(geometry_projected); meshHang = new THREE.Mesh(geometry_projected, new THREE.MeshFaceMaterial(materials)); var newY = -(2 * meshStl.position.y) + 0; var newY = -meshStl.position.y; meshHang.position.set(0, newY, 0); meshStl.add( meshHang ); }
EDIT: Наконец-то!! Я понял! Чтобы клонировать исходные грани, я должен получить доступ к их 3 исходным вершинам, используя свойства" a"," b "и" c", которые являются индексами, ссылающимися на экземпляры Vector3 в массиве" вершины " исходной геометрии.
Я клонировал 3 вершины, выравнивая положение Z до нуля, используя их новые индексы, чтобы создать новую грань и добавить ее в проекционную сетку (синим цветом).
Я также добавляю строки как визуальный элемент. союз между обоими лицами. Теперь я готов к шагу 3, но я думаю, что это достаточно сложно, чтобы закрыть этот вопрос.
Спасибо за подсказку updateMatrixWorld! Это было жизненно важно для достижения моей цели;)