mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-23 12:31:24 +01:00
Better cities and towns labels in 3D view
This commit is contained in:
parent
af1d369e31
commit
5cc2454765
2 changed files with 142 additions and 1 deletions
|
|
@ -82,6 +82,10 @@ async function getMapURL(type, subtype) {
|
||||||
const svgDefs = document.getElementById("defElements");
|
const svgDefs = document.getElementById("defElements");
|
||||||
|
|
||||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
||||||
|
if (type === "mesh") {
|
||||||
|
clone.select("#labels #burgLabels").remove();
|
||||||
|
clone.select("#icons #burgIcons").remove();
|
||||||
|
}
|
||||||
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 (subtype === "noWater") {
|
if (subtype === "noWater") {
|
||||||
|
|
|
||||||
139
modules/ui/3d.js
139
modules/ui/3d.js
|
|
@ -12,6 +12,8 @@ const options = {scale: 50, lightness: .7, shadow: .5, sun: {x: 100, y: 600, z:
|
||||||
let Renderer, scene, camera, controls, animationFrame, material, texture,
|
let Renderer, scene, camera, controls, animationFrame, material, texture,
|
||||||
geometry, mesh, ambientLight, spotLight, waterPlane, waterMaterial, waterMesh,
|
geometry, mesh, ambientLight, spotLight, waterPlane, waterMaterial, waterMesh,
|
||||||
objexporter;
|
objexporter;
|
||||||
|
let drawCtx = document.createElement('canvas').getContext('2d');
|
||||||
|
let textMeshs = [], iconMeshs = [];
|
||||||
|
|
||||||
// initiate 3d scene
|
// initiate 3d scene
|
||||||
const create = async function(canvas, type = "viewMesh") {
|
const create = async function(canvas, type = "viewMesh") {
|
||||||
|
|
@ -42,6 +44,17 @@ const stop = function() {
|
||||||
material.dispose();
|
material.dispose();
|
||||||
if (waterPlane) waterPlane.dispose();
|
if (waterPlane) waterPlane.dispose();
|
||||||
if (waterMaterial) waterMaterial.dispose();
|
if (waterMaterial) waterMaterial.dispose();
|
||||||
|
for (const mesh of textMeshs) {
|
||||||
|
mesh.material.map.dispose();
|
||||||
|
mesh.material.dispose();
|
||||||
|
mesh.geometry.dispose();
|
||||||
|
scene.remove(mesh);
|
||||||
|
}
|
||||||
|
for (const mesh of iconMeshs) {
|
||||||
|
mesh.material.dispose();
|
||||||
|
mesh.geometry.dispose();
|
||||||
|
scene.remove(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
Renderer.renderLists.dispose(); // is it required?
|
Renderer.renderLists.dispose(); // is it required?
|
||||||
Renderer.dispose();
|
Renderer.dispose();
|
||||||
|
|
@ -166,12 +179,50 @@ async function newMesh(canvas) {
|
||||||
controls.maxPolarAngle = Math.PI/2;
|
controls.maxPolarAngle = Math.PI/2;
|
||||||
controls.autoRotate = Boolean(options.rotateMesh);
|
controls.autoRotate = Boolean(options.rotateMesh);
|
||||||
controls.autoRotateSpeed = options.rotateMesh;
|
controls.autoRotateSpeed = options.rotateMesh;
|
||||||
if (controls.autoRotate) animate();
|
animate();
|
||||||
controls.addEventListener("change", render);
|
controls.addEventListener("change", render);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createTextMesh(text, font, size) {
|
||||||
|
drawCtx.clearRect(0, 0, drawCtx.canvas.width, drawCtx.canvas.height);
|
||||||
|
drawCtx.font = "50px " + font;
|
||||||
|
|
||||||
|
drawCtx.canvas.width = drawCtx.measureText(text).width;
|
||||||
|
drawCtx.canvas.height = 50 + 5;
|
||||||
|
drawCtx.font = "50px " + font;
|
||||||
|
|
||||||
|
drawCtx.fillStyle = "rgba(0,0,0,1)";
|
||||||
|
drawCtx.fillText(text, 0, 50);
|
||||||
|
|
||||||
|
// canvas contents will be used for a texture
|
||||||
|
let text_texture = new THREE.TextureLoader().load(drawCtx.canvas.toDataURL());
|
||||||
|
text_texture.minFilter = THREE.LinearFilter
|
||||||
|
text_texture.needsUpdate = true;
|
||||||
|
|
||||||
|
let text_material = new THREE.MeshBasicMaterial({map: text_texture/*, side:THREE.DoubleSide*/, depthWrite: false});
|
||||||
|
text_material.transparent = true;
|
||||||
|
|
||||||
|
let text_mesh = new THREE.Mesh(
|
||||||
|
new THREE.PlaneGeometry(drawCtx.canvas.width*(size/100), drawCtx.canvas.height*(size/100)),
|
||||||
|
text_material
|
||||||
|
);
|
||||||
|
text_mesh.renderOrder = 1;
|
||||||
|
|
||||||
|
return text_mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
function get3dCoords(x, base_y) {
|
||||||
|
const svg = $('svg#map')[0];
|
||||||
|
|
||||||
|
let y = getMeshHeight(findGridCell(x, base_y));
|
||||||
|
x = x - svg.width.baseVal.value/2;
|
||||||
|
let z = base_y - svg.height.baseVal.value/2;
|
||||||
|
|
||||||
|
return [x, y, z];
|
||||||
|
}
|
||||||
|
|
||||||
// create a mesh from pixel data
|
// create a mesh from pixel data
|
||||||
async function createMesh(width, height, segmentsX, segmentsY) {
|
async function createMesh(width, height, segmentsX, segmentsY) {
|
||||||
const url = await getMapURL("mesh", options.extendedWater ? "noWater" : null);
|
const url = await getMapURL("mesh", options.extendedWater ? "noWater" : null);
|
||||||
|
|
@ -196,6 +247,87 @@ async function createMesh(width, height, segmentsX, segmentsY) {
|
||||||
mesh.castShadow = true;
|
mesh.castShadow = true;
|
||||||
mesh.receiveShadow = true;
|
mesh.receiveShadow = true;
|
||||||
scene.add(mesh);
|
scene.add(mesh);
|
||||||
|
|
||||||
|
for (const mesh of textMeshs) {
|
||||||
|
mesh.material.map.dispose();
|
||||||
|
mesh.material.dispose();
|
||||||
|
mesh.geometry.dispose();
|
||||||
|
scene.remove(mesh);
|
||||||
|
}
|
||||||
|
textMeshs = []
|
||||||
|
|
||||||
|
for (const mesh of iconMeshs) {
|
||||||
|
mesh.material.dispose();
|
||||||
|
mesh.geometry.dispose();
|
||||||
|
scene.remove(mesh);
|
||||||
|
}
|
||||||
|
iconMeshs = []
|
||||||
|
|
||||||
|
const svg = $('svg#map')[0];
|
||||||
|
if(layerIsOn("toggleLabels")) {
|
||||||
|
const cities_labels = $('svg #viewbox #labels #burgLabels #cities')[0]
|
||||||
|
|
||||||
|
for (const label of cities_labels.childNodes) {
|
||||||
|
var text_mesh = createTextMesh(label.innerHTML, "Almendra SC", 25)
|
||||||
|
|
||||||
|
const [x, y, z] = get3dCoords(label.x.baseVal[0].value, label.y.baseVal[0].value)
|
||||||
|
text_mesh.position.set(x, y + 25, z);
|
||||||
|
text_mesh.animate = function () {
|
||||||
|
this.lookAt(camera.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
textMeshs.push(text_mesh)
|
||||||
|
scene.add(text_mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
const towns_labels = $('svg #viewbox #labels #burgLabels #towns')[0]
|
||||||
|
for (const label of towns_labels.childNodes) {
|
||||||
|
var text_mesh = createTextMesh(label.innerHTML, "Almendra SC", 7)
|
||||||
|
|
||||||
|
const [x, y, z] = get3dCoords(label.x.baseVal[0].value, label.y.baseVal[0].value)
|
||||||
|
text_mesh.position.set(x, y + 5, z);
|
||||||
|
text_mesh.animate = function () {
|
||||||
|
this.lookAt(camera.position);
|
||||||
|
if(this.position.distanceTo(camera.position) > 200) {
|
||||||
|
this.visible = false;
|
||||||
|
} else {
|
||||||
|
this.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textMeshs.push(text_mesh)
|
||||||
|
scene.add(text_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(layerIsOn("toggleIcons")) {
|
||||||
|
const cities_icon = $('svg #viewbox #icons #burgIcons #cities')[0]
|
||||||
|
for (const icon of cities_icon.childNodes) {
|
||||||
|
var icon_material = new THREE.MeshBasicMaterial({color: 0xcccccc});
|
||||||
|
var icon_mesh = new THREE.Mesh(
|
||||||
|
new THREE.SphereGeometry(2, 16, 16),
|
||||||
|
icon_material
|
||||||
|
);
|
||||||
|
|
||||||
|
icon_mesh.position.set(...get3dCoords(icon.cx.baseVal.value, icon.cy.baseVal.value))
|
||||||
|
|
||||||
|
iconMeshs.push(icon_mesh);
|
||||||
|
scene.add(icon_mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
const town_icon = $('svg #viewbox #icons #burgIcons #towns')[0]
|
||||||
|
for (const icon of town_icon.childNodes) {
|
||||||
|
var icon_material = new THREE.MeshBasicMaterial({color: 0xcccccc});
|
||||||
|
var icon_mesh = new THREE.Mesh(
|
||||||
|
new THREE.SphereGeometry(1, 16, 16),
|
||||||
|
icon_material
|
||||||
|
);
|
||||||
|
|
||||||
|
icon_mesh.position.set(...get3dCoords(icon.cx.baseVal.value, icon.cy.baseVal.value))
|
||||||
|
|
||||||
|
iconMeshs.push(icon_mesh);
|
||||||
|
scene.add(icon_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMeshHeight(i) {
|
function getMeshHeight(i) {
|
||||||
|
|
@ -317,6 +449,11 @@ function render() {
|
||||||
function animate() {
|
function animate() {
|
||||||
animationFrame = requestAnimationFrame(animate);
|
animationFrame = requestAnimationFrame(animate);
|
||||||
controls.update();
|
controls.update();
|
||||||
|
for(const mesh of textMeshs) {
|
||||||
|
if(mesh.animate) {
|
||||||
|
mesh.animate();
|
||||||
|
}
|
||||||
|
}
|
||||||
Renderer.render(scene, camera);
|
Renderer.render(scene, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue