ThreeJS:简单的城市表现问题

Problem:
我遇到了关于使用Three JS渲染的场景的性能方面的主要问题 . 该问题涉及渲染大量简单的几何形状(11,107) .

(编辑)每栋建筑都有一个独特的高度,基于高程数据,基于轮廓的独特形状,以及5种可能选项的材料,具体取决于它们占据的区域大小 .

我有 isolated the issue in the first scene below ,第二个链接提供上下文 . 关闭第二个链接中的多边形建筑物说明了该层导致的帧速率下降 .

Preview Image

How polygon attributes were determined:

每个多边形具有均匀的高度,但基于建筑物的足迹具有独特的形状 . 此外,每个建筑物的颜色都是相对于其面积大小的渐变(大黄色,中红色小紫色) . 作为参考,这是在传递给ThreeJS(QGIS,带有QGIStoTHREEJS插件)之前在地理信息系统中实现的 .

Attempted Solutions:
我专注于尝试合并多边形几何以减少渲染调用的数量 . 但是,因为每个多边形都有指定的颜色,所以我遇到了应用适当的材料和网格的问题 . 我正在努力解决如何在操作中的两个循环的上下文中执行此操作的逻辑 .

Relevant Code Snippet:
可以找到完整的源here,并且可以下载工作代码here . 该片段来自1935年至1987年 .
我已将ThreeJS来源修改为与我的问题相关的内容 .

///////////////// WIP /////////////////
Q3D.PolygonLayer.prototype.build = function(parent) {
    var materials = this.materials,
        project = this.project;

    if (this.objType == "Extruded") {


        // (3) Function for creating the individual building polygons 
        var createSubObject = function(f, polygon, z) {
            var shape = new THREE.Shape(Q3D.Utils.arrayToVec2Array(polygon[0]));
            for (var i = 1, l = polygon.length; i < l; i++) {
                shape.holes.push(new THREE.Path(Q3D.Utils.arrayToVec2Array(polygon[i])));
            }

            // Where the problems start...

            // Here each geometry is created turned into a mesh with its unqiue material
            var geom = new THREE.ExtrudeGeometry(shape, {
                bevelEnabled: false,
                amount: f.h
            });
            var mesh = new THREE.Mesh(geom, materials[f.m].m);
            mesh.position.z = z;
            return mesh;

            //I am not sure how I can merge each polygons geometry with the others whilst allowing each polygon to hold onto its unique colouring...

        };

        // (2) Function for creating polygon layer
        var createObject = function(f) {
            if (f.polygons.length == 1) { // TRUE for building polygons
                return createSubObject(f, f.polygons[0], f.zs[0]); // calls function to create each building

            }
        };
    }


    // (1) function for manufacturing each layer
    this.f.forEach(function(f, fid) {
        f.objs = []; // create array of objects
        var obj = createObject(f); // call polygon creation method
        obj.userData.layerId = this.index;
        obj.userData.featureId = fid;
        this.addObject(obj);
        f.objs.push(obj);
    }, this);

    if (parent) parent.add(this.objectGroup);
};

///////////////// END OF WIP /////////////////

编辑:每个几何的结构如下(f) .

几何f [A] = {h,m,多边形,zs};假设f是11,000个几何中的一个,A是索引(0到1106),h是浮点数,m是int(0到5),它作为访问五个颜色类别之一的索引,多边形是用于构建足迹边缘的坐标列表,zs是挤出高度 . 例如f [11106] = {h:0.0302738130622,m:1,多边形:[[[[ - 23.0863540568,-1.57556646762],[ - 23.1968547585,-1.56551240558],[ - 23.1928481251,-1.49924919288],[ - 23.0803253841,-1.50930323633] ,[ - 23.0863540568,-1.57556646762]]]],ZS:[0.0695352124961]};材料有五种颜色类别 . 索引充当给定几何体的参考,以查找其关联材料 . 例如f [11106] .m指向m [1] = {c:0xcb4778,类型:0};

There must be someone who knows a way of rendering these buildings without hammering out so many draw calls . 任何帮助都会非常感激 .

回答(1)

2 years ago

您正在向场景中添加数千个拉伸网格,这会因绘制调用过多而导致性能问题 .

一种解决方案是创建单个网格,这将导致单个绘制调用 . 您可以使用 ExtrudeGeometry 执行此操作,但 ExtrudeBufferGeometry 更有效 .

var shapes = [];
shapes.push( shape_1 );
...
shapes.push( shape_n );

var geometry = new THREE.ExtrudeBufferGeometry( shapes, extrudeSettings );

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

scene.add( mesh );

如果需要对形状应用不同的颜色,则可以选择将顶点颜色添加到几何体中 . 另一个选项是,如果没有太多不同的颜色,则将 groups 添加到几何体中 . 哪一个最好取决于您的用例 .

编辑:实际上,在您的情况下,最简单的方法是为每种颜色设置一个单独的挤压网格 .

编辑:Here is a fiddle,显示如何使用各种拉伸形状填充单个 BufferGeometry .

three.js r.89