diff --git a/docs/stl.md b/docs/stl.md index 42b6a456..fc48d87b 100644 --- a/docs/stl.md +++ b/docs/stl.md @@ -26,13 +26,12 @@ For questions, problems, or improvements, contact me on Twitter [@probabletrain] For this guide I'm using Blender, which is excellent and free 3D modeling software. If you're already handy with Blender this section might be all you need. Otherwise, see the next section for screenshots and more detail. -**Version**: Constructing the model requires boolean operations on objects with co-planar surfaces. The only way I got this to properly work in Blender was using version **2.79b** which still has the `Carve` solver for the boolean modifier. I couldn't get it to work on 2.8+. According to the Blender forums, proper boolean operations with coplanar surfaces is in development, so this may change. - -- Import `sea` and `domain` and extrude them both in the z axis. Subtract `sea` from `domain` using boolean difference. Make sure to use `Carve` as the solver. +- Import `sea` and `domain` and extrude them both in the z axis. Subtract `sea` from `domain` using boolean difference. + - If using a Blender version below 2.8, you may need to use `Carve` as the solver. - Import `coastline` and extrude in the z axis. Union with `domain`. - Import `river` and extrude in z axis. Subtract from `domain` with boolean difference. - If you don't care about accurate roads, import `blocks` and `buildings` and place them on top of `domain`. -- If you want proper road geometry, import `roads`. Extract in z, select all, press `p -> By loose parts`. This splits each road into its own object. +- If you want proper road geometry, import `roads`. Extrude in z, select all, press `p -> By loose parts`. This splits each road into its own object. - Enable `Bool Tools` addon - Select `domain` and all of the separate road objects, with `domain` as the active object. - Use `BoolTools -> difference` to subtract roads from `domain`. @@ -40,7 +39,6 @@ If you're already handy with Blender this section might be all you need. Otherwi - Import roads again, extrude in z, use it to create the roads by filling the gaps in `domain`. Control the road depth with the z location of `roads`. - Import `domain` again, use it to create the sea and river. Control the depth with its z value. - ## Detailed Blender Overview Note that this isn't intended to be a first-time Blender tutorial, and may assume basic Blender knowledge. diff --git a/src/ts/model_generator.ts b/src/ts/model_generator.ts index a16cc5f4..b5504d53 100644 --- a/src/ts/model_generator.ts +++ b/src/ts/model_generator.ts @@ -17,6 +17,10 @@ enum ModelGeneratorStates { export default class ModelGenerator { private readonly groundLevel = 20; // Thickness of groundMesh + + // Using THREE.extrudeGeometry with depth = 0 flips normals + // Specifying a small minimum extrusion depth prevents issues with Boolean modifiers in Blender + private readonly minExtrudeDepth = 0.01; private readonly exportSTL = require('threejs-export-stl'); private resolve: (blob: any) => void = b => {}; @@ -72,12 +76,12 @@ export default class ModelGenerator { return false; } case ModelGeneratorStates.SUBTRACT_OCEAN: { - const seaLevelMesh = this.polygonToMesh(this.ground, 0); + const seaLevelMesh = this.polygonToMesh(this.ground, this.minExtrudeDepth); this.threeToBlender(seaLevelMesh); const seaLevelSTL = this.exportSTL.fromMesh(seaLevelMesh); this.zip.file("model/domain.stl", seaLevelSTL); - const seaMesh = this.polygonToMesh(this.sea, 0); + const seaMesh = this.polygonToMesh(this.sea, this.minExtrudeDepth); this.threeToBlender(seaMesh); const seaMeshSTL = this.exportSTL.fromMesh(seaMesh); this.zip.file("model/sea.stl", seaMeshSTL); @@ -85,7 +89,7 @@ export default class ModelGenerator { break; } case ModelGeneratorStates.ADD_COASTLINE: { - const coastlineMesh = this.polygonToMesh(this.coastline, 0); + const coastlineMesh = this.polygonToMesh(this.coastline, this.minExtrudeDepth); this.threeToBlender(coastlineMesh); const coastlineSTL = this.exportSTL.fromMesh(coastlineMesh); this.zip.file("model/coastline.stl", coastlineSTL); @@ -93,7 +97,7 @@ export default class ModelGenerator { break; } case ModelGeneratorStates.SUBTRACT_RIVER: { - const riverMesh = this.polygonToMesh(this.river, 0); + const riverMesh = this.polygonToMesh(this.river, this.minExtrudeDepth); this.threeToBlender(riverMesh); const riverSTL = this.exportSTL.fromMesh(riverMesh); this.zip.file("model/river.stl", riverSTL); @@ -114,7 +118,7 @@ export default class ModelGenerator { } const road = this.polygonsToProcess.pop(); - const roadsMesh = this.polygonToMesh(road, 0); + const roadsMesh = this.polygonToMesh(road, this.minExtrudeDepth); this.roadsGeometry.merge(roadsMesh.geometry as THREE.Geometry, this.groundMesh.matrix); break; }