From 7e9f0e0bd80c39479087c691e61850e3b84e149a Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Sat, 15 Oct 2022 00:38:10 +0200 Subject: [PATCH] Shift scene + camera closer to the center to fix precision issues --- src/MapViewer.js | 34 ++++++++++++++++++++++++------ src/map/Map.js | 4 ++-- src/map/TileManager.js | 10 +++++---- src/map/hires/HiresVertexShader.js | 9 +------- src/util/CombinedCamera.js | 26 +++++++++++++++++------ 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/MapViewer.js b/src/MapViewer.js index 3d8670b..3f0bc5c 100644 --- a/src/MapViewer.js +++ b/src/MapViewer.js @@ -95,6 +95,7 @@ export class MapViewer { this.camera = new CombinedCamera(75, 1, 0.1, 10000, 0); this.skyboxCamera = new PerspectiveCamera(75, 1, 0.1, 10000); + this.skyboxCamera.updateProjectionMatrix(); this.controlsManager = new ControlsManager(this, this.camera); @@ -280,12 +281,11 @@ export class MapViewer { delta: delta, }); - //render + // render this.renderer.clear(); - //prepare skybox camera + // prepare skybox camera this.skyboxCamera.rotation.copy(this.camera.rotation); - this.skyboxCamera.updateProjectionMatrix(); // render skybox this.renderer.render(this.skyboxScene, this.skyboxCamera); @@ -293,8 +293,19 @@ export class MapViewer { if (this.map && this.map.isLoaded) { - //update uniforms + // shift whole scene including camera towards 0,0 to tackle shader-precision issues + const s = 10000; + const sX = Math.round(this.camera.position.x / s) * s; + const sZ = Math.round(this.camera.position.z / s) * s; + this.camera.position.x -= sX; + this.camera.position.z -= sZ; + + // update uniforms this.data.uniforms.hiresTileMap.value.pos.copy(this.map.hiresTileManager.centerTile); + this.data.uniforms.hiresTileMap.value.translate.set( + this.map.data.hires.translate.x - sX, + this.map.data.hires.translate.z - sZ + ); // prepare camera for lowres const cameraFar = this.camera.far; @@ -307,7 +318,10 @@ export class MapViewer { const highestLod = this.map.lowresTileManager.length - 1; for (let i = this.map.lowresTileManager.length - 1; i >= 0; i--) { if (i === highestLod || this.controlsManager.distance < 1000 * Math.pow(this.map.data.lowres.lodFactor, i + 1)) { - this.renderer.render(this.map.lowresTileManager[i].scene, this.camera); + let scenePos = this.map.lowresTileManager[i].scene.position; + scenePos.x = -sX; + scenePos.z = -sZ; + this.renderer.render(this.map.lowresTileManager[i].sceneParent, this.camera); this.renderer.clearDepth(); } } @@ -317,8 +331,16 @@ export class MapViewer { // render hires if (this.controlsManager.distance < 1000) { this.camera.updateProjectionMatrix(); - this.renderer.render(this.map.hiresTileManager.scene, this.camera); + let scenePos = this.map.hiresTileManager.scene.position; + scenePos.x = -sX; + scenePos.z = -sZ; + this.renderer.render(this.map.hiresTileManager.sceneParent, this.camera); } + + // shift back + this.camera.position.x += sX; + this.camera.position.z += sZ; + } // render markers diff --git a/src/map/Map.js b/src/map/Map.js index 15e5b3b..ad72d3d 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -117,12 +117,12 @@ export class Map { this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); - this.hiresTileManager = new TileManager(new Scene(), new TileLoader(`${this.data.dataUrl}tiles/0/`, this.hiresMaterial, this.data.hires, this.loadBlocker, tileCacheHash), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); + this.hiresTileManager = new TileManager(new TileLoader(`${this.data.dataUrl}tiles/0/`, this.hiresMaterial, this.data.hires, this.loadBlocker, tileCacheHash), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); this.hiresTileManager.scene.autoUpdate = false; this.lowresTileManager = []; for (let i = 0; i < this.data.lowres.lodCount; i++) { - this.lowresTileManager[i] = new TileManager(new Scene(), new LowresTileLoader(`${this.data.dataUrl}tiles/`, this.data.lowres, i + 1, lowresVertexShader, lowresFragmentShader, uniforms, async () => {}, tileCacheHash), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); + this.lowresTileManager[i] = new TileManager(new LowresTileLoader(`${this.data.dataUrl}tiles/`, this.data.lowres, i + 1, lowresVertexShader, lowresFragmentShader, uniforms, async () => {}, tileCacheHash), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); this.lowresTileManager[i].scene.autoUpdate = false; } diff --git a/src/map/TileManager.js b/src/map/TileManager.js index a379076..a52c55e 100644 --- a/src/map/TileManager.js +++ b/src/map/TileManager.js @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -import { Vector2 } from 'three'; +import { Vector2, Scene, Group } from 'three'; import { Tile } from './Tile.js'; import {alert, hashTile} from '../util/Utils.js'; import {TileMap} from "./TileMap"; @@ -33,17 +33,19 @@ export class TileManager { static tileMapHalfSize = TileManager.tileMapSize / 2; /** - * @param scene {THREE.Scene} * @param tileLoader {TileLoader | LowresTileLoader} * @param onTileLoad {function(Tile)} * @param onTileUnload {function(Tile)} * @param events {EventTarget} */ - constructor(scene, tileLoader, onTileLoad = null, onTileUnload = null, events = null) { + constructor(tileLoader, onTileLoad = null, onTileUnload = null, events = null) { Object.defineProperty( this, 'isTileManager', { value: true } ); + this.sceneParent = new Scene(); + this.scene = new Group(); + this.sceneParent.add(this.scene); + this.events = events; - this.scene = scene; this.tileLoader = tileLoader; this.onTileLoad = onTileLoad || function(){}; diff --git a/src/map/hires/HiresVertexShader.js b/src/map/hires/HiresVertexShader.js index c430693..d919f42 100644 --- a/src/map/hires/HiresVertexShader.js +++ b/src/map/hires/HiresVertexShader.js @@ -33,30 +33,23 @@ attribute float sunlight; attribute float blocklight; varying vec3 vPosition; -//varying vec3 vWorldPosition; varying vec3 vNormal; varying vec2 vUv; varying vec3 vColor; varying float vAo; varying float vSunlight; varying float vBlocklight; -//varying float vDistance; void main() { - vec4 worldPos = modelMatrix * vec4(position, 1); - vec4 viewPos = viewMatrix * worldPos; - vPosition = position; - //vWorldPosition = worldPos.xyz; vNormal = normal; vUv = uv; vColor = color; vAo = ao; vSunlight = sunlight; vBlocklight = blocklight; - //vDistance = -viewPos.z - gl_Position = projectionMatrix * viewPos; + gl_Position = projectionMatrix * (viewMatrix * modelMatrix * vec4(position, 1)); ${ShaderChunk.logdepthbuf_vertex} } diff --git a/src/util/CombinedCamera.js b/src/util/CombinedCamera.js index fb4f81f..54f0887 100644 --- a/src/util/CombinedCamera.js +++ b/src/util/CombinedCamera.js @@ -36,6 +36,8 @@ export class CombinedCamera extends PerspectiveCamera { constructor(fov, aspect, near, far, ortho) { super(fov, aspect, near, far); + this.needsUpdate = true; + this.data = { fov: this.fov, aspect: this.aspect, @@ -49,29 +51,31 @@ export class CombinedCamera extends PerspectiveCamera { // redirect parent properties Object.defineProperty(this, "fov", { get() { return this.data.fov }, - set(value) { this.data.fov = value } + set(value) { if (value !== this.data.fov) { this.data.fov = value; this.needsUpdate = true }} }); Object.defineProperty(this, "aspect", { get() { return this.data.aspect }, - set(value) { this.data.aspect = value } + set(value) { if (value !== this.data.aspect) { this.data.aspect = value; this.needsUpdate = true }} }); Object.defineProperty(this, "near", { get() { return this.data.near }, - set(value) { this.data.near = value } + set(value) { if (value !== this.data.near) { this.data.near = value; this.needsUpdate = true }} }); Object.defineProperty(this, "far", { get() { return this.data.far }, - set(value) { this.data.far = value } + set(value) { if (value !== this.data.far) { this.data.far = value; this.needsUpdate = true }} }); Object.defineProperty(this, "zoom", { get() { return this.data.zoom }, - set(value) { this.data.zoom = value } + set(value) { if (value !== this.data.zoom) { this.data.zoom = value; this.needsUpdate = true }} }); this.updateProjectionMatrix(); } updateProjectionMatrix() { + if (!this.needsUpdate) return; + if (!this.ortographicProjection) this.ortographicProjection = new Matrix4(); @@ -121,6 +125,7 @@ export class CombinedCamera extends PerspectiveCamera { this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + this.needsUpdate = false; } /** @@ -162,7 +167,10 @@ export class CombinedCamera extends PerspectiveCamera { * @param value {number} */ set ortho(value) { - this.data.ortho = value; + if (value !== this.data.ortho){ + this.data.ortho = value; + this.needsUpdate = true; + } } /** @@ -176,6 +184,10 @@ export class CombinedCamera extends PerspectiveCamera { * @param value {number} */ set distance(value) { - this.data.distance = value; + if (value !== this.data.distance) { + this.data.distance = value; + this.needsUpdate = true; + } } + } \ No newline at end of file