【问题标题】:Three.js - Create new mesh from certain faces/vertices of another meshThree.js - 从另一个网格的某些面/顶点创建新网格
【发布时间】:2016-05-17 09:53:41
【问题描述】:

我已经为一个特定的 Three.js 问题苦苦挣扎了好几天,但我找不到任何解决方法。这是我的情况:

1) 我有一个浮动网格,由几个三角形面组成。在使用 getAttribute('position') 获取其顶点和面后,此网格是根据加载器返回的几何图形创建的:How to smooth mesh triangles in STL loaded BufferGeometry

2)我现在要做的是将底面“投影”到地板上。

3) 稍后,添加这个新面后,创建填充两个面的 3 个顶点之间的空间的结果网格。

我在第 2 步中已经遇到了麻烦...要创建一个新面,我应该将其 3 个顶点添加到 geometry.vertices。我做到了,克隆了原来的面顶点。我使用 geometry.vertices.push() 结果来了解它们的新索引,然后我使用该索引 (-1) 最终创建新面。但它的形状很奇怪,位置和大小也很奇怪。我认为我没有正确理解世界/场景/矢量位置等价理论:P

我尝试应用这个,但没有运气: How to get the absolute position of a vertex in three.js? Converting World coordinates to Screen coordinates in Three.js using Projection 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 );

【问题讨论】:

    标签: three.js mesh projection floor face


    【解决方案1】:

    试试这个

     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;
                }
    

    【讨论】:

    • 您好,感谢您的宝贵时间!嗯,我虽然我正在这样做......!看看我在第一篇文章中添加的源代码。这种策略的第一个问题:原始面的原始顶点在其 x、y、z 属性上的值与生成的克隆“vectorClone”不同。我想我必须以某种方式将矢量坐标传输到真实世界的坐标?
    • 我们在做同样的事情吗..?在您的代码中,什么是 i、i2 和 i3?我开始认为 vertexNormals 不是我获得面的 3 个顶点所需要的?
    • first 您必须设置 original_geometry 的下表面(底部),为此您必须比较所有面并返回 Z 中最低的面。然后在 Zfloor 中创建相同的下脸。在 virtex(samX samY Zfloor)
    • 是的,我刚刚省略了计算,我知道哪一个是底面,但那部分已经完成,谢谢。我的问题是获得面部的 3 个顶点。你怎么得到它们?我使用原始面的 vertexNormals 属性(这是一个由 3 个向量组成的数组,每个向量都有其 x、y、z 属性)。但是单位...非常低,例如-0.2、0.4、2等。这是矢量单位,对吗?我添加向量/面的方式是否正确?我首先添加 3 个克隆的向量,获取它的索引并使用它们来添加人脸。但我看到你只使用 0,1,2 数字作为参数,我很困惑。
    • 我认为你需要更新你的 original_geometry 才能克隆它
    【解决方案2】:

    我用这个案例创建了一个完全可操作的 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 );        
    }
    

    编辑:终于!!我得到了它!要克隆原始面,我必须使用“a”、“b”和“c”属性访问它们的 3 个原始顶点,这些属性是引用原始几何的“顶点”数组中的 Vector3 实例的索引。

    我克隆了 3 个将 Z 位置平展为零的顶点,使用它们的新索引创建新面并将其添加到投影网格(蓝色)。

    我还在添加线条作为两个面孔之间的视觉结合。现在我已经为第 3 步做好了准备,但我认为这已经足够复杂,可以结束这个问题了。

    感谢 updateMatrixWorld 线索!实现我的目标至关重要;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-03
      • 1970-01-01
      • 2021-02-15
      • 1970-01-01
      • 2019-02-03
      • 2020-12-05
      • 1970-01-01
      相关资源
      最近更新 更多