only render 3D canvas when there are changes to render,

add performance debug logs
(3D canvas still broken though)
This commit is contained in:
HF 2024-01-20 16:25:52 +01:00
parent d7c60a9df2
commit 4bef680735
7 changed files with 225 additions and 198 deletions

View File

@ -24,9 +24,6 @@ import {
Vector2, Vector2,
Vector3, Vector3,
} from 'three'; } from 'three';
import {
setViewCoordinates,
} from '../store/actions';
import { import {
THREE_CANVAS_HEIGHT, THREE_CANVAS_HEIGHT,
} from '../core/constants'; } from '../core/constants';
@ -56,7 +53,6 @@ const STATE = {
const CHANGE_EVENT = { type: 'change' }; const CHANGE_EVENT = { type: 'change' };
const START_EVENT = { type: 'start' }; const START_EVENT = { type: 'start' };
const END_EVENT = { type: 'end' }; const END_EVENT = { type: 'end' };
const EPS = 0.000001;
/* /*
* configuration * configuration
@ -73,10 +69,6 @@ const maxPolarAngle = Math.PI; // radians
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
const minAzimuthAngle = -Infinity; // radians const minAzimuthAngle = -Infinity; // radians
const maxAzimuthAngle = Infinity; // radians const maxAzimuthAngle = Infinity; // radians
// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
const enableDamping = false;
const dampingFactor = 0.05;
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility. // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
// Set to false to disable zooming // Set to false to disable zooming
const enableZoom = true; const enableZoom = true;
@ -103,7 +95,6 @@ class VoxelPainterControls extends EventDispatcher {
renderer; renderer;
domElement; domElement;
state; state;
//
// Set to false to disable this control // Set to false to disable this control
enabled = true; enabled = true;
// "target" sets the location of focus, where the object orbits around // "target" sets the location of focus, where the object orbits around
@ -128,7 +119,6 @@ class VoxelPainterControls extends EventDispatcher {
// //
scale = 1; scale = 1;
panOffset = new Vector3(); panOffset = new Vector3();
zoomChanged = false;
rotateStart = new Vector2(); rotateStart = new Vector2();
rotateEnd = new Vector2(); rotateEnd = new Vector2();
rotateDelta = new Vector2(); rotateDelta = new Vector2();
@ -146,23 +136,22 @@ class VoxelPainterControls extends EventDispatcher {
updateTime = Date.now(); updateTime = Date.now();
prevTime = Date.now(); prevTime = Date.now();
offset = new Vector3(); offset = new Vector3();
lastPosition = new Vector3();
lastQuaternion = new Quaternion();
direction = new Vector3(); direction = new Vector3();
velocity = new Vector3(); velocity = new Vector3();
vec = new Vector3(); vec = new Vector3();
constructor(renderer, camera, domElement, store) { constructor(renderer, camera, target, domElement, store) {
super(); super();
this.renderer = renderer; this.renderer = renderer;
this.camera = camera; this.camera = camera;
this.domElement = domElement; this.domElement = domElement;
this.store = store; this.store = store;
// //
this.target = new Vector3(); this.target = target;
this.target0 = this.target.clone(); //
this.position0 = this.camera.position.clone(); this.target0 = target.clone();
this.zoom0 = this.camera.zoom; this.position0 = camera.position.clone();
this.zoom0 = camera.zoom;
this.state = STATE.NONE; this.state = STATE.NONE;
this.onContextMenu = this.onContextMenu.bind(this); this.onContextMenu = this.onContextMenu.bind(this);
@ -336,7 +325,7 @@ class VoxelPainterControls extends EventDispatcher {
} else if (event.deltaY > 0) { } else if (event.deltaY > 0) {
this.dollyIn(this.getZoomScale()); this.dollyIn(this.getZoomScale());
} }
this.update(); this.forceNextUpdate = true;
} }
handleTouchStartRotate(event) { handleTouchStartRotate(event) {
@ -468,30 +457,24 @@ class VoxelPainterControls extends EventDispatcher {
case 87: // w case 87: // w
this.moveForward = true; this.moveForward = true;
break; break;
case 37: // left case 37: // left
case 65: // a case 65: // a
this.moveLeft = true; this.moveLeft = true;
break; break;
case 40: // down case 40: // down
case 83: // s case 83: // s
this.moveBackward = true; this.moveBackward = true;
break; break;
case 39: // right case 39: // right
case 68: // d case 68: // d
this.moveRight = true; this.moveRight = true;
break; break;
case 69: // E case 69: // E
this.moveUp = true; this.moveUp = true;
break; break;
case 67: // C case 67: // C
this.moveDown = true; this.moveDown = true;
break; break;
default: default:
break; break;
} }
@ -513,30 +496,24 @@ class VoxelPainterControls extends EventDispatcher {
case 87: // w case 87: // w
this.moveForward = false; this.moveForward = false;
break; break;
case 37: // left case 37: // left
case 65: // a case 65: // a
this.moveLeft = false; this.moveLeft = false;
break; break;
case 40: // down case 40: // down
case 83: // s case 83: // s
this.moveBackward = false; this.moveBackward = false;
break; break;
case 39: // right case 39: // right
case 68: // d case 68: // d
this.moveRight = false; this.moveRight = false;
break; break;
case 69: // E case 69: // E
this.moveUp = false; this.moveUp = false;
break; break;
case 67: // C case 67: // C
this.moveDown = false; this.moveDown = false;
break; break;
default: default:
break; break;
} }
@ -756,15 +733,12 @@ class VoxelPainterControls extends EventDispatcher {
case 0: case 0:
mouseAction = MOUSE_BUTTONS.LEFT; mouseAction = MOUSE_BUTTONS.LEFT;
break; break;
case 1: case 1:
mouseAction = MOUSE_BUTTONS.MIDDLE; mouseAction = MOUSE_BUTTONS.MIDDLE;
break; break;
case 2: case 2:
mouseAction = MOUSE_BUTTONS.RIGHT; mouseAction = MOUSE_BUTTONS.RIGHT;
break; break;
default: default:
mouseAction = -1; mouseAction = -1;
} }
@ -774,7 +748,6 @@ class VoxelPainterControls extends EventDispatcher {
this.handleMouseDownDolly(event); this.handleMouseDownDolly(event);
this.state = STATE.DOLLY; this.state = STATE.DOLLY;
break; break;
case MOUSE.ROTATE: case MOUSE.ROTATE:
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
this.handleMouseDownPan(event); this.handleMouseDownPan(event);
@ -784,7 +757,6 @@ class VoxelPainterControls extends EventDispatcher {
this.state = STATE.ROTATE; this.state = STATE.ROTATE;
} }
break; break;
case MOUSE.PAN: case MOUSE.PAN:
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
this.handleMouseDownRotate(event); this.handleMouseDownRotate(event);
@ -794,7 +766,6 @@ class VoxelPainterControls extends EventDispatcher {
this.state = STATE.PAN; this.state = STATE.PAN;
} }
break; break;
default: default:
this.state = STATE.NONE; this.state = STATE.NONE;
} }
@ -833,14 +804,26 @@ class VoxelPainterControls extends EventDispatcher {
this.state = STATE.NONE; this.state = STATE.NONE;
} }
setView(view) {
if (view.length !== 3) {
return;
}
this.target.set(...view);
}
update() { update() {
const {
moveRight,
moveLeft,
moveUp,
moveDown,
moveForward,
moveBackward,
} = this;
if (!(this.state !== STATE.NONE
|| this.forceNextUpdate
|| moveRight || moveLeft
|| moveUp || moveDown
|| moveForward || moveBackward
)) {
return false;
}
this.forceNextUpdate = false;
const { const {
camera, camera,
target, target,
@ -863,15 +846,6 @@ class VoxelPainterControls extends EventDispatcher {
velocity.set(0, 0, 0); velocity.set(0, 0, 0);
} }
const {
moveRight,
moveLeft,
moveUp,
moveDown,
moveForward,
moveBackward,
} = this;
direction.x = Number(moveRight) - Number(moveLeft); direction.x = Number(moveRight) - Number(moveLeft);
direction.y = Number(moveUp) - Number(moveDown); direction.y = Number(moveUp) - Number(moveDown);
direction.z = Number(moveForward) - Number(moveBackward); direction.z = Number(moveForward) - Number(moveBackward);
@ -898,9 +872,7 @@ class VoxelPainterControls extends EventDispatcher {
this.prevTime = time; this.prevTime = time;
const { position } = camera; offset.copy(camera.position).sub(this.target);
offset.copy(position).sub(this.target);
// rotate offset to "y-axis-is-up" space // rotate offset to "y-axis-is-up" space
offset.applyQuaternion(this.quat); offset.applyQuaternion(this.quat);
@ -908,13 +880,8 @@ class VoxelPainterControls extends EventDispatcher {
// angle from z-axis around y-axis // angle from z-axis around y-axis
spherical.setFromVector3(offset); spherical.setFromVector3(offset);
if (enableDamping) { spherical.theta += sphericalDelta.theta;
spherical.theta += sphericalDelta.theta * dampingFactor; spherical.phi += sphericalDelta.phi;
spherical.phi += sphericalDelta.phi * dampingFactor;
} else {
spherical.theta += sphericalDelta.theta;
spherical.phi += sphericalDelta.phi;
}
// restrict theta to be between desired limits // restrict theta to be between desired limits
spherical.theta = Math.max( spherical.theta = Math.max(
@ -941,11 +908,7 @@ class VoxelPainterControls extends EventDispatcher {
if (panOffset.length() > 1000) { if (panOffset.length() > 1000) {
panOffset.set(0, 0, 0); panOffset.set(0, 0, 0);
} }
if (enableDamping) { target.add(panOffset);
target.addScaledVector(panOffset, dampingFactor);
} else {
target.add(panOffset);
}
/* /*
if (scope.target.y < 10.0) { if (scope.target.y < 10.0) {
scope.target.y = 10.0; scope.target.y = 10.0;
@ -969,58 +932,15 @@ class VoxelPainterControls extends EventDispatcher {
// rotate offset back to "camera-up-vector-is-up" space // rotate offset back to "camera-up-vector-is-up" space
offset.applyQuaternion(this.quatInverse); offset.applyQuaternion(this.quatInverse);
position.copy(target).add(offset); this.camera.position.copy(target).add(offset);
camera.lookAt(target); camera.lookAt(target);
if (enableDamping) { sphericalDelta.set(0, 0, 0);
sphericalDelta.theta *= (1 - dampingFactor); panOffset.set(0, 0, 0);
sphericalDelta.phi *= (1 - dampingFactor);
panOffset.multiplyScalar(1 - dampingFactor);
if (panOffset.length() < 0.2 && panOffset.length() !== 0.0) {
panOffset.set(0, 0, 0);
this.store.dispatch(setViewCoordinates(target.toArray()));
this.renderer.storeViewInState();
} else if (panOffset.length() !== 0.0) {
if (time > this.updateTime + 500) {
this.updateTime = time;
this.store.dispatch(setViewCoordinates(target.toArray()));
this.renderer.storeViewInState();
}
}
/*
if (Math.abs(sphericalDelta.theta) < rotationFinishThreshold
&& sphericalDelta.theta != 0.0
&& Math.abs(sphericalDelta.phi) < rotationFinishThreshold
&& sphericalDelta.phi != 0.0) {
sphericalDelta.set(0, 0, 0);
console.log(`rotation finished`);
}
*/
} else {
sphericalDelta.set(0, 0, 0);
panOffset.set(0, 0, 0);
}
this.scale = 1; this.scale = 1;
// update condition is: this.dispatchEvent(CHANGE_EVENT);
// min(camera displacement, camera rotation in radians)^2 > EPS return true;
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
if (this.zoomChanged
|| this.lastPosition.distanceToSquared(camera.position) > EPS
|| 8 * (1 - this.lastQuaternion.dot(camera.quaternion)) > EPS
) {
this.dispatchEvent(CHANGE_EVENT);
this.lastPosition.copy(camera.position);
this.lastQuaternion.copy(camera.quaternion);
this.zoomChanged = false;
return true;
}
return false;
} }
} }

View File

@ -1,4 +1,19 @@
import * as THREE from 'three'; import {
MeshPhongMaterial,
TextureLoader,
Color,
Scene,
PerspectiveCamera,
WebGLRenderer,
AmbientLight,
DirectionalLight,
Mesh,
SphereGeometry,
MeshBasicMaterial,
BackSide,
Raycaster,
Vector2,
} from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import TrackballControls from 'three-trackballcontrols'; import TrackballControls from 'three-trackballcontrols';
@ -50,27 +65,27 @@ document.addEventListener('DOMContentLoaded', () => {
const [canvasIdent, canvasId, canvasSize, x, y] = parseHashCoords(); const [canvasIdent, canvasId, canvasSize, x, y] = parseHashCoords();
const canvasTexture = new THREE.MeshPhongMaterial({ const canvasTexture = new MeshPhongMaterial({
map: new THREE.TextureLoader().load(`./tiles/${canvasId}/texture.webp`), map: new TextureLoader().load(`./tiles/${canvasId}/texture.webp`),
bumpMap: new THREE.TextureLoader().load(`./assets3d/normal${canvasId}.jpg`), bumpMap: new TextureLoader().load(`./assets3d/normal${canvasId}.jpg`),
bumpScale: 0.02, bumpScale: 0.02,
specularMap: new THREE.TextureLoader() specularMap: new TextureLoader()
.load(`./assets3d/specular${canvasId}.jpg`), .load(`./assets3d/specular${canvasId}.jpg`),
specular: new THREE.Color('grey'), specular: new Color('grey'),
}); });
let width = window.innerWidth; let width = window.innerWidth;
let height = window.innerHeight; let height = window.innerHeight;
const scene = new THREE.Scene(); const scene = new Scene();
const camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000); const camera = new PerspectiveCamera(45, width / height, 0.01, 1000);
camera.position.z = 4.0; camera.position.z = 4.0;
const renderer = new THREE.WebGLRenderer(); const renderer = new WebGLRenderer();
renderer.setSize(width, height); renderer.setSize(width, height);
scene.add(new THREE.AmbientLight(0x333333)); scene.add(new AmbientLight(0x333333));
let controls = null; let controls = null;
let object = null; let object = null;
@ -82,7 +97,7 @@ document.addEventListener('DOMContentLoaded', () => {
renderer.render(scene, camera); renderer.render(scene, camera);
} }
const light = new THREE.DirectionalLight(0xffffff, 0.7); const light = new DirectionalLight(0xffffff, 0.7);
light.position.set(10, 6, 10); light.position.set(10, 6, 10);
scene.add(light); scene.add(light);
@ -129,11 +144,11 @@ document.addEventListener('DOMContentLoaded', () => {
webglEl.appendChild(renderer.domElement); webglEl.appendChild(renderer.domElement);
const stars = new THREE.Mesh( const stars = new Mesh(
new THREE.SphereGeometry(90, 64, 64), new SphereGeometry(90, 64, 64),
new THREE.MeshBasicMaterial({ new MeshBasicMaterial({
map: new THREE.TextureLoader().load('./assets3d/starfield.png'), map: new TextureLoader().load('./assets3d/starfield.png'),
side: THREE.BackSide, side: BackSide,
}), }),
); );
scene.add(stars); scene.add(stars);
@ -153,8 +168,8 @@ document.addEventListener('DOMContentLoaded', () => {
/* /*
* update coords * update coords
*/ */
const raycaster = new THREE.Raycaster(); const raycaster = new Raycaster();
const mouse = new THREE.Vector2(); const mouse = new Vector2();
const coorbox = document.getElementById('coorbox'); const coorbox = document.getElementById('coorbox');
function onDocumentMouseMove(event) { function onDocumentMouseMove(event) {
if (!object) { if (!object) {

View File

@ -6,7 +6,12 @@
/* We have to look for performance here not for good looking code */ /* We have to look for performance here not for good looking code */
/* eslint-disable prefer-destructuring */ /* eslint-disable prefer-destructuring */
import * as THREE from 'three'; import {
MeshLambertMaterial,
Mesh,
BufferGeometry,
BufferAttribute,
} from 'three';
import Chunk from './Chunk'; import Chunk from './Chunk';
import { import {
@ -69,7 +74,7 @@ const faceCorners = [
], ],
]; ];
const material = new THREE.MeshLambertMaterial({ const material = new MeshLambertMaterial({
vertexColors: true, vertexColors: true,
}); });
@ -79,7 +84,7 @@ class Chunk3D extends Chunk {
ready = false; ready = false;
palette; // Object palette; // Object
buffer; // Uint8Array buffer; // Uint8Array
mesh = null; // THREE.Mesh mesh = null; // Mesh
faceCnt; // number faceCnt; // number
lastPixel; // number lastPixel; // number
heightMap; // Array heightMap; // Array
@ -344,36 +349,36 @@ class Chunk3D extends Chunk {
const geometry = (this.mesh) const geometry = (this.mesh)
? this.mesh.geometry ? this.mesh.geometry
: new THREE.BufferGeometry(); : new BufferGeometry();
geometry.setAttribute( geometry.setAttribute(
'position', 'position',
new THREE.BufferAttribute( new BufferAttribute(
positions, positions,
3, 3,
), ),
); );
geometry.setAttribute( geometry.setAttribute(
'normal', 'normal',
new THREE.BufferAttribute( new BufferAttribute(
normals, normals,
3, 3,
), ),
); );
geometry.setAttribute( geometry.setAttribute(
'color', 'color',
new THREE.BufferAttribute( new BufferAttribute(
colors, colors,
3, 3,
true, true,
), ),
); );
geometry.setIndex(new THREE.BufferAttribute(indices, 1)); geometry.setIndex(new BufferAttribute(indices, 1));
geometry.computeBoundingSphere(); geometry.computeBoundingSphere();
geometry.setDrawRange(0, this.faceCnt * 6); geometry.setDrawRange(0, this.faceCnt * 6);
if (!this.mesh) { if (!this.mesh) {
this.mesh = new THREE.Mesh(geometry, material); this.mesh = new Mesh(geometry, material);
this.mesh.name = this.key; this.mesh.name = this.key;
} }

View File

@ -7,20 +7,26 @@
/* eslint-disable max-len */ /* eslint-disable max-len */
import * as THREE from 'three'; import {
Mesh,
Color,
PlaneBufferGeometry,
ShaderMaterial,
DoubleSide,
} from 'three';
export default class InfiniteGridHelper extends THREE.Mesh { export default class InfiniteGridHelper extends Mesh {
constructor(size1, size2, color, distance, axes = 'xzy') { constructor(size1, size2, color, distance, axes = 'xzy') {
color = color || new THREE.Color('white'); color = color || new Color('white');
size1 = size1 || 10; size1 = size1 || 10;
size2 = size2 || 100; size2 = size2 || 100;
distance = distance || 8000; distance = distance || 8000;
const planeAxes = axes.substring(0, 2); const planeAxes = axes.substring(0, 2);
const geometry = new THREE.PlaneBufferGeometry(2, 2, 1, 1); const geometry = new PlaneBufferGeometry(2, 2, 1, 1);
const material = new THREE.ShaderMaterial({ const material = new ShaderMaterial({
side: THREE.DoubleSide, side: DoubleSide,
uniforms: { uniforms: {
uSize1: { value: size1 }, uSize1: { value: size1 },

View File

@ -19,8 +19,14 @@ class Renderer {
chunkLoader = null; chunkLoader = null;
// needs to be known for lazy loading THREE // needs to be known for lazy loading THREE
is3D = null; is3D = null;
// force renderer to rebuild whole view or
// to "subrender" known view next tick
forceNextRender = true;
forceNextSubrender = true;
// current position (subclass decies what it means), // current position (subclass decies what it means),
// will be changed by controls // will be changed by controls
// TODO might be better as private and with a getter but no setter to avoid
// misconseption of it being writeable. Might have performance impact.
view = [0, 0, 0]; view = [0, 0, 0];
// //
#storeViewTimeout = null; #storeViewTimeout = null;

View File

@ -3,7 +3,22 @@
* *
*/ */
import * as THREE from 'three'; import {
Vector2,
Vector3,
PerspectiveCamera,
Scene,
AmbientLight,
DirectionalLight,
FogExp2,
BoxBufferGeometry,
MeshBasicMaterial,
Mesh,
Raycaster,
PlaneBufferGeometry,
MeshLambertMaterial,
WebGLRenderer,
} from 'three';
import Sky from './Sky'; import Sky from './Sky';
import InfiniteGridHelper from './InfiniteGridHelper'; import InfiniteGridHelper from './InfiniteGridHelper';
@ -28,6 +43,8 @@ const renderDistance = 150;
class Renderer3D extends Renderer { class Renderer3D extends Renderer {
scene; scene;
camera; camera;
// position camera is looking at
target = new Vector3();
rollOverMesh; rollOverMesh;
objects; objects;
loadedChunks; loadedChunks;
@ -43,8 +60,6 @@ class Renderer3D extends Renderer {
pressTime; pressTime;
pressCdTime; pressCdTime;
multitap; multitap;
//--
forceNextRender = false;
constructor(store) { constructor(store) {
super(store); super(store);
@ -53,7 +68,7 @@ class Renderer3D extends Renderer {
this.objects = []; this.objects = [];
// camera // camera
const camera = new THREE.PerspectiveCamera( const camera = new PerspectiveCamera(
45, 45,
window.innerWidth / window.innerHeight, window.innerWidth / window.innerHeight,
1, 1,
@ -64,19 +79,19 @@ class Renderer3D extends Renderer {
this.camera = camera; this.camera = camera;
// scene // scene
const scene = new THREE.Scene(); const scene = new Scene();
// scene.background = new THREE.Color(0xf0f0f0); // scene.background = new Color(0xf0f0f0);
this.scene = scene; this.scene = scene;
// lights // lights
const ambientLight = new THREE.AmbientLight(0x222222); const ambientLight = new AmbientLight(0x222222);
scene.add(ambientLight); scene.add(ambientLight);
// const directionalLight = new THREE.DirectionalLight(0xffffff); // const directionalLight = new DirectionalLight(0xffffff);
// directionalLight.position.set(1, 1.2, 0.8).normalize(); // directionalLight.position.set(1, 1.2, 0.8).normalize();
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); const directionalLight = new DirectionalLight(0xffffff, 1);
directionalLight.position.set(80, 80, 75); directionalLight.position.set(80, 80, 75);
const contourLight = new THREE.DirectionalLight(0xffffff, 0.4); const contourLight = new DirectionalLight(0xffffff, 0.4);
contourLight.position.set(-80, 80, -75); contourLight.position.set(-80, 80, -75);
scene.add(directionalLight); scene.add(directionalLight);
scene.add(contourLight); scene.add(contourLight);
@ -85,7 +100,7 @@ class Renderer3D extends Renderer {
sky.scale.setScalar(450000); sky.scale.setScalar(450000);
scene.add(sky); scene.add(sky);
scene.fog = new THREE.FogExp2(0xffffff, 0.003); scene.fog = new FogExp2(0xffffff, 0.003);
const effectController = { const effectController = {
turbidity: 10, turbidity: 10,
@ -104,31 +119,31 @@ class Renderer3D extends Renderer {
uniforms.sunPosition.value.set(400000, 400000, 400000); uniforms.sunPosition.value.set(400000, 400000, 400000);
// hover helper // hover helper
const rollOverGeo = new THREE.BoxBufferGeometry(1, 1, 1); const rollOverGeo = new BoxBufferGeometry(1, 1, 1);
const rollOverMaterial = new THREE.MeshBasicMaterial({ const rollOverMaterial = new MeshBasicMaterial({
color: 0xff0000, color: 0xff0000,
opacity: 0.5, opacity: 0.5,
transparent: true, transparent: true,
}); });
this.rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial); this.rollOverMesh = new Mesh(rollOverGeo, rollOverMaterial);
scene.add(this.rollOverMesh); scene.add(this.rollOverMesh);
// grid // grid
// const gridHelper = new THREE.GridHelper(100, 10, 0x555555, 0x555555); // const gridHelper = new GridHelper(100, 10, 0x555555, 0x555555);
const gridHelper = new InfiniteGridHelper(1, 10); const gridHelper = new InfiniteGridHelper(1, 10);
scene.add(gridHelper); scene.add(gridHelper);
// //
this.raycaster = new THREE.Raycaster(); this.raycaster = new Raycaster();
this.mouse = new THREE.Vector2(); this.mouse = new Vector2();
this.multitap = 0; this.multitap = 0;
// Plane Floor // Plane Floor
const geometry = new THREE.PlaneBufferGeometry(1024, 1024); const geometry = new PlaneBufferGeometry(1024, 1024);
geometry.rotateX(-Math.PI / 2); geometry.rotateX(-Math.PI / 2);
const plane = new THREE.Mesh( const plane = new Mesh(
geometry, geometry,
new THREE.MeshLambertMaterial({ color: 0xcae3ff }), new MeshLambertMaterial({ color: 0xcae3ff }),
); );
scene.add(plane); scene.add(plane);
this.plane = plane; this.plane = plane;
@ -136,20 +151,20 @@ class Renderer3D extends Renderer {
this.plane.position.y = -0.1; this.plane.position.y = -0.1;
// Out of bounds plane // Out of bounds plane
const oobGeometry = new THREE.PlaneBufferGeometry( const oobGeometry = new PlaneBufferGeometry(
THREE_TILE_SIZE, THREE_TILE_SIZE,
THREE_TILE_SIZE, THREE_TILE_SIZE,
); );
oobGeometry.rotateX(-Math.PI / 2); oobGeometry.rotateX(-Math.PI / 2);
oobGeometry.translate(THREE_TILE_SIZE / 2, 0.2, THREE_TILE_SIZE / 2); oobGeometry.translate(THREE_TILE_SIZE / 2, 0.2, THREE_TILE_SIZE / 2);
const oobMaterial = new THREE.MeshLambertMaterial({ const oobMaterial = new MeshLambertMaterial({
color: '#C4C4C4', color: '#C4C4C4',
}); });
this.oobGeometry = oobGeometry; this.oobGeometry = oobGeometry;
this.oobMaterial = oobMaterial; this.oobMaterial = oobMaterial;
// renderer // renderer
const threeRenderer = new THREE.WebGLRenderer({ const threeRenderer = new WebGLRenderer({
preserveDrawingBuffer: true, preserveDrawingBuffer: true,
}); });
threeRenderer.setPixelRatio(window.devicePixelRatio); threeRenderer.setPixelRatio(window.devicePixelRatio);
@ -163,11 +178,11 @@ class Renderer3D extends Renderer {
const controls = new VoxelPainterControls( const controls = new VoxelPainterControls(
this, this,
camera, camera,
this.target,
domElement, domElement,
store, store,
); );
controls.enableDamping = true; // TODO doesn't work like this anymore
controls.dampingFactor = 0.10;
controls.maxPolarAngle = Math.PI / 2; controls.maxPolarAngle = Math.PI / 2;
controls.minDistance = 10.00; controls.minDistance = 10.00;
controls.maxDistance = 100.00; controls.maxDistance = 100.00;
@ -201,6 +216,14 @@ class Renderer3D extends Renderer {
this.updateCanvasData(state); this.updateCanvasData(state);
} }
get view() {
return this.target.toArray();
}
set view(view) {
this.target.set(...view);
}
destructor() { destructor() {
window.removeEventListener('resize', this.onWindowResize, false); window.removeEventListener('resize', this.onWindowResize, false);
this.threeRenderer.dispose(); this.threeRenderer.dispose();
@ -211,7 +234,11 @@ class Renderer3D extends Renderer {
super.destructor(); super.destructor();
} }
updateView() { updateView(view) {
if (view.length !== 3) {
return;
}
this.view = view;
this.forceNextRender = true; this.forceNextRender = true;
} }
@ -251,15 +278,10 @@ class Renderer3D extends Renderer {
); );
} }
} }
this.controls.setView(view); this.updateView(view);
this.forceNextRender = true; this.forceNextRender = true;
} }
// eslint-disable-next-line class-methods-use-this
updateScale() {
return null;
}
renderPixel( renderPixel(
i, i,
j, j,
@ -319,7 +341,7 @@ class Renderer3D extends Renderer {
let chunk = null; let chunk = null;
if (xc < 0 || zc < 0 || xc >= chunkMaxXY || zc >= chunkMaxXY) { if (xc < 0 || zc < 0 || xc >= chunkMaxXY || zc >= chunkMaxXY) {
// if out of bounds // if out of bounds
chunk = new THREE.Mesh(this.oobGeometry, this.oobMaterial); chunk = new Mesh(this.oobGeometry, this.oobMaterial);
} else { } else {
chunk = chunkLoader.getChunk(xc, zc, true); chunk = chunkLoader.getChunk(xc, zc, true);
} }
@ -353,12 +375,44 @@ class Renderer3D extends Renderer {
if (!this.threeRenderer) { if (!this.threeRenderer) {
return; return;
} }
super.render(); const controlUpdate = super.render();
if (this.forceNextRender) { if (this.forceNextRender) {
this.reloadChunks(); this.reloadChunks();
this.forceNextRender = false;
} }
this.threeRenderer.render(this.scene, this.camera); if (this.forceNextRender || this.forceNextSubRender || controlUpdate) {
if (this.forceNextRender) {
if (this.lol !== 'force') {
console.log(this.lol, this.lola);
this.lol = 'force';
this.lola = 0;
}
this.lola += 1;
} else if (this.forceNextSubRender) {
if (this.lol !== 'sub') {
console.log(this.lol, this.lola);
this.lol = 'sub';
this.lola = 0;
}
this.lola += 1;
} else if (controlUpdate) {
if (this.lol !== 'update') {
console.log(this.lol, this.lola);
this.lol = 'update';
this.lola = 0;
}
this.lola += 1;
}
this.threeRenderer.render(this.scene, this.camera);
this.forceNextRender = false;
this.forceNextSubRender = false;
} else {
if (this.lol !== 'skip') {
console.log(this.lol, this.lola);
this.lol = 'skip';
this.lola = 0;
}
this.lola += 1;
}
} }
onWindowResize() { onWindowResize() {
@ -385,15 +439,17 @@ class Renderer3D extends Renderer {
rollOverMesh, rollOverMesh,
store, store,
} = this; } = this;
const state = store.getState();
const { const {
fetchingPixel, fetchingPixel,
} = store.getState().fetching; } = state.fetching;
mouse.set( mouse.set(
(clientX / innerWidth) * 2 - 1, (clientX / innerWidth) * 2 - 1,
-(clientY / innerHeight) * 2 + 1, -(clientY / innerHeight) * 2 + 1,
); );
console.log('move mouse');
raycaster.setFromCamera(mouse, camera); raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(objects); const intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) { if (intersects.length > 0) {
@ -403,13 +459,25 @@ class Renderer3D extends Renderer {
.floor() .floor()
.addScalar(0.5); .addScalar(0.5);
if (fetchingPixel if (fetchingPixel
|| target.clone().sub(camera.position).length() > 120) { || target.clone().sub(camera.position).length() > 120
rollOverMesh.position.y = -10; ) {
if (rollOverMesh.position.y !== -10) {
// unsetHover ?
rollOverMesh.position.y = -10;
this.forceNextSubRender = true;
}
} else { } else {
const { hover: prevHover } = state.canvas;
rollOverMesh.position.copy(target); rollOverMesh.position.copy(target);
const hover = target const hover = target.toArray().map((u) => Math.floor(u));
.toArray().map((u) => Math.floor(u)); if (!prevHover
this.store.dispatch(setHover(hover)); || prevHover[0] !== hover[0]
|| prevHover[1] !== hover[1]
|| prevHover[2] !== hover[2]
) {
this.store.dispatch(setHover(hover));
this.forceNextSubRender = true;
}
} }
} }
} }

View File

@ -17,22 +17,29 @@
/* eslint-disable max-len */ /* eslint-disable max-len */
import * as THREE from 'three'; import {
Vector3,
Mesh,
ShaderMaterial,
BackSide,
BoxGeometry,
UniformsUtils,
} from 'three';
export default class Sky extends THREE.Mesh { export default class Sky extends Mesh {
static isSky = true; static isSky = true;
constructor() { constructor() {
const shader = Sky.SkyShader; const shader = Sky.SkyShader;
const material = new THREE.ShaderMaterial({ const material = new ShaderMaterial({
name: 'SkyShader', name: 'SkyShader',
fragmentShader: shader.fragmentShader, fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader, vertexShader: shader.vertexShader,
uniforms: THREE.UniformsUtils.clone(shader.uniforms), uniforms: UniformsUtils.clone(shader.uniforms),
side: THREE.BackSide, side: BackSide,
depthWrite: false, depthWrite: false,
}); });
super(new THREE.BoxGeometry(1, 1, 1), material); super(new BoxGeometry(1, 1, 1), material);
} }
} }
@ -51,10 +58,10 @@ Sky.SkyShader = {
value: 0.8, value: 0.8,
}, },
sunPosition: { sunPosition: {
value: new THREE.Vector3(), value: new Vector3(),
}, },
up: { up: {
value: new THREE.Vector3(0, 1, 0), value: new Vector3(0, 1, 0),
}, },
}, },
vertexShader: vertexShader: