问题
I'm making a globe in three.js and will be adding some data layers. All of the layers will be created from geoJSON. I have set it up so that the globe (the first data file, which is of countries) shows up as lines. This uses ThreeGeoJSON.
However, I do not want just outlines. I'd like to fill the countries with color.
My current project can be seen here: http://bl.ocks.org/jhubley/321232d4ccefefcdc53218fd0adccac5
The code is here: https://gist.github.com/jhubley/321232d4ccefefcdc53218fd0adccac5
I tried to create a new function that would render the polygons and multipolygons as meshes instead of lines. That function is as follows:
function drawShape(x_values, y_values, z_values, options) {
var shape_geom = new THREE.BoxGeometry();
createVertexForEachPoint(shape_geom, x_values, y_values, z_values);
var shape_material = new THREE.MeshBasicMaterial( {color: 0xffff00 } );
var shape = new THREE.Mesh(shape_geom, shape_material);
scene.add(shape);
clearArrays();
}
Unfortunately, nothing shows up when I use that. There are no errors in the console to help me understand why.
Can anyone explain how I could set up the countries so that they can be filled? Any advice or pointers would be very much appreciated.
回答1:
As @mlkn said you have to use triangles to fill a mesh.
I messed around a little:
function drawLine(x_values, y_values, z_values, options) {
// container
var obj = new THREE.Object3D();
// lines
var line_geom = new THREE.Geometry();
createVertexForEachPoint(line_geom, x_values, y_values, z_values);
var line_material = new THREE.LineBasicMaterial({
color: 'yellow'
});
var line = new THREE.Line(line_geom, line_material);
obj.add(line);
// mesh
var mesh_geom = new THREE.Geometry();
createVertexForEachPoint(mesh_geom, x_values, y_values, z_values);
var mesh_material = new THREE.MeshBasicMaterial({
color: 'blue',
side: THREE.DoubleSide
});
var mesh = new THREE.Mesh(mesh_geom, mesh_material);
obj.add(mesh);
scene.add(obj);
clearArrays();
}
The Object3D
obj
is wrapping both lines and meshes.
Faces (triangles) are created here:
function createVertexForEachPoint(object_geometry, values_axis1, values_axis2, values_axis3) {
for (var i = 0; i < values_axis1.length; i++) {
object_geometry.vertices.push(new THREE.Vector3(values_axis1[i],
values_axis2[i], values_axis3[i]));
object_geometry.faces.push(new THREE.Face3(0, i + 1, i)); // <- add faces
}
}
The result is bit of a mess, I don't know if because of the data or the vertex order/generation.
Demo:
- https://gist.github.com/marcopompili/f5e071ce646c5cf3d600828ace734ce7
- http://bl.ocks.org/marcopompili/f5e071ce646c5cf3d600828ace734ce7
That threeGeoJSON is poorly written IMO, without structure, as an example you just need to change the name of var scene = ...
to var myscene = ...
and the whole lib stop working, that's poor design.
Also there's a high amount of CPU usage, probably too many draw calls.
回答2:
You have segments which form an outline and draw them as lines. But filled shape is have to be constructed from triangles (more on webgl draw modes there).
So to render filled country you need to make a triangulation of your set of segments. There are multiple ways to do that, and ready to use code is available (for example, this earcut implementation).
However, since you want to map shape on globe, next problem could be the size of produced polygons. If triangulation you use produces big triangles, and you transform vertices to spherical coords, big triangles will be noticable flat. Here could be used displacement mapping in fragment shader or further triangles subdivision (based on triangles area, for example).
The last but not the least: triangulation is computationally expensive, so if you don't need to do it dynamically, consider offline geometry preparation. If you need to triangulate dynamic data: consider using webworker for that task (or super-fast non javascript server if project is big).
来源:https://stackoverflow.com/questions/40520463/how-can-i-draw-geojson-in-three-js-as-a-mesh-and-not-a-line-and-fill-with-color