mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
Added 3d options
This commit is contained in:
parent
f4fa36a1ca
commit
3cb5b69d83
5 changed files with 355 additions and 18 deletions
|
|
@ -1987,6 +1987,10 @@ svg.button {
|
||||||
border: dashed 1px #5d4651;
|
border: dashed 1px #5d4651;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#threeDOptions {
|
||||||
|
background-color: #a48b95;
|
||||||
|
}
|
||||||
|
|
||||||
#debug {
|
#debug {
|
||||||
font-size: 1px;
|
font-size: 1px;
|
||||||
opacity: .8;
|
opacity: .8;
|
||||||
|
|
|
||||||
48
index.html
48
index.html
|
|
@ -2536,6 +2536,54 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="threeDOptions" class="dialog stable" style="display: none">
|
||||||
|
<table>
|
||||||
|
<tbody id="threeDBody">
|
||||||
|
<tr data-tip="Adjust to change how high mountains and raised areas appear to be">
|
||||||
|
<td>Height scale:</td><td><input id="threeDHeightScale" type="range" min="1" max="200" value="50"></td>
|
||||||
|
</tr>
|
||||||
|
<tr p-tip="Change the scene background color">
|
||||||
|
<td>Scene background color:</td><td><input id="threeDBackgroundColor" type="color" value="#000000"/>
|
||||||
|
<output id="threeDBackgroundColorOutput">#000000</output></td>
|
||||||
|
</tr>
|
||||||
|
<tr data-tip="Enable/disable spotlight and set distance (for shadows)">
|
||||||
|
<td><input id="threeDSpotlight" type="checkbox" class="checkbox" checked>
|
||||||
|
<label for="threeDSpotlight" class="checkbox-label">Spotlight:</label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Spotlight distance: </td>
|
||||||
|
<td><input id="threeDSpotlightDistance" type="range" min="500" max="5000" value="1000"></td>
|
||||||
|
</tr>
|
||||||
|
<tr data-tip="Enable/disable shadows">
|
||||||
|
<td><input id="threeDShadows" type="checkbox" class="checkbox" checked>
|
||||||
|
<label for="threeDShadows" class="checkbox-label">Shadows</label></td>
|
||||||
|
</tr>
|
||||||
|
<tr p-tip="Enable/disable fog and set distance and color">
|
||||||
|
<td><input id="threeDFog" type="checkbox" class="checkbox">
|
||||||
|
<label for="threeDFog" class="checkbox-label">Show fog</label></td>
|
||||||
|
<td>Color: <input id="threeDFogColor" type="color" value="#cccccc"/>
|
||||||
|
<output id="threeDFogColorOutput">#cccccc</output></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fog distance: </td>
|
||||||
|
<td><input id="threeDFogDistance" type="range" min="0" max="3000" value="500"></td>
|
||||||
|
</tr>
|
||||||
|
<tr data-tip="Enable/disable skybox">
|
||||||
|
<td><input id="threeDSkybox" type="checkbox" class="checkbox">
|
||||||
|
<label for="threeDSkybox" class="checkbox-label">Show skybox</label></td>
|
||||||
|
</tr>
|
||||||
|
<tr data-tip="Skybox image used for texture">
|
||||||
|
<td>Skybox image: </td>
|
||||||
|
<td><input id="threeDSkyboxURL" type="text" placeholder="http://www.example.com/skybox.jpg" size=35></td>
|
||||||
|
</tr>
|
||||||
|
<tr data-tip="Enable/disable extended water">
|
||||||
|
<td><input id="threeDExtendedWater" type="checkbox" class="checkbox">
|
||||||
|
<label for="threeDExtendedWater" class="checkbox-label">Extended water</label></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="biomesEditor" class="dialog stable" style="display: none">
|
<div id="biomesEditor" class="dialog stable" style="display: none">
|
||||||
<div id="biomesHeader" class="header">
|
<div id="biomesHeader" class="header">
|
||||||
<div style="left:1.4em" data-tip="Click to sort by biome name" class="sortable alphabetically" data-sortby="name">Biome </div>
|
<div style="left:1.4em" data-tip="Click to sort by biome name" class="sortable alphabetically" data-sortby="name">Biome </div>
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,40 @@ async function saveJPEG() {
|
||||||
console.timeEnd("saveJPEG");
|
console.timeEnd("saveJPEG");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getWater(width, height) {
|
||||||
|
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
|
||||||
|
cloneEl.id = "fantasyMap";
|
||||||
|
document.body.appendChild(cloneEl);
|
||||||
|
const clone = d3.select(cloneEl);
|
||||||
|
clone.select("#debug").remove();
|
||||||
|
|
||||||
|
clone.attr("width", graphWidth).attr("height", graphHeight);
|
||||||
|
|
||||||
|
clone.select("#oceanPattern").select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||||
|
clone.select("#oceanLayers").select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||||
|
|
||||||
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
|
if (isFirefox) clone.select("#oceanPattern").remove();
|
||||||
|
clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
||||||
|
|
||||||
|
clone.selectAll("g").each(function() {
|
||||||
|
if (this.id !== "oceanPattern" && this.id !== "oceanLayers" && this.id !== "oceanBase" && this.id !== "viewbox" && this.id !== "ocean")
|
||||||
|
this.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove the layers, but keep the background colour
|
||||||
|
clone.select("#oceanLayers").selectAll("path").remove();
|
||||||
|
|
||||||
|
clone.append("metadata").text("<dc:format>image/svg+xml</dc:format>");
|
||||||
|
const serialized = (new XMLSerializer()).serializeToString(clone.node());
|
||||||
|
const svg_xml = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + serialized;
|
||||||
|
clone.remove();
|
||||||
|
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
// parse map svg to object url
|
// parse map svg to object url
|
||||||
async function getMapURL(type, subtype) {
|
async function getMapURL(type, subtype) {
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
|
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
|
||||||
|
|
@ -84,7 +118,14 @@ async function getMapURL(type, subtype) {
|
||||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
|
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
|
||||||
if (subtype === "globe") clone.select("#scaleBar").remove();
|
if (subtype === "globe") clone.select("#scaleBar").remove();
|
||||||
if (type === "mesh") clone.attr("width", graphWidth).attr("height", graphHeight);
|
if (type === "mesh") {
|
||||||
|
clone.attr("width", graphWidth).attr("height", graphHeight);
|
||||||
|
|
||||||
|
if (threeDExtendedWater.checked && subtype !== "globe") {
|
||||||
|
clone.select("#oceanBase").attr("opacity", 0);
|
||||||
|
clone.select("#oceanPattern").attr("opacity", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (type !== "png") clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
if (type !== "png") clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
||||||
if (type === "svg") removeUnusedElements(clone);
|
if (type === "svg") removeUnusedElements(clone);
|
||||||
if (customization && type === "mesh") updateMeshCells(clone);
|
if (customization && type === "mesh") updateMeshCells(clone);
|
||||||
|
|
@ -886,7 +927,6 @@ function parseLoadedData(data) {
|
||||||
|
|
||||||
// v 1.11 had an issue with fogging being displayed on load
|
// v 1.11 had an issue with fogging being displayed on load
|
||||||
unfog();
|
unfog();
|
||||||
|
|
||||||
// v 1.2 added new terrain attributes
|
// v 1.2 added new terrain attributes
|
||||||
if (!terrain.attr("set")) terrain.attr("set", "simple");
|
if (!terrain.attr("set")) terrain.attr("set", "simple");
|
||||||
if (!terrain.attr("size")) terrain.attr("size", 1);
|
if (!terrain.attr("size")) terrain.attr("size", 1);
|
||||||
|
|
|
||||||
272
modules/ui/3d.js
272
modules/ui/3d.js
|
|
@ -7,13 +7,14 @@ async function start3d(canvas) {
|
||||||
const loaded = await loadTHREE();
|
const loaded = await loadTHREE();
|
||||||
if (!loaded) {tip("Cannot load 3d library", false, "error", 4000); return false};
|
if (!loaded) {tip("Cannot load 3d library", false, "error", 4000); return false};
|
||||||
|
|
||||||
|
threeD.Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
|
||||||
threeD.scene = new THREE.Scene();
|
threeD.scene = new THREE.Scene();
|
||||||
//threeD.scene.background = new THREE.Color(0x53679f);
|
//threeD.scene.background = new THREE.Color(0x53679f);
|
||||||
threeD.camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 2000);
|
threeD.camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 3000);
|
||||||
|
threeD.camera.name = "camera";
|
||||||
threeD.camera.position.x = 0;
|
threeD.camera.position.x = 0;
|
||||||
threeD.camera.position.z = 350;
|
threeD.camera.position.z = 350;
|
||||||
threeD.camera.position.y = 285;
|
threeD.camera.position.y = 285;
|
||||||
threeD.Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
|
|
||||||
threeD.controls = await OrbitControls(threeD.camera, threeD.Renderer.domElement);
|
threeD.controls = await OrbitControls(threeD.camera, threeD.Renderer.domElement);
|
||||||
threeD.controls.minDistance = 10; threeD.controls.maxDistance = 1000;
|
threeD.controls.minDistance = 10; threeD.controls.maxDistance = 1000;
|
||||||
threeD.controls.maxPolarAngle = Math.PI/2;
|
threeD.controls.maxPolarAngle = Math.PI/2;
|
||||||
|
|
@ -21,14 +22,15 @@ async function start3d(canvas) {
|
||||||
|
|
||||||
threeD.Renderer.setSize(canvas.width, canvas.height);
|
threeD.Renderer.setSize(canvas.width, canvas.height);
|
||||||
add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
||||||
|
addLight();
|
||||||
|
|
||||||
const ambientLight = new THREE.AmbientLight(0xcccccc, .7);
|
updateWaterMesh();
|
||||||
threeD.scene.add(ambientLight);
|
updateFog();
|
||||||
const spotLight = new THREE.SpotLight(0xcccccc, .8, 2000, .7, 0, 0);
|
updateSkybox();
|
||||||
spotLight.position.set(100, 600, 1000);
|
updateFogDistance();
|
||||||
spotLight.castShadow = true;
|
updateSceneBackground();
|
||||||
threeD.scene.add(spotLight);
|
updateLight();
|
||||||
//threeD.scene.add(new THREE.SpotLightHelper(spotLight));
|
updateShadows();
|
||||||
|
|
||||||
threeD.controls.addEventListener("change", render);
|
threeD.controls.addEventListener("change", render);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -48,17 +50,211 @@ async function add3dMesh(width, height, segmentsX, segmentsY) {
|
||||||
const texture = new THREE.TextureLoader().load(url, render);
|
const texture = new THREE.TextureLoader().load(url, render);
|
||||||
texture.needsUpdate = true;
|
texture.needsUpdate = true;
|
||||||
threeD.material.map = texture;
|
threeD.material.map = texture;
|
||||||
|
threeD.material.transparent = true;
|
||||||
|
|
||||||
|
threeDscale = parseInt(threeDHeightScale.value);
|
||||||
geometry.vertices.forEach((v, i) => v.z = getMeshHeight(i));
|
geometry.vertices.forEach((v, i) => v.z = getMeshHeight(i));
|
||||||
geometry.computeVertexNormals(); // added
|
geometry.computeVertexNormals();
|
||||||
threeD.Renderer.shadowMap.enabled = true; // added
|
threeD.Renderer.shadowMap.enabled = true;
|
||||||
threeD.mesh = new THREE.Mesh(geometry, threeD.material);
|
threeD.mesh = new THREE.Mesh(geometry, threeD.material);
|
||||||
|
threeD.mesh.name = "ground";
|
||||||
threeD.mesh.rotation.x = -Math.PI / 2;
|
threeD.mesh.rotation.x = -Math.PI / 2;
|
||||||
threeD.mesh.castShadow = true;
|
if (threeDShadows.checked) {
|
||||||
threeD.mesh.receiveShadow = true;
|
threeD.mesh.castShadow = true;
|
||||||
|
threeD.mesh.receiveShadow = true;
|
||||||
|
threeD.Renderer.shadowMap.enabled = true;
|
||||||
|
} else {
|
||||||
|
threeD.mesh.castShadow = false;
|
||||||
|
threeD.mesh.receiveShadow = false;
|
||||||
|
threeD.Renderer.shadowMap.enabled = false;
|
||||||
|
}
|
||||||
threeD.scene.add(threeD.mesh);
|
threeD.scene.add(threeD.mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addWaterMesh(width, height) {
|
||||||
|
const waterPlane = new THREE.PlaneGeometry(width*16, height*16, 10, 10);
|
||||||
|
const waterMaterial = new THREE.MeshLambertMaterial();
|
||||||
|
const urlWater = await getWater(width*16, height*16);
|
||||||
|
|
||||||
|
waterMaterial.map = new THREE.TextureLoader().load(urlWater);
|
||||||
|
// this is to hide the ocean when viewing from sea level
|
||||||
|
waterMaterial.polygonOffset = true;
|
||||||
|
waterMaterial.polygonOffsetFactor = 2;
|
||||||
|
|
||||||
|
threeD.waterMesh = new THREE.Mesh(waterPlane, waterMaterial);
|
||||||
|
threeD.waterMesh.rotation.x = -Math.PI / 2;
|
||||||
|
threeD.waterMesh.position.y -= 3; // fix for z-fighting, gap is visible at sea level
|
||||||
|
threeD.waterMesh.castShadow = false;
|
||||||
|
threeD.waterMesh.receiveShadow = false;
|
||||||
|
threeD.scene.add(threeD.waterMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHeightScale() {
|
||||||
|
update3dPreview(canvas3d);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateWaterMesh() {
|
||||||
|
if (threeDExtendedWater.checked) {
|
||||||
|
await addWaterMesh(graphWidth, graphHeight);
|
||||||
|
update3dPreview(canvas3d);
|
||||||
|
} else {
|
||||||
|
if (threeD.waterMesh) {
|
||||||
|
threeD.scene.remove(threeD.waterMesh);
|
||||||
|
threeD.waterMesh = undefined;
|
||||||
|
update3dPreview(canvas3d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLight() {
|
||||||
|
threeD.ambientLight = new THREE.AmbientLight(0xcccccc, .7);
|
||||||
|
threeD.scene.add(threeD.ambientLight);
|
||||||
|
|
||||||
|
threeD.spotLight = new THREE.SpotLight(0xcccccc, .8, 1000, .7, 0, 0);
|
||||||
|
threeD.spotLight.position.set(100, 600, parseInt(threeDSpotlightDistance.value));
|
||||||
|
threeD.spotLight.castShadow = threeDShadows.checked;
|
||||||
|
threeD.scene.add(threeD.spotLight);
|
||||||
|
//threeD.scene.add(new THREE.SpotLightHelper(spotLight));
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLight() {
|
||||||
|
if (threeDSpotlight.checked) {
|
||||||
|
if (threeD.spotLight) { threeD.spotLight.visible = true; }
|
||||||
|
} else {
|
||||||
|
if (threeD.spotLight) { threeD.spotLight.visible = false; }
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSpotlightDistance() {
|
||||||
|
threeD.spotLight.position.z = parseInt(threeDSpotlightDistance.value);
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateShadows() {
|
||||||
|
var b = threeDShadows.checked;
|
||||||
|
if (threeD.mesh) {
|
||||||
|
threeD.mesh.castShadow = b;
|
||||||
|
threeD.mesh.receiveShadow = b;
|
||||||
|
threeD.Renderer.shadowMap.enabled = b;
|
||||||
|
}
|
||||||
|
if (threeD.spotLight) {
|
||||||
|
threeD.spotLight.castShadow = b;
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFog() {
|
||||||
|
var fogColor = new THREE.Color(threeDFogColorOutput.value);
|
||||||
|
threeD.scene.background = fogColor;
|
||||||
|
threeD.scene.fog = new THREE.Fog(fogColor, parseInt(threeDFogDistance.value), 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFog() {
|
||||||
|
const w = document.getElementById("threeDFog");
|
||||||
|
if (w.checked) {
|
||||||
|
addFog();
|
||||||
|
} else {
|
||||||
|
threeD.scene.fog = undefined;
|
||||||
|
render();
|
||||||
|
updateSceneBackground();
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFogDistance() {
|
||||||
|
if (threeD.scene.fog) { threeD.scene.fog.near = parseInt(threeDFogDistance.value); render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSceneBackground() {
|
||||||
|
var bgColor = new THREE.Color(threeDBackgroundColorOutput.value);
|
||||||
|
|
||||||
|
threeD.scene.background = bgColor;
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRGB(color) {
|
||||||
|
var rgb = color.match(/^rgb?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
|
||||||
|
return {
|
||||||
|
r: parseInt(rgb[1]),
|
||||||
|
g: parseInt(rgb[2]),
|
||||||
|
b: parseInt(rgb[3]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSkyboxTexture(width, height) {
|
||||||
|
var url = threeDSkyboxURL.value;
|
||||||
|
if (url != "") {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
// this is a light-blue gradient
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
var color = d3.scaleSequential(d3.interpolateBlues);
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var image = ctx.createImageData(width, height);
|
||||||
|
|
||||||
|
for (var y=0; y < height; y++) {
|
||||||
|
let v = (y / height * 0.6) + (0.2); // use center 60% of "Blues"
|
||||||
|
let rgb = getRGB(color(1-v));
|
||||||
|
for (var x=0; x < width; x++) {
|
||||||
|
let i = (y * width + x) * 4;
|
||||||
|
image.data[i+0] = rgb.r;
|
||||||
|
image.data[i+1] = rgb.g;
|
||||||
|
image.data[i+2] = rgb.b;
|
||||||
|
image.data[i+3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.putImageData(image,0,0);
|
||||||
|
return canvas.toDataURL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSkybox() {
|
||||||
|
const shader = THREE.ShaderLib.equirect;
|
||||||
|
|
||||||
|
const skyMaterial = new THREE.ShaderMaterial({
|
||||||
|
fragmentShader: shader.fragmentShader,
|
||||||
|
vertexShader: shader.vertexShader,
|
||||||
|
uniforms: shader.uniforms,
|
||||||
|
depthWrite: false,
|
||||||
|
side: THREE.BackSide,
|
||||||
|
});
|
||||||
|
const texture = new THREE.TextureLoader().load(getSkyboxTexture(640, 320));
|
||||||
|
texture.magFilter = THREE.LinearFilter;
|
||||||
|
texture.minFilter = THREE.LinearFilter;
|
||||||
|
|
||||||
|
skyMaterial.uniforms.tEquirect.value = texture;
|
||||||
|
|
||||||
|
var plane = new THREE.SphereGeometry(1900, 32, 32);
|
||||||
|
threeD.skyMesh = new THREE.Mesh(plane, skyMaterial);
|
||||||
|
threeD.scene.add(threeD.skyMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateSkybox() {
|
||||||
|
if (threeDSkybox.checked) {
|
||||||
|
await addSkybox();
|
||||||
|
} else {
|
||||||
|
if (threeD.skyMesh) {
|
||||||
|
threeD.scene.remove(threeD.skyMesh);
|
||||||
|
threeD.skyMesh = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateSkyboxType() {
|
||||||
|
if (threeD.skyMesh) {
|
||||||
|
threeD.scene.remove(threeD.skyMesh);
|
||||||
|
threeD.skyMesh = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
await addSkybox();
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
function getMeshHeight(i) {
|
function getMeshHeight(i) {
|
||||||
const h = grid.cells.h[i];
|
const h = grid.cells.h[i];
|
||||||
return h < 20 ? 0 : (h - 18) / 82 * threeDscale;
|
return h < 20 ? 0 : (h - 18) / 82 * threeDscale;
|
||||||
|
|
@ -138,7 +334,11 @@ function OrbitControls(camera, domElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update3dPreview(canvas) {
|
function update3dPreview(canvas) {
|
||||||
threeD.scene.remove(threeD.mesh);
|
if (threeD.mesh) {
|
||||||
|
threeD.mesh.geometry.dispose();
|
||||||
|
threeD.mesh.material.dispose();
|
||||||
|
threeD.scene.remove(threeD.mesh);
|
||||||
|
}
|
||||||
threeD.Renderer.setSize(canvas.width, canvas.height);
|
threeD.Renderer.setSize(canvas.width, canvas.height);
|
||||||
if (canvas.dataset.type === "viewGlobe") addGlobe3dMesh();
|
if (canvas.dataset.type === "viewGlobe") addGlobe3dMesh();
|
||||||
else add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
else add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
||||||
|
|
@ -156,6 +356,10 @@ function stop3d() {
|
||||||
threeD.Renderer.dispose()
|
threeD.Renderer.dispose()
|
||||||
cancelAnimationFrame(threeD.animationFrame);
|
cancelAnimationFrame(threeD.animationFrame);
|
||||||
threeD = {};
|
threeD = {};
|
||||||
|
|
||||||
|
if (modules.edit3d) {
|
||||||
|
$("#threeDOptions").dialog("close");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startGlobe(canvas) {
|
async function startGlobe(canvas) {
|
||||||
|
|
@ -224,3 +428,43 @@ async function saveScreenshot() {
|
||||||
tip(`Screenshot is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
tip(`Screenshot is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
||||||
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
|
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function close3d() {
|
||||||
|
modules.edit3d = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show3doptions(type) {
|
||||||
|
if (type === "view3D") {
|
||||||
|
if (modules.edit3d) return;
|
||||||
|
modules.edit3d = true;
|
||||||
|
|
||||||
|
$("#threeDOptions").dialog({
|
||||||
|
title: "3D Options", resizable: false, width: fitContent(), close: close3d,
|
||||||
|
position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}
|
||||||
|
});
|
||||||
|
|
||||||
|
threeDHeightScale.addEventListener("click", updateHeightScale);
|
||||||
|
threeDExtendedWater.addEventListener("click", updateWaterMesh);
|
||||||
|
threeDFog.addEventListener("click", updateFog);
|
||||||
|
threeDFogDistance.addEventListener("change", updateFogDistance);
|
||||||
|
threeDSkybox.addEventListener("click", updateSkybox);
|
||||||
|
threeDSpotlight.addEventListener("click", updateLight);
|
||||||
|
threeDSpotlightDistance.addEventListener("change", updateSpotlightDistance);
|
||||||
|
threeDShadows.addEventListener("click", updateShadows);
|
||||||
|
|
||||||
|
threeDFogColor.addEventListener("input", function() {
|
||||||
|
threeDFogColor.value = threeDFogColorOutput.value = d3.color(this.value).hex();
|
||||||
|
updateFog();
|
||||||
|
});
|
||||||
|
|
||||||
|
threeDBackgroundColor.addEventListener("input", function() {
|
||||||
|
threeDBackgroundColor.value = threeDBackgroundColorOutput.value = d3.color(this.value).hex();
|
||||||
|
updateSceneBackground();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (modules.edit3d) {
|
||||||
|
$("#threeDOptions").dialog("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -466,4 +466,5 @@ async function enter3dView(type) {
|
||||||
+canvas.dataset.hovered > 2 ? tip("") : tip(help);
|
+canvas.dataset.hovered > 2 ? tip("") : tip(help);
|
||||||
canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
|
canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
|
||||||
};
|
};
|
||||||
|
show3doptions(type);
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue