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
问题:
关于使用 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