3D Scene system upgrade. (#956)

* 3d view system upgrade.

* version fix

* Versioning fixed.

* Subdivision Added

* Subdivision added. Removed toggle wireframe as an option.
Reverted to previous rendering method.

* Update obj export because new threejs version.

* Clean up of unrequired code.

* Multiple fixes to 3D view upgrade PR.

* Remove unused code.(for3DRender)
This commit is contained in:
Efruz Yıldırır 2023-08-05 21:54:13 +03:00 committed by GitHub
parent c398bc64d6
commit 3d8aa7c3ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 348 additions and 1042 deletions

View file

@ -11,7 +11,7 @@ async function saveSVG() {
link.click();
tip(
`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`,
`${link.download} is saved. Open "Downloads" screen (ctrl + J) to check. You can set image scale in options`,
true,
"success",
5000

View file

@ -12,7 +12,11 @@ window.ThreeD = (function () {
waterColor: "#466eab",
extendedWater: 0,
labels3d: 0,
resolution: 2
wireframe: 0,
resolution: 2,
resolutionScale: 2048,
sunColor: "#cccccc",
subdivide: 0
};
// set variables
@ -92,7 +96,11 @@ window.ThreeD = (function () {
const setScale = function (scale) {
options.scale = scale;
geometry.vertices.forEach((v, i) => (v.z = getMeshHeight(i)));
let vertices = geometry.getAttribute('position');
for(let i = 0; i < vertices.count; i++){
vertices.setZ(i,getMeshHeight(i));
}
geometry.setAttribute('position',vertices);
geometry.verticesNeedUpdate = true;
geometry.computeVertexNormals();
geometry.verticesNeedUpdate = false;
@ -100,6 +108,17 @@ window.ThreeD = (function () {
redraw();
};
const setSunColor = function(color){
options.sunColor = color;
spotLight.color = new THREE.Color(color);
render();
}
const setResolutionScale = function (scale) {
options.resolutionScale = scale;
redraw();
};
const setLightness = function (intensity) {
options.lightness = intensity;
ambientLight.intensity = intensity;
@ -148,6 +167,16 @@ window.ThreeD = (function () {
}
};
const toggle3dSubdivision = function(){
options.subdivide = !options.subdivide;
redraw();
}
const toggleWireframe = function () {
options.wireframe = !options.wireframe;
redraw();
};
const setColors = function (sky, water) {
options.skyColor = sky;
scene.background = scene.fog.color = new THREE.Color(sky);
@ -189,16 +218,20 @@ window.ThreeD = (function () {
// light
ambientLight = new THREE.AmbientLight(0xcccccc, options.lightness);
scene.add(ambientLight);
spotLight = new THREE.SpotLight(0xcccccc, 0.8, 2000, 0.8, 0, 0);
spotLight = new THREE.SpotLight(options.sunColor, 0.8, 2000, 0.8, 0, 0);
spotLight.position.set(options.sun.x, options.sun.y, options.sun.z);
spotLight.castShadow = true;
//maybe add a option for this. But changing the option will require to reinstance the spotLight.
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
scene.add(spotLight);
//scene.add(new THREE.SpotLightHelper(spotLight));
// Rendered
// Renderer
Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
Renderer.setSize(canvas.width, canvas.height);
Renderer.shadowMap.enabled = true;
// Renderer.shadowMap.type = THREE.PCFSoftShadowMap;
if (options.extendedWater) extendWater(graphWidth, graphHeight);
createMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
@ -223,7 +256,7 @@ window.ThreeD = (function () {
function textureToSprite(texture, width, height) {
const map = new THREE.TextureLoader().load(texture);
map.anisotropy = Renderer.getMaxAnisotropy();
map.anisotropy = Renderer.capabilities.getMaxAnisotropy();
const material = new THREE.SpriteMaterial({map});
const sprite = new THREE.Sprite(material);
@ -296,7 +329,9 @@ window.ThreeD = (function () {
};
const city_icon_material = new THREE.MeshPhongMaterial({color: cityOptions.iconColor});
city_icon_material.wireframe = options.wireframe;
const town_icon_material = new THREE.MeshPhongMaterial({color: townOptions.iconColor});
town_icon_material.wireframe = options.wireframe;
const city_icon_geometry = new THREE.CylinderGeometry(cityOptions.iconSize * 2, cityOptions.iconSize * 2, cityOptions.iconSize, 16, 1);
const town_icon_geometry = new THREE.CylinderGeometry(townOptions.iconSize * 2, townOptions.iconSize * 2, townOptions.iconSize, 16, 1);
const line_material = new THREE.LineBasicMaterial({color: cityOptions.iconColor});
@ -387,32 +422,81 @@ window.ThreeD = (function () {
lines = [];
}
async function createMeshTextureUrl(){
return new Promise(async (resolve, reject)=>{
const mapOptions = {
noLabels: options.labels3d,
noWater: options.extendedWater,
fullMap: true
};
const url = await getMapURL("mesh",mapOptions);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = options.resolutionScale;
canvas.height = options.resolutionScale;
const img = new Image();
img.src = url;
img.onload = function(){
ctx.drawImage(img,0,0,canvas.width,canvas.height);
canvas.toBlob((blob)=>{
const blobObj = window.URL.createObjectURL(blob)
window.setTimeout(()=>{
canvas.remove();
window.URL.revokeObjectURL(blobObj);
}, 100);
resolve(blobObj);
})
}
})
}
// create a mesh from pixel data
async function createMesh(width, height, segmentsX, segmentsY) {
const mapOptions = {
noLabels: options.labels3d,
noWater: options.extendedWater,
fullMap: true
};
const url = await getMapURL("mesh", mapOptions);
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
if (texture) texture.dispose();
texture = new THREE.TextureLoader().load(url, render);
if(!options.wireframe){
//Try loading skin texture.
texture = new THREE.TextureLoader().load(await createMeshTextureUrl(), render);
texture.needsUpdate = true;
texture.anisotropy = Renderer.capabilities.getMaxAnisotropy();
}
if (material) material.dispose();
material = new THREE.MeshLambertMaterial();
material.map = texture;
material.transparent = true;
if(options.wireframe){
material = new THREE.MeshLambertMaterial();
material.wireframe = true;
}else{
material = new THREE.MeshLambertMaterial();
material.map = texture;
material.transparent = true;
}
if (geometry) geometry.dispose();
geometry = new THREE.PlaneGeometry(width, height, segmentsX - 1, segmentsY - 1);
geometry.vertices.forEach((v, i) => (v.z = getMeshHeight(i)));
let vertices = geometry.getAttribute('position');
for(let i = 0; i < vertices.count; i++){
vertices.setZ(i,getMeshHeight(i));
}
geometry.setAttribute('position',vertices);
geometry.computeVertexNormals();
if (mesh) scene.remove(mesh);
mesh = new THREE.Mesh(geometry, material);
if(options.subdivide){
await loadLoopSubdivision();
const subdivideParams = {
split: true,
uvSmooth: false,
preserveEdges: true,
flatOnly: false,
maxTriangles: Infinity
};
const smoothGeometry = loopSubdivision.modify(geometry,1,subdivideParams);
mesh = new THREE.Mesh(smoothGeometry, material);
}else{
mesh = new THREE.Mesh(geometry, material);
}
mesh.rotation.x = -Math.PI / 2;
mesh.castShadow = true;
mesh.receiveShadow = true;
@ -449,7 +533,7 @@ window.ThreeD = (function () {
noWater: options.extendedWater,
fullMap: true
};
const url = await getMapURL("mesh", mapOptions);
const url = await createMeshTextureUrl();
window.setTimeout(() => window.URL.revokeObjectURL(url), 4000);
texture = new THREE.TextureLoader().load(url, render);
material.map = texture;
@ -579,6 +663,17 @@ window.ThreeD = (function () {
});
}
function loadLoopSubdivision(){
if (window.loopSubdivision) return Promise.resolve(true);
return new Promise(resolve => {
const script = document.createElement("script");
script.src = "libs/loopsubdivison.min.js";
document.head.append(script);
script.onload = () => resolve(true);
script.onerror = () => resolve(false);
});
}
function OrbitControls(camera, domElement) {
if (THREE.OrbitControls) return new THREE.OrbitControls(camera, domElement);
@ -596,7 +691,7 @@ window.ThreeD = (function () {
return new Promise(resolve => {
const script = document.createElement("script");
script.src = "libs/objexporter.min.js";
script.src = "libs/objexporter.min.js?v=1.89.35";
document.head.append(script);
script.onload = () => resolve(new THREE.OBJExporter());
script.onerror = () => resolve(false);
@ -609,11 +704,15 @@ window.ThreeD = (function () {
update,
stop,
options,
setSunColor,
setScale,
setResolutionScale,
setLightness,
setSun,
setRotation,
toggleLabels,
toggle3dSubdivision,
toggleWireframe,
toggleSky,
setResolution,
setColors,

View file

@ -1060,6 +1060,7 @@ function toggle3dOptions() {
document.getElementById("options3dSunX").addEventListener("change", changeSunPosition);
document.getElementById("options3dSunY").addEventListener("change", changeSunPosition);
document.getElementById("options3dSunZ").addEventListener("change", changeSunPosition);
document.getElementById("options3dMeshSkinResolution").addEventListener("change", changeResolutionScale);
document.getElementById("options3dMeshRotationRange").addEventListener("input", changeRotation);
document.getElementById("options3dMeshRotationNumber").addEventListener("change", changeRotation);
document.getElementById("options3dGlobeRotationRange").addEventListener("input", changeRotation);
@ -1069,6 +1070,10 @@ function toggle3dOptions() {
document.getElementById("options3dMeshSky").addEventListener("input", changeColors);
document.getElementById("options3dMeshWater").addEventListener("input", changeColors);
document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
// document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d);
document.getElementById("options3dSunColor").addEventListener("input", changeSunColor);
document.getElementById("options3dSubdivide").addEventListener("change",toggle3dSubdivision);
function updateValues() {
const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe";
@ -1081,6 +1086,7 @@ function toggle3dOptions() {
options3dSunY.value = ThreeD.options.sun.y;
options3dSunZ.value = ThreeD.options.sun.z;
options3dMeshRotationRange.value = options3dMeshRotationNumber.value = ThreeD.options.rotateMesh;
options3dMeshSkinResolution.value = ThreeD.options.resolutionScale;
options3dGlobeRotationRange.value = options3dGlobeRotationNumber.value = ThreeD.options.rotateGlobe;
options3dMeshLabels3d.value = ThreeD.options.labels3d;
options3dMeshSkyMode.value = ThreeD.options.extendedWater;
@ -1088,6 +1094,8 @@ function toggle3dOptions() {
options3dMeshSky.value = ThreeD.options.skyColor;
options3dMeshWater.value = ThreeD.options.waterColor;
options3dGlobeResolution.value = ThreeD.options.resolution;
options3dSunColor.value = ThreeD.options.sunColor;
options3dSubdivide.value = ThreeD.options.subdivide;
}
function changeHeightScale() {
@ -1095,11 +1103,20 @@ function toggle3dOptions() {
ThreeD.setScale(+this.value);
}
function changeResolutionScale() {
options3dMeshSkinResolution.value = this.value;
ThreeD.setResolutionScale(+this.value);
}
function changeLightness() {
options3dLightnessRange.value = options3dLightnessNumber.value = this.value;
ThreeD.setLightness(this.value / 100);
}
function changeSunColor(){
ThreeD.setSunColor(options3dSunColor.value);
}
function changeSunPosition() {
const x = +options3dSunX.value;
const y = +options3dSunY.value;
@ -1117,6 +1134,14 @@ function toggle3dOptions() {
ThreeD.toggleLabels();
}
function toggle3dSubdivision(){
ThreeD.toggle3dSubdivision();
}
// function toggleWireframe3d() {
// ThreeD.toggleWireframe();
// }
function toggleSkyMode() {
const hide = ThreeD.options.extendedWater;
options3dColorSection.style.display = hide ? "none" : "block";