Subdivision added. Removed toggle wireframe as an option.

Reverted to previous rendering method.
This commit is contained in:
Efruz Yıldırır 2023-07-22 20:01:55 +03:00
parent a2ba10be78
commit a591b8eebd
5 changed files with 217 additions and 180 deletions

View file

@ -5673,14 +5673,7 @@
<input id="options3dSunZ" type="number" min="-1500" max="1500" step="100" style="width: 4.7em" /> <input id="options3dSunZ" type="number" min="-1500" max="1500" step="100" style="width: 4.7em" />
</div> </div>
<div data-tip="Set Sun Color" id="options3dSunColorSection">
<span>Sun Color:</span
><input
id="options3dSunColor"
type="color"
style="width: 4.4em; height: 1em; border: 0; padding: 0; margin: 0 0.2em"
/>
</div>
<div data-tip="Toggle 3d labels" style="margin: 0.6em 0 0.3em -0.2em"> <div data-tip="Toggle 3d labels" style="margin: 0.6em 0 0.3em -0.2em">
<input id="options3dMeshLabels3d" class="checkbox" type="checkbox" /> <input id="options3dMeshLabels3d" class="checkbox" type="checkbox" />
@ -5692,9 +5685,23 @@
<label for="options3dMeshSkyMode" class="checkbox-label"><i>Show sky and extend water</i></label> <label for="options3dMeshSkyMode" class="checkbox-label"><i>Show sky and extend water</i></label>
</div> </div>
<div data-tip="Toggle wireframe mode, generally used for debugging." style="margin: 0.6em 0 0.3em -0.2em"> <div data-tip="Toggle 3d subdivision. Increases the polygon count. Opening this will take some time. WARNING: Can smooth the sharp points in progress." style="margin: 0.6em 0 0.3em -0.2em">
<input id="options3dSubdivide" class="checkbox" type="checkbox" />
<label for="options3dSubdivide" class="checkbox-label"><i>Subdivide Model.</i></label>
</div>
<!-- <div data-tip="Toggle wireframe mode, generally used for debugging." style="margin: 0.6em 0 0.3em -0.2em">
<input id="options3dMeshWireframeMode" class="checkbox" type="checkbox" /> <input id="options3dMeshWireframeMode" class="checkbox" type="checkbox" />
<label for="options3dMeshWireframeMode" class="checkbox-label"><i>Show mesh material as wireframe</i></label> <label for="options3dMeshWireframeMode" class="checkbox-label"><i>Show mesh material as wireframe</i></label>
</div> -->
<div data-tip="Set Sun Color" id="options3dSunColorSection">
<span>Sun Color:</span
><input
id="options3dSunColor"
type="color"
style="width: 4.4em; height: 1em; border: 0; padding: 0; margin: 0 0.2em"
/>
</div> </div>
<div data-tip="Set sky and water color" id="options3dColorSection" style="display: none"> <div data-tip="Set sky and water color" id="options3dColorSection" style="display: none">
@ -7913,7 +7920,7 @@
<script src="modules/ui/stylePresets.js?v=1.89.11"></script> <script src="modules/ui/stylePresets.js?v=1.89.11"></script>
<script src="modules/ui/general.js?v=1.87.03"></script> <script src="modules/ui/general.js?v=1.87.03"></script>
<script src="modules/ui/options.js?v=1.89.20"></script> <script src="modules/ui/options.js?v=1.89.35"></script>
<script src="main.js?v=1.89.32"></script> <script src="main.js?v=1.89.32"></script>
<script defer src="modules/relief-icons.js"></script> <script defer src="modules/relief-icons.js"></script>
@ -7949,14 +7956,14 @@
<script defer src="modules/ui/battle-screen.js"></script> <script defer src="modules/ui/battle-screen.js"></script>
<script defer src="modules/ui/emblems-editor.js?v=1.89.21"></script> <script defer src="modules/ui/emblems-editor.js?v=1.89.21"></script>
<script defer src="modules/ui/markers-editor.js"></script> <script defer src="modules/ui/markers-editor.js"></script>
<script defer src="modules/ui/3d.js?v=1.89.33"></script> <script defer src="modules/ui/3d.js?v=1.89.35"></script>
<script defer src="modules/ui/submap.js"></script> <script defer src="modules/ui/submap.js"></script>
<script defer src="modules/ui/hotkeys.js?v=1.88.00"></script> <script defer src="modules/ui/hotkeys.js?v=1.88.00"></script>
<script defer src="modules/coa-renderer.js?v=1.87.08"></script> <script defer src="modules/coa-renderer.js?v=1.87.08"></script>
<script defer src="libs/rgbquant.min.js"></script> <script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script> <script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="libs/three.min.js"></script> <script defer src="libs/three.min.js"></script>
<script defer src="libs/LoopSubdivision.js"></script> <script defer src="libs/loopSubdivision.js"></script>
<script defer src="modules/io/save.js?v=1.89.29"></script> <script defer src="modules/io/save.js?v=1.89.29"></script>
<script defer src="modules/io/load.js?v=1.89.30"></script> <script defer src="modules/io/load.js?v=1.89.30"></script>

View file

@ -67,8 +67,8 @@
// //
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
const loopSubdivision = {};
(()=>{
///// Constants ///// Constants
const POSITION_DECIMALS = 2; const POSITION_DECIMALS = 2;
@ -107,7 +107,6 @@ const _triangle = new THREE.Triangle();
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
/** Loop subdivision surface modifier for use with modern three.js BufferGeometry */ /** Loop subdivision surface modifier for use with modern three.js BufferGeometry */
class LoopSubdivision {
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
///// Modify ///// Modify
@ -128,8 +127,8 @@ class LoopSubdivision {
* @param {Boolean} flatOnly - If true, subdivision generates triangles, but does not modify positions * @param {Boolean} flatOnly - If true, subdivision generates triangles, but does not modify positions
* @param {Number} maxTriangles - If geometry contains more than this many triangles, subdivision will not continue * @param {Number} maxTriangles - If geometry contains more than this many triangles, subdivision will not continue
*/ */
static modify(bufferGeometry, iterations = 1, params = {}) { function modify(bufferGeometry, iterations = 1, params = {}) {
if (arguments.length > 3) console.warn(`LoopSubdivision.modify() now uses a parameter object. See readme for more info!`); if (arguments.length > 3) console.warn(`modify() now uses a parameter object. See readme for more info!`);
if (typeof params !== 'object') params = {}; if (typeof params !== 'object') params = {};
@ -146,7 +145,7 @@ class LoopSubdivision {
///// Presplit ///// Presplit
if (params.split) { if (params.split) {
const splitGeometry = LoopSubdivision.edgeSplit(modifiedGeometry) const splitGeometry = edgeSplit(modifiedGeometry)
modifiedGeometry.dispose(); modifiedGeometry.dispose();
modifiedGeometry = splitGeometry; modifiedGeometry = splitGeometry;
} }
@ -159,9 +158,9 @@ class LoopSubdivision {
// Subdivide // Subdivide
if (params.flatOnly) { if (params.flatOnly) {
subdividedGeometry = LoopSubdivision.flat(modifiedGeometry); subdividedGeometry = flat(modifiedGeometry);
} else { } else {
subdividedGeometry = LoopSubdivision.smooth(modifiedGeometry, params); subdividedGeometry = smooth(modifiedGeometry, params);
} }
// Copy and Resize Groups // Copy and Resize Groups
@ -178,7 +177,8 @@ class LoopSubdivision {
///// Return New Geometry ///// Return New Geometry
return modifiedGeometry; return modifiedGeometry;
} }
loopSubdivision.modify = modify;
console.log("Hello World");
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
///// Split Hypotenuse ///// Split Hypotenuse
//////////////////// ////////////////////
@ -188,7 +188,7 @@ class LoopSubdivision {
* Starts by splitting at longest shared edge, followed by splitting from that new center edge point to the * Starts by splitting at longest shared edge, followed by splitting from that new center edge point to the
* center of any other shared edges. * center of any other shared edges.
*/ */
static edgeSplit(geometry) { function edgeSplit(geometry) {
///// Geometries ///// Geometries
if (!verifyGeometry(geometry)) return geometry; if (!verifyGeometry(geometry)) return geometry;
@ -431,7 +431,7 @@ class LoopSubdivision {
//////////////////// ////////////////////
/** Applies one iteration of Loop (flat) subdivision (1 triangle split into 4 triangles) */ /** Applies one iteration of Loop (flat) subdivision (1 triangle split into 4 triangles) */
static flat(geometry) { function flat(geometry) {
///// Geometries ///// Geometries
if (!verifyGeometry(geometry)) return geometry; if (!verifyGeometry(geometry)) return geometry;
@ -447,7 +447,7 @@ class LoopSubdivision {
const attribute = existing.getAttribute(attributeName); const attribute = existing.getAttribute(attributeName);
if (!attribute) return; if (!attribute) return;
loop.setAttribute(attributeName, LoopSubdivision.flatAttribute(attribute, vertexCount)); loop.setAttribute(attributeName, flatAttribute(attribute, vertexCount));
}); });
///// Morph Attributes ///// Morph Attributes
@ -459,7 +459,7 @@ class LoopSubdivision {
// Process Array of Float32BufferAttributes // Process Array of Float32BufferAttributes
for (let i = 0, l = morphAttribute.length; i < l; i++) { for (let i = 0, l = morphAttribute.length; i < l; i++) {
if (morphAttribute[i].count !== vertexCount) continue; if (morphAttribute[i].count !== vertexCount) continue;
array.push(LoopSubdivision.flatAttribute(morphAttribute[i], vertexCount)); array.push(flatAttribute(morphAttribute[i], vertexCount));
} }
loop.morphAttributes[attributeName] = array; loop.morphAttributes[attributeName] = array;
} }
@ -470,7 +470,7 @@ class LoopSubdivision {
return loop; return loop;
} }
static flatAttribute(attribute, vertexCount) { function flatAttribute(attribute, vertexCount) {
const newTriangles = 4; const newTriangles = 4;
const arrayLength = (vertexCount * attribute.itemSize) * newTriangles; const arrayLength = (vertexCount * attribute.itemSize) * newTriangles;
const floatArray = new attribute.array.constructor(arrayLength); const floatArray = new attribute.array.constructor(arrayLength);
@ -504,7 +504,7 @@ class LoopSubdivision {
//////////////////// ////////////////////
/** Applies one iteration of Loop (smooth) subdivision (1 triangle split into 4 triangles) */ /** Applies one iteration of Loop (smooth) subdivision (1 triangle split into 4 triangles) */
static smooth(geometry, params = {}) { function smooth(geometry, params = {}) {
if (typeof params !== 'object') params = {}; if (typeof params !== 'object') params = {};
@ -515,14 +515,14 @@ class LoopSubdivision {
///// Geometries ///// Geometries
if (!verifyGeometry(geometry)) return geometry; if (!verifyGeometry(geometry)) return geometry;
const existing = (geometry.index !== null) ? geometry.toNonIndexed() : geometry.clone(); const existing = (geometry.index !== null) ? geometry.toNonIndexed() : geometry.clone();
const flat = LoopSubdivision.flat(existing); const flatGeometry = flat(existing);
const loop = new THREE.BufferGeometry(); const loop = new THREE.BufferGeometry();
///// Attributes ///// Attributes
const attributeList = gatherAttributes(existing); const attributeList = gatherAttributes(existing);
const vertexCount = existing.attributes.position.count; const vertexCount = existing.attributes.position.count;
const posAttribute = existing.getAttribute('position'); const posAttribute = existing.getAttribute('position');
const flatPosition = flat.getAttribute('position'); const flatPosition = flatGeometry.getAttribute('position');
const hashToIndex = {}; // Position hash mapped to index values of same position const hashToIndex = {}; // Position hash mapped to index values of same position
const existingNeighbors = {}; // Position hash mapped to existing vertex neighbors const existingNeighbors = {}; // Position hash mapped to existing vertex neighbors
const flatOpposites = {}; // Position hash mapped to new edge point opposites const flatOpposites = {}; // Position hash mapped to new edge point opposites
@ -579,7 +579,7 @@ class LoopSubdivision {
} }
///// Flat Position to Index Map ///// Flat Position to Index Map
for (let i = 0; i < flat.attributes.position.count; i++) { for (let i = 0; i < flatGeometry.attributes.position.count; i++) {
const posHash = hashFromVector(_temp.fromBufferAttribute(flatPosition, i)); const posHash = hashFromVector(_temp.fromBufferAttribute(flatPosition, i));
if (!hashToIndex[posHash]) hashToIndex[posHash] = []; if (!hashToIndex[posHash]) hashToIndex[posHash] = [];
hashToIndex[posHash].push(i); hashToIndex[posHash].push(i);
@ -588,7 +588,7 @@ class LoopSubdivision {
///// Build Geometry, Set Attributes ///// Build Geometry, Set Attributes
attributeList.forEach((attributeName) => { attributeList.forEach((attributeName) => {
const existingAttribute = existing.getAttribute(attributeName); const existingAttribute = existing.getAttribute(attributeName);
const flatAttribute = flat.getAttribute(attributeName); const flatAttribute = flatGeometry.getAttribute(attributeName);
if (existingAttribute === undefined || flatAttribute === undefined) return; if (existingAttribute === undefined || flatAttribute === undefined) return;
const floatArray = subdivideAttribute(attributeName, existingAttribute, flatAttribute); const floatArray = subdivideAttribute(attributeName, existingAttribute, flatAttribute);
@ -605,7 +605,7 @@ class LoopSubdivision {
for (let i = 0, l = morphAttribute.length; i < l; i++) { for (let i = 0, l = morphAttribute.length; i < l; i++) {
if (morphAttribute[i].count !== vertexCount) continue; if (morphAttribute[i].count !== vertexCount) continue;
const existingAttribute = morphAttribute[i]; const existingAttribute = morphAttribute[i];
const flatAttribute = LoopSubdivision.flatAttribute(morphAttribute[i], morphAttribute[i].count) const flatAttribute = flatAttribute(morphAttribute[i], morphAttribute[i].count)
const floatArray = subdivideAttribute(attributeName, existingAttribute, flatAttribute); const floatArray = subdivideAttribute(attributeName, existingAttribute, flatAttribute);
array.push(new THREE.BufferAttribute(floatArray, flatAttribute.itemSize)); array.push(new THREE.BufferAttribute(floatArray, flatAttribute.itemSize));
@ -615,7 +615,7 @@ class LoopSubdivision {
loop.morphTargetsRelative = existing.morphTargetsRelative; loop.morphTargetsRelative = existing.morphTargetsRelative;
///// Clean Up ///// Clean Up
flat.dispose(); flatGeometry.dispose();
existing.dispose(); existing.dispose();
return loop; return loop;
@ -623,12 +623,12 @@ class LoopSubdivision {
// Loop Subdivide Function // Loop Subdivide Function
function subdivideAttribute(attributeName, existingAttribute, flatAttribute) { function subdivideAttribute(attributeName, existingAttribute, flatAttribute) {
const arrayLength = (flat.attributes.position.count * flatAttribute.itemSize); const arrayLength = (flatGeometry.attributes.position.count * flatAttribute.itemSize);
const floatArray = new existingAttribute.array.constructor(arrayLength); const floatArray = new existingAttribute.array.constructor(arrayLength);
// Process Triangles // Process Triangles
let index = 0; let index = 0;
for (let i = 0; i < flat.attributes.position.count; i += 3) { for (let i = 0; i < flatGeometry.attributes.position.count; i += 3) {
// Process Triangle Points // Process Triangle Points
for (let v = 0; v < 3; v++) { for (let v = 0; v < 3; v++) {
@ -734,7 +734,7 @@ class LoopSubdivision {
} }
}
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
///// Local Functions, Hash ///// Local Functions, Hash
@ -824,3 +824,5 @@ function verifyGeometry(geometry) {
} }
return true; return true;
} }
})()

View file

@ -5,7 +5,7 @@ window.ThreeD = (function () {
scale: 50, scale: 50,
lightness: 0.7, lightness: 0.7,
shadow: 0.5, shadow: 0.5,
sun: {x: 300, y: 1500, z: 800}, sun: {x: 100, y: 600, z: 1000},
rotateMesh: 0, rotateMesh: 0,
rotateGlobe: 0.5, rotateGlobe: 0.5,
skyColor: "#9ecef5", skyColor: "#9ecef5",
@ -15,7 +15,8 @@ window.ThreeD = (function () {
wireframe: 0, wireframe: 0,
resolution: 2, resolution: 2,
resolutionScale: 3, resolutionScale: 3,
sunColor: "#ffffff" sunColor: "#cccccc",
subdivide: 0
}; };
// set variables // set variables
@ -95,7 +96,11 @@ window.ThreeD = (function () {
const setScale = function (scale) { const setScale = function (scale) {
options.scale = 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.verticesNeedUpdate = true;
geometry.computeVertexNormals(); geometry.computeVertexNormals();
geometry.verticesNeedUpdate = false; geometry.verticesNeedUpdate = false;
@ -163,6 +168,12 @@ window.ThreeD = (function () {
} }
}; };
const toggle3dSubdivision = function(){
console.log("toggle 3d subdivision");
options.subdivide = !options.subdivide;
redraw();
}
const toggleWireframe = function () { const toggleWireframe = function () {
options.wireframe = !options.wireframe; options.wireframe = !options.wireframe;
redraw(); redraw();
@ -222,7 +233,7 @@ window.ThreeD = (function () {
Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true}); Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
Renderer.setSize(canvas.width, canvas.height); Renderer.setSize(canvas.width, canvas.height);
Renderer.shadowMap.enabled = true; Renderer.shadowMap.enabled = true;
Renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Renderer.shadowMap.type = THREE.PCFSoftShadowMap;
if (options.extendedWater) extendWater(graphWidth, graphHeight); if (options.extendedWater) extendWater(graphWidth, graphHeight);
createMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY); createMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
@ -480,9 +491,8 @@ window.ThreeD = (function () {
material = new THREE.MeshLambertMaterial(); material = new THREE.MeshLambertMaterial();
material.wireframe = true; material.wireframe = true;
}else{ }else{
material = new THREE.MeshStandardMaterial(); material = new THREE.MeshLambertMaterial();
material.map = texture; material.map = texture;
material.roughness = 0.9;
material.transparent = true; material.transparent = true;
} }
@ -493,14 +503,24 @@ window.ThreeD = (function () {
for(let i = 0; i < vertices.count; i++){ for(let i = 0; i < vertices.count; i++){
vertices.setZ(i,getMeshHeight(i)); vertices.setZ(i,getMeshHeight(i));
} }
// vertices.forEach((v, i) => (v.z = getMeshHeight(i)));
geometry.setAttribute('position',vertices); geometry.setAttribute('position',vertices);
geometry.computeVertexNormals(); geometry.computeVertexNormals();
//This takes too long //This takes too long
const smoothGeometry = LoopSubdivision.modify(geometry,1,undefined);
if (mesh) scene.remove(mesh); if (mesh) scene.remove(mesh);
if(options.subdivide){
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); mesh = new THREE.Mesh(smoothGeometry, material);
}else{
mesh = new THREE.Mesh(geometry, material);
}
mesh.rotation.x = -Math.PI / 2; mesh.rotation.x = -Math.PI / 2;
mesh.castShadow = true; mesh.castShadow = true;
mesh.receiveShadow = true; mesh.receiveShadow = true;
@ -704,6 +724,7 @@ window.ThreeD = (function () {
setSun, setSun,
setRotation, setRotation,
toggleLabels, toggleLabels,
toggle3dSubdivision,
toggleWireframe, toggleWireframe,
toggleSky, toggleSky,
setResolution, setResolution,

View file

@ -1070,8 +1070,9 @@ function toggle3dOptions() {
document.getElementById("options3dMeshSky").addEventListener("input", changeColors); document.getElementById("options3dMeshSky").addEventListener("input", changeColors);
document.getElementById("options3dMeshWater").addEventListener("input", changeColors); document.getElementById("options3dMeshWater").addEventListener("input", changeColors);
document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution); document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d); // document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d);
document.getElementById("options3dSunColor").addEventListener("input", changeSunColor); document.getElementById("options3dSunColor").addEventListener("input", changeSunColor);
document.getElementById("options3dSubdivide").addEventListener("change",toggle3dSubdivision);
function updateValues() { function updateValues() {
@ -1094,6 +1095,7 @@ function toggle3dOptions() {
options3dMeshWater.value = ThreeD.options.waterColor; options3dMeshWater.value = ThreeD.options.waterColor;
options3dGlobeResolution.value = ThreeD.options.resolution; options3dGlobeResolution.value = ThreeD.options.resolution;
options3dSunColor.value = ThreeD.options.sunColor; options3dSunColor.value = ThreeD.options.sunColor;
options3dSubdivide.value = ThreeD.options.subdivide;
console.log("options3dSunColor.value =",ThreeD.options.sunColor); console.log("options3dSunColor.value =",ThreeD.options.sunColor);
} }
@ -1134,10 +1136,15 @@ function toggle3dOptions() {
ThreeD.toggleLabels(); ThreeD.toggleLabels();
} }
function toggleWireframe3d() { function toggle3dSubdivision(){
ThreeD.toggleWireframe(); console.log(options.subdivide);
ThreeD.toggle3dSubdivision();
} }
// function toggleWireframe3d() {
// ThreeD.toggleWireframe();
// }
function toggleSkyMode() { function toggleSkyMode() {
const hide = ThreeD.options.extendedWater; const hide = ThreeD.options.extendedWater;
options3dColorSection.style.display = hide ? "none" : "block"; options3dColorSection.style.display = hide ? "none" : "block";

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
// version and caching control // version and caching control
const version = "1.89.34"; // generator version, update each time const version = "1.89.35"; // generator version, update each time
{ {
document.title += " v" + version; document.title += " v" + version;