diff --git a/elaborate.js b/elaborate.js
index 7e14f7b..37e5767 100644
--- a/elaborate.js
+++ b/elaborate.js
@@ -24,7 +24,7 @@ class Node {
}
isWaterBody() {
- return this.isSea() || this.waterHeight > 0;
+ return this.isSea() || this.waterHeight > this.baseHeight+1e-8;
}
isSink() {
@@ -32,7 +32,11 @@ class Node {
}
height() {
- return this.baseHeight + this.waterHeight;
+ return Math.max(this.baseHeight, this.waterHeight);
+ }
+
+ waterVolume() {
+ return Math.max(this.waterHeight - this.baseHeight, 0);
}
changeGround(ground) {
@@ -206,7 +210,7 @@ class World {
for (let node of this.graph.sinks()) {
fringe.put(node);
visited.add(node.id.hash());
- node.waterHeight = Math.max(0, -node.baseHeight);
+ node.waterHeight = 0;
}
while (!fringe.isEmpty()) {
let node = fringe.take();
@@ -215,32 +219,32 @@ class World {
for (let neighbour of node.neighbours) {
if (!visited.has(neighbour.id.hash())) {
let dh = neighbour.baseHeight - node.baseHeight;
- if (dh > 0 && !neighbour.waterHeight) {
+ if (dh > 0 && !neighbour.isWaterBody()) {
let water = node.isSink() ? 1 : node.water;
let erosion = Math.sqrt(water) * (baseErosion + momentumErosion*neighbour.momentum) / neighbour.size;
let newHeight = clamp(node.baseHeight + dh / (1+erosion), node.baseHeight, neighbour.baseHeight);
let eroded = neighbour.baseHeight - newHeight;
+ if (!eroded && eroded !== 0) {
+ console.log("erosion error", erosion, water, baseErosion, momentumErosion, neighbour.momentum, neighbour.size);
+ }
neighbour.changeGround(-eroded);
this.sediment.created += eroded;
neighbour.sediment += eroded;
}
- neighbour.waterHeight = 0;
+ neighbour.waterHeight = -1e9;
neighbour.sea = false;
neighbour.drains = [];
if (neighbour.height() < node.height()) {
+ neighbour.waterHeight = node.height() + 1e-7 * (2+randf(neighbour.id, this.graph.seed ^ 4890));
if (node.isSea()) {
- neighbour.waterHeight = node.height() - neighbour.baseHeight + 1e-7 * (2+randf(neighbour.id, this.graph.seed ^ 4890));
+ // neighbour.waterHeight = node.waterHeight + 1e-7 * (2+randf(neighbour.id, this.graph.seed ^ 4890));
neighbour.sea = true;
} else {
- let l = clamp(noise.GetNoise(neighbour.pos.x, neighbour.pos.y) + lakeAmount * 2 - 1, -1, 1);
- if (l > 0) {
- neighbour.waterHeight = l * (node.height() - neighbour.height()) * lakeDepth;
- let totalHeight = node.height() + 1e-6 * randf(neighbour.id, this.graph.seed ^ 8429);
- neighbour.baseHeight = totalHeight - neighbour.waterHeight;
- } else {
- neighbour.baseHeight = node.height() + randf(neighbour.id, this.graph.seed ^ 3627) * plainsSlope / (node.height() - neighbour.height() + 1);
- }
+ let l = clamp(noise.GetNoise(neighbour.pos.x, neighbour.pos.y) + lakeAmount * 2 - 1, 0, 1) * lakeDepth;
+ neighbour.baseHeight = neighbour.baseHeight * l + neighbour.waterHeight * (1-l);
}
+ } else {
+ neighbour.waterHeight = node.waterHeight + 1e-7 * (2+randf(neighbour.id, this.graph.seed ^ 8429));
}
fringe.put(neighbour);
visited.add(neighbour.id.hash());
@@ -271,6 +275,9 @@ class World {
let outflow = [];
for (let drain of drains) {
let dh = nh - drain.height();
+ if (!(dh >= 0)) {
+ console.log("drain order error", dh, nh, dh);
+ }
node.momentum += dh;
let o = node.isWaterBody() ? 1 : dh**cohesion;
outflow.push([drain, o]);
@@ -298,8 +305,11 @@ class World {
continue;
}
let drains = this.graph.drains(node);
- let deposited = clamp((amount +node.waterHeight * depthFactor) * node.sediment / (node.water+amount) / (node.momentum+1), 0, node.sediment);
+ let deposited = clamp((amount + node.waterVolume()* depthFactor) * node.sediment / (node.water+amount) / (node.momentum+1), 0, node.sediment);
node.sediment -= deposited;
+ if (!deposited && deposited !== 0) {
+ console.log("deposit error", deposited);
+ }
node.changeGround(deposited);
this.sediment.deposited += deposited;
for (let [drain, o] of node.outflow) {
@@ -308,6 +318,20 @@ class World {
node.sediment = 0;
}
}
+
+ amplifyWater() {
+ for (let node of this.graph.all()) {
+ if (node.isWaterBody()) {
+ continue;
+ }
+ let wetNeighbours = node.neighbours.filter(n => n.isWaterBody());
+ if (wetNeighbours.length) {
+ node.waterHeight = Math.min(node.height(), wetNeighbours.reduce((acc, n) => acc + n.waterHeight, 0) / wetNeighbours.length)
+ } else {
+ node.waterHeight = -1e6;
+ }
+ }
+ }
}
@@ -341,6 +365,7 @@ async function generate(settings, view) {
sorted = await view.time("flow", () => world.land(settings.plainsSlope, settings.lakeAmount, settings.lakeSize, 1, settings.baseErosion * erosionWeight, settings.momentumErosion * erosionWeight));
await view.time("drain", () => world.drain(sorted, settings.rainfall, settings.cohesion, Math.pow(settings.slowing, settings.nodeSize)));
}
+ await view.time("amplify water", () => world.amplifyWater());
await view.time("draw", () => view.drawWorldGraph(graph, settings));
console.log(`sediment created: ${world.sediment.created / 1e6}, sediment deposited: ${world.sediment.deposited/1e6}, sediment lost: ${world.sediment.lost/1e6}, balance: ${(world.sediment.created - world.sediment.deposited - world.sediment.lost)/1e6}`);
let endTime = Date.now();
diff --git a/index.html b/index.html
index 9d84e0a..56e3fb3 100644
--- a/index.html
+++ b/index.html
@@ -269,6 +269,11 @@
boosted movement speed
+
+ field of view
+
+
+
diff --git a/main.js b/main.js
index f71395c..dcccc0d 100644
--- a/main.js
+++ b/main.js
@@ -18,6 +18,10 @@ class CanvasView {
} else if (n.isWaterBody()) {
return [76, 76, 255];
} else {
+ let v = n.height();
+ if (v != v) {
+ console.log(n);
+ }
return settings.colorScale.rgbBytes(n.height() / settings.colorMax);
}
});
diff --git a/view3d.js b/view3d.js
index 6031bf3..691e60e 100644
--- a/view3d.js
+++ b/view3d.js
@@ -79,7 +79,7 @@ class ThreeView {
this.scene.add(directionalLight);
const ambientLight = new THREE.AmbientLight(0x88888888);
this.scene.add(ambientLight);
- this.currentGround = null;
+ this.terrain = null;
this.visible = false;
}
@@ -88,46 +88,44 @@ class ThreeView {
console.log("drawing graph 3d");
let settings = readSettings(document.getElementById("draw3dsettings"));
console.log(settings);
+ this.camera.fov = settings.fov
+ this.camera.updateProjectionMatrix();
this.movementSpeed = settings.movementSpeed;
this.boostSpeed = settings.boostSpeed;
+
+ let terrain = new THREE.Group()
+
let vertices = [];
+ let waterVertices = []
let colors = []
let indices = [];
- if (settings.flatFaces) {
- for (let triangle of graph.triangles()) {
- for (let node of triangle) {
- vertices.push(node.pos.x * settings.horizontalScale, node.height() * settings.heightScale, node.pos.y * settings.horizontalScale);
- if (node.isSea()) {
- colors.push(0, 0, 0.9);
- } else if (node.isWaterBody()) {
- colors.push(0.2, 0.2, 1);
- } else {
- colors.push(...settings.colorScale.rgbFloats(node.height() / settings.colorMax));
- }
- }
- }
- } else {
- let nodeIndex = new Map();
- let i = 0;
- for (let node of graph.all()) {
- vertices.push(node.pos.x * settings.horizontalScale, node.height() * settings.heightScale, node.pos.y * settings.horizontalScale);
- if (node.isSea()) {
- colors.push(0, 0, 0.9);
- } else if (node.isWaterBody()) {
- colors.push(0.2, 0.2, 1);
- } else {
- colors.push(...settings.colorScale.rgbFloats(node.height() / settings.colorMax));
- }
- nodeIndex.set(node.id.hash(), i++);
- }
+ let nodes = settings.flatFaces ? [...graph.triangles()].flatMap(triangle => triangle) : graph.all();
+ let nodeIndex = new Map();
+ let i = 0;
+ for (let node of nodes) {
+ vertices.push(node.pos.x * settings.horizontalScale, node.baseHeight * settings.heightScale, node.pos.y * settings.horizontalScale);
+ waterVertices.push(node.pos.x * settings.horizontalScale, node.waterHeight * settings.heightScale, node.pos.y * settings.horizontalScale);
+ colors.push(...settings.colorScale.rgbFloats(node.baseHeight / settings.colorMax));
+ nodeIndex.set(node.id.hash(), i++);
+ }
- for (let triangle of graph.triangles()) {
- for (let node of triangle) {
- indices.push(nodeIndex.get(node.id.hash()));
- }
+ for (let triangle of graph.triangles()) {
+ for (let node of triangle) {
+ indices.push(nodeIndex.get(node.id.hash()));
}
}
+ const waterGeometry = new THREE.BufferGeometry();
+ waterGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(waterVertices), 3));
+ if (!settings.flatFaces) {
+ waterGeometry.setIndex(indices);
+ }
+ waterGeometry.computeBoundingBox();
+ waterGeometry.computeVertexNormals()
+ let water = new THREE.Mesh(waterGeometry, new THREE.MeshStandardMaterial({color: 0x0000ff}));
+ water.position.y -= 1e-6;
+ terrain.add(water);
+
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
@@ -138,13 +136,20 @@ class ThreeView {
geometry.computeVertexNormals()
let ground = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({vertexColors: true}));
+ terrain.add(ground);
+
+
if (settings.centerMesh) {
- ground.position.x -= graph.size.x * settings.horizontalScale / 2;
- ground.position.z -= graph.size.y * settings.horizontalScale / 2;
+ terrain.position.x -= graph.size.x * settings.horizontalScale / 2;
+ terrain.position.z -= graph.size.y * settings.horizontalScale / 2;
}
- this.scene.remove(this.currentGround);
- this.scene.add(ground);
- this.currentGround = ground;
+ if (this.terrain) {
+ this.scene.remove(this.terrain);
+ }
+ this.terrain = terrain;
+ this.scene.add(this.terrain);
+
+ this.renderer.setSize( window.innerWidth, window.innerHeight );
console.log("graph 3d drawn");
}