如何在 STL 加载的 BufferGeometry 中平滑网格三角形

Posted

技术标签:

【中文标题】如何在 STL 加载的 BufferGeometry 中平滑网格三角形【英文标题】:How to smooth mesh triangles in STL loaded BufferGeometry 【发布时间】:2016-05-10 05:50:46 【问题描述】:

我正在尝试使用 Three.js 加载一些 STL 文件。模型已正确加载,但我想合并/平滑的三角形太多。

我已经成功地应用了其他 3D 格式的平滑加载地形,但我无法使用通过 STLLoader 加载 STL 文件产生的 BufferGeometry 来实现。

_

var material = new THREE.MeshLambertMaterial(  ...  );
var path = "./models/budah.stl";
var loader = new THREE.STLLoader();
loader.load( path, function ( object ) 
                object.computeBoundingBox();
                object.computeBoundingSphere();
                object.computeFaceNormals();
                object.computeVertexNormals();
                object.normalizeNormals();
                object.center();

                // Apply smooth
                var modifier = new THREE.SubdivisionModifier( 1);
                var smooth = smooth = object.clone();
                smooth.mergeVertices();
                smooth.computeFaceNormals();
                smooth.computeVertexNormals();
                modifier.modify( smooth );
                scene.add( smooth );
);

这是我试过的,它抛出一个错误:Uncaught TypeError: smooth.mergeVertices is not a function

如果我评论“mergeVertices()”行,我得到的是一个不同的错误:Uncaught TypeError: Cannot read property 'length' of undefined in SubdivisionsModifier,第 156 行。

我正在尝试的示例代码似乎已经过时(由于 Three.JS 库中的巨大变化,最近经常发生这种情况)。或者,也许我忘记了什么。事实是顶点似乎为空..?

提前致谢!

【问题讨论】:

【参考方案1】:

看来我看错了方向:平滑三角形与 SubdivisionsModifier 无关...我需要的比这更容易,只需在应用材质之前计算顶点,因此它可以使用 SmoothShading 而不是FlatShading(我猜对了吗?)。

这里的问题是 STLLoader 返回的 BufferGeometry 没有计算顶点/顶点,所以我不得不手动进行。之后,在 computeVertexNormals() 之前应用 mergeVertices() ,瞧!三角形消失,一切顺利:

var material = new THREE.MeshLambertMaterial(  ...  );
var path = "./models/budah.stl";
var loader = new THREE.STLLoader();
loader.load( path, function ( object )                 
                object.computeBoundingBox();
                object.computeVertexNormals();
                object.center();
                ///////////////////////////////////////////////////////////////

                var attrib = object.getAttribute('position');
                if(attrib === undefined) 
                    throw new Error('a given BufferGeometry object must have a position attribute.');
                
                var positions = attrib.array;
                var vertices = [];
                for(var i = 0, n = positions.length; i < n; i += 3) 
                    var x = positions[i];
                    var y = positions[i + 1];
                    var z = positions[i + 2];
                    vertices.push(new THREE.Vector3(x, y, z));
                
                var faces = [];
                for(var i = 0, n = vertices.length; i < n; i += 3) 
                    faces.push(new THREE.Face3(i, i + 1, i + 2));
                

                var geometry = new THREE.Geometry();
                geometry.vertices = vertices;
                geometry.faces = faces;
                geometry.computeFaceNormals();              
                geometry.mergeVertices()
                geometry.computeVertexNormals();

                ///////////////////////////////////////////////////////////////
                var mesh = new THREE.Mesh(geometry, material);

                scene.add( mesh );
);

【讨论】:

请有人纠正我:所以如果我只想让网格在视觉上变得平滑,我需要在应用材质之前合并Vertices() + computeVertexNormals()(更好的性能)。另一方面,SubdivisionsModifiers 允许修改网格本身,使越来越多的三角形在物理上平滑(大型模型的性能低下)。这个概念对吗? 我认为您需要替换“对象”。通过“object.geometry”(乘以 4 个位置)。 (通过该编辑)您的解决方案解决了我尝试从 OBJ 源文件中获得平滑阴影的问题,非常感谢:-)。【参考方案2】:

然后,您可以将其转换回 BufferGeometry,因为对于更复杂的模型,它的 GPU/CPU 效率更高:

var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();
geometry.mergeVertices();
geometry.computeVertexNormals();
var buffer_g = new THREE.BufferGeometry();
buffer_g.fromGeometry(geometry);
var mesh = new THREE.Mesh(buffer_g, material);
scene.add( mesh )

【讨论】:

【参考方案3】:

我在加载 obj 文件时发生了这个问题。如果你有 3ds​​max 之类的 3d 软件:

    打开 obj 文件, 进入多边形选择模式并选择所有多边形。 在“曲面属性”面板下,单击“自动平滑”按钮。 将模型导出回 obj 格式

现在您不必调用函数 geometry.mergeVertices() 和 geometry.computeVertexNormals();。只需加载 obj 并添加到场景中,网格就会变得平滑。

编辑: 我的 obj 文件默认具有 meshphongmaterial,将着色属性更改为值 2 后,网格变得平滑。

child.material.shading = 2

【讨论】:

【参考方案4】:

STL 不支持顶点索引。 这就是它复制了所有三角形的顶点的原因。 每个顶点的法线为三角形法线。 结果,在同一位置(多个非常闭合的顶点),有多个法线值。 当使用法线进行光照计算时,这会导致几何体表面不光滑。

【讨论】:

以上是关于如何在 STL 加载的 BufferGeometry 中平滑网格三角形的主要内容,如果未能解决你的问题,请参考以下文章

使用 Vue-cli 和 Three.js 加载 STL 文件

两种方法在Qt中使用OpenGL库加载stl三维模型

three.js加载stl模型文件,怎么能让模型大小一致并居中

使用 C++ Boost 或 STL 和 Mysql 存储和检索图像

如何在 main 之前预加载数据

Amazon Redshift:当找到的表 id 不匹配时,如何将 `stl_load_errors` 行与正确的表名相关联?