Shift scene + camera closer to the center to fix precision issues

This commit is contained in:
Lukas Rieger (Blue) 2022-10-15 00:38:10 +02:00
parent f53253381c
commit 7e9f0e0bd8
No known key found for this signature in database
GPG Key ID: 2D09EC5ED2687FF2
5 changed files with 56 additions and 27 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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(){};

View File

@ -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}
}

View File

@ -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) {
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) {
if (value !== this.data.distance) {
this.data.distance = value;
this.needsUpdate = true;
}
}
}