ThreeJS:简单的城市性能问题

ThreeJS: Simple City Performance Issue

问题:
关于使用 Three JS 渲染的场景,我遇到了主要的性能问题。问题涉及 渲染大量简单几何体 (11,107)。

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

在下面的第一个场景中隔离了问题,第二个link提供了上下文。在第二个 link 中关闭多边形建筑物说明了图层导致的帧率下降。

Preview Image


如何确定多边形属性:

Each polygon has a uniform height, but unique shape based upon a building footprint. Furthermore, each building is assigned a colour from a gradient relative to the size of its area (large yellow, mid red small purple). As a reference, this was achieved in a geographic information system before being passed to ThreeJS (QGIS, with QGIStoTHREEJS plugin).


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


相关代码片段:
可以找到完整的源代码 here, and a download of the working code is available 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)。

GEOMETRY
f[A] = {h, m, polygons, zs};
Given that f is one of the 11,000 geometries, A is an index (0 to 1106), h is a float, m is an int (0 to 5) that acts as an index for accessing one of the five colour categories, polygons is a list of coordinate for building footprint edges, and zs is the extrusion height.

e.g.
f[11106] = {h:0.0302738130622,m:1,polygons:[[[[-23.0863540568,-1.57556646762],[-23.1968547585,-1.56551240558],[-23.1928481251,-1.49924919288],[-23.0803253841,-1.50930323633],[-23.0863540568,-1.57556646762]]]],zs:[0.0695352124961]};

MATERIAL
There are five colour categories. the index acts as a reference for a given geometry to find its associated material.

e.g.
f[11106].m points to
m[1] = {c:0xcb4778,type:0};

一定有人知道渲染这些建筑物的方法,而无需敲定那么多绘图调用 。任何帮助将不胜感激。

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

一种解决方案是创建单个网格,这将导致单个绘制调用。您可以使用 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