Stress-testing the physics engine
This commit is contained in:
parent
6d20041842
commit
ca7b1d1956
|
|
@ -14,6 +14,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/three": "^0.165.0",
|
"@types/three": "^0.165.0",
|
||||||
|
"stats.js": "^0.17.0",
|
||||||
"three": "^0.165.0",
|
"three": "^0.165.0",
|
||||||
"three-mesh-bvh": "^0.7.5"
|
"three-mesh-bvh": "^0.7.5"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,30 +14,52 @@ export default class Asset implements AABB
|
||||||
mat: Three.Matrix4;
|
mat: Three.Matrix4;
|
||||||
layer: number;
|
layer: number;
|
||||||
|
|
||||||
selected: boolean = false;
|
#selected = false;
|
||||||
|
#dirty = false;
|
||||||
|
|
||||||
static instance = new Three.InstancedMesh(CONST.QUAD, new Three.MeshBasicMaterial({ color: new Three.Color( 0xffffff ) }), 2**14);
|
//@ts-ignore
|
||||||
|
#aabb: AABB;
|
||||||
|
|
||||||
|
static instance = new Three.InstancedMesh(CONST.QUAD, new Three.MeshBasicMaterial({ color: new Three.Color( 0xffffff ) }), 1000000);
|
||||||
|
|
||||||
constructor(mat?: Three.Matrix4, layer?: number)
|
constructor(mat?: Three.Matrix4, layer?: number)
|
||||||
{
|
{
|
||||||
this.mat = mat ?? new Three.Matrix4();
|
this.mat = mat ?? new Three.Matrix4();
|
||||||
|
this.#updateAABB();
|
||||||
this.layer = layer ?? 0;
|
this.layer = layer ?? 0;
|
||||||
}
|
}
|
||||||
get x1()
|
#updateAABB() {
|
||||||
{
|
const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 };
|
||||||
return this.mat.elements[0] * (-0.5) + this.mat.elements[4] * (-0.5) + this.mat.elements[12] * (1 / ( this.mat.elements[ 3 ] * -0.5 + + this.mat.elements[ 15 ] ));
|
|
||||||
|
const e = this.mat.elements;
|
||||||
|
|
||||||
|
const x1 = aabb.x1 * e[0] + aabb.y1 * e[4] + e[12];
|
||||||
|
const x2 = aabb.x2 * e[0] + aabb.y2 * e[4] + e[12];
|
||||||
|
const y1 = aabb.x1 * e[1] + aabb.y1 * e[5] + e[13];
|
||||||
|
const y2 = aabb.x2 * e[1] + aabb.y2 * e[5] + e[13];
|
||||||
|
const x3 = aabb.x2 * e[0] + aabb.y1 * e[4] + e[12];
|
||||||
|
const x4 = aabb.x1 * e[0] + aabb.y2 * e[4] + e[12];
|
||||||
|
const y3 = aabb.x2 * e[1] + aabb.y1 * e[5] + e[13];
|
||||||
|
const y4 = aabb.x1 * e[1] + aabb.y2 * e[5] + e[13];
|
||||||
|
|
||||||
|
this.#aabb = {
|
||||||
|
x1: Math.min(x1, x2, x3, x4),
|
||||||
|
x2: Math.max(x1, x2, x3, x4),
|
||||||
|
y1: Math.min(y1, y2, y3, y4),
|
||||||
|
y2: Math.max(y1, y2, y3, y4)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
get y1()
|
get x1() {
|
||||||
{
|
return this.#aabb.x1;
|
||||||
return this.mat.elements[1] * (-0.5) + this.mat.elements[5] * (-0.5) + this.mat.elements[13] * (1 / ( this.mat.elements[ 7 ] * -0.5 + + this.mat.elements[ 15 ] ));
|
|
||||||
}
|
}
|
||||||
get x2()
|
get y1() {
|
||||||
{
|
return this.#aabb.y1;
|
||||||
return this.mat.elements[0] * (0.5) + this.mat.elements[4] * (0.5) + this.mat.elements[12] * (1 / ( this.mat.elements[ 3 ] * 0.5 + + this.mat.elements[ 15 ] ));
|
|
||||||
}
|
}
|
||||||
get y2()
|
get x2() {
|
||||||
{
|
return this.#aabb.x2;
|
||||||
return this.mat.elements[1] * (0.5) + this.mat.elements[5] * (0.5) + this.mat.elements[13] * (1 / ( this.mat.elements[ 7 ] * 0.5 + + this.mat.elements[ 15 ] ));
|
}
|
||||||
|
get y2() {
|
||||||
|
return this.#aabb.y2;
|
||||||
}
|
}
|
||||||
move(x: number, y: number): Asset
|
move(x: number, y: number): Asset
|
||||||
{
|
{
|
||||||
|
|
@ -48,6 +70,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
moveTo(x: number, y: number): Asset
|
moveTo(x: number, y: number): Asset
|
||||||
|
|
@ -59,6 +83,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
rotate(rad: number): Asset
|
rotate(rad: number): Asset
|
||||||
|
|
@ -71,6 +97,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
rotateTo(rad: number): Asset
|
rotateTo(rad: number): Asset
|
||||||
|
|
@ -83,6 +111,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
scale(x: number, y: number): Asset
|
scale(x: number, y: number): Asset
|
||||||
|
|
@ -94,6 +124,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
scaleTo(x: number, y: number): Asset
|
scaleTo(x: number, y: number): Asset
|
||||||
|
|
@ -105,6 +137,8 @@ export default class Asset implements AABB
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
this.mat.compose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
shapeTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): Asset
|
shapeTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): Asset
|
||||||
|
|
|
||||||
|
|
@ -207,4 +207,8 @@ interface LinkedElmt<T>
|
||||||
|
|
||||||
next: LinkedElmt<T> | null;
|
next: LinkedElmt<T> | null;
|
||||||
prev: LinkedElmt<T> | null;
|
prev: LinkedElmt<T> | null;
|
||||||
|
}
|
||||||
|
export function clamp(x: number, min: number, max: number): number
|
||||||
|
{
|
||||||
|
return x > max ? max : x < min ? min : x;
|
||||||
}
|
}
|
||||||
80
src/main.ts
80
src/main.ts
|
|
@ -3,52 +3,106 @@ import Renderer from './renderer/renderer.class';
|
||||||
import Asset from './assets/asset.class';
|
import Asset from './assets/asset.class';
|
||||||
import Quadtree from './physics/quadtree.class';
|
import Quadtree from './physics/quadtree.class';
|
||||||
import { FRUSTUMSIZE } from './consts';
|
import { FRUSTUMSIZE } from './consts';
|
||||||
|
import { clamp } from './common';
|
||||||
|
|
||||||
|
performance.mark("start");
|
||||||
Renderer.init();
|
Renderer.init();
|
||||||
const quad = new Quadtree({x1: -FRUSTUMSIZE * Renderer.aspect, x2: FRUSTUMSIZE * Renderer.aspect, y1: -FRUSTUMSIZE, y2: FRUSTUMSIZE});
|
const quad = new Quadtree({x1: -FRUSTUMSIZE * Renderer.aspect, x2: FRUSTUMSIZE * Renderer.aspect, y1: -FRUSTUMSIZE, y2: FRUSTUMSIZE});
|
||||||
|
|
||||||
window.Asset = Asset;
|
performance.mark("init");
|
||||||
|
|
||||||
const assets: Asset[] = [];
|
const assets: Asset[] = [];
|
||||||
for(let i = 0; i < 1; i++)
|
for(let i = 0; i < 10000; i++)
|
||||||
{
|
{
|
||||||
assets[i] = new Asset(new THREE.Matrix4(), 1);
|
assets[i] = new Asset(new THREE.Matrix4(), 1);
|
||||||
|
|
||||||
assets[i]
|
assets[i]
|
||||||
.move((Math.random() - 0.5) * FRUSTUMSIZE * Renderer.aspect, (Math.random() - 0.5) * FRUSTUMSIZE)
|
.move((Math.random() - 0.5) * FRUSTUMSIZE * Renderer.aspect, (Math.random() - 0.5) * FRUSTUMSIZE)
|
||||||
.rotate(Math.random() * Math.PI * 2)
|
.rotate(Math.random() * Math.PI * 2)
|
||||||
.scale(Math.random() * 1.5 + 0.1, Math.random() * 1.5 + 0.1)
|
.scale(Math.random() * 0.05 + 0.005, Math.random() * 0.05 + 0.005)
|
||||||
|
|
||||||
Asset.instance.setMatrixAt(i, assets[i].mat);
|
Asset.instance.setMatrixAt(i, assets[i].mat);
|
||||||
quad.insert(assets[i]);
|
quad.insert(assets[i]);
|
||||||
|
|
||||||
console.log(assets[i]);
|
|
||||||
console.log("{ %s, %s, %s, %s }", assets[i].x1, assets[i].y1, assets[i].x2, assets[i].y2);
|
|
||||||
}
|
}
|
||||||
|
performance.mark("ready");
|
||||||
|
|
||||||
|
const highlightBox = new THREE.Box3();
|
||||||
|
const highlightHelper = new THREE.Box3Helper(highlightBox, 0xffffff);
|
||||||
|
highlightHelper.visible = false;
|
||||||
|
|
||||||
|
let overallTimer = 0, overallSamples = 0;
|
||||||
|
|
||||||
Asset.instance.count = assets.length;
|
Asset.instance.count = assets.length;
|
||||||
|
|
||||||
Asset.instance.computeBoundingBox();
|
Asset.instance.computeBoundingBox();
|
||||||
Asset.instance.computeBoundingSphere();
|
Asset.instance.computeBoundingSphere();
|
||||||
|
|
||||||
console.log(Asset.instance.boundingBox);
|
const sphere = new THREE.SphereGeometry(0.05);
|
||||||
|
const sphereMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ wireframe: true, }));
|
||||||
|
|
||||||
Renderer.scene.add(Asset.instance);
|
Renderer.scene.add(Asset.instance);
|
||||||
Renderer.render();
|
Renderer.scene.add(highlightHelper);
|
||||||
|
Renderer.scene.add(sphereMesh);
|
||||||
|
|
||||||
|
Renderer.startRendering();
|
||||||
|
|
||||||
window.addEventListener('mousedown', drag);
|
window.addEventListener('mousedown', drag);
|
||||||
window.addEventListener('mouseup', select);
|
window.addEventListener('mouseup', select);
|
||||||
window.addEventListener('mousemove', hover);
|
window.addEventListener('mousemove', hover);
|
||||||
|
|
||||||
|
window.addEventListener('wheel', zoom);
|
||||||
|
|
||||||
|
console.log("Start time: %sms", performance.measure("Start time", "start", "init").duration);
|
||||||
|
console.log("Init time: %sms", performance.measure("Init time", "init", "ready").duration);
|
||||||
|
|
||||||
|
let cursor = { x: 0, y: 0 };
|
||||||
|
let dragCursor = {x: 0, y: 0 }, dragging = false;
|
||||||
|
|
||||||
function drag(e: MouseEvent): void
|
function drag(e: MouseEvent): void
|
||||||
{
|
{
|
||||||
|
dragCursor = Renderer.screenSpaceToCameraSpace(e.clientX, e.clientY, false);
|
||||||
|
dragging = true;
|
||||||
}
|
}
|
||||||
function select(e: MouseEvent): void
|
function select(e: MouseEvent): void
|
||||||
{
|
{
|
||||||
console.log(e.clientX, e.clientY, (e.clientX / window.innerWidth - 0.5) * FRUSTUMSIZE * Renderer.aspect, - (e.clientY / window.innerHeight - 0.5) * FRUSTUMSIZE);
|
dragging = false;
|
||||||
}
|
}
|
||||||
function hover(e: MouseEvent): void
|
function hover(e: MouseEvent): void
|
||||||
{
|
{
|
||||||
|
if(dragging === true)
|
||||||
}
|
{
|
||||||
|
const cursor = Renderer.screenSpaceToCameraSpace(e.clientX, e.clientY, false);
|
||||||
|
Renderer.move(dragCursor.x - cursor.x, dragCursor.y - cursor.y);
|
||||||
|
|
||||||
|
dragCursor = cursor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const cursor = Renderer.screenSpaceToCameraSpace(e.clientX, e.clientY, true);
|
||||||
|
|
||||||
|
sphereMesh.position.set(cursor.x, cursor.y, 0);
|
||||||
|
|
||||||
|
overallTimer -= performance.now();
|
||||||
|
const assets = quad.fetch(cursor.x, cursor.y) as Asset[];
|
||||||
|
overallTimer += performance.now();
|
||||||
|
overallSamples++;
|
||||||
|
|
||||||
|
if (assets.length > 0) {
|
||||||
|
highlightHelper.box.setFromArray([assets[0].x1, assets[0].y1, 0, assets[0].x2, assets[0].y2, 0]);
|
||||||
|
highlightHelper.updateMatrixWorld();
|
||||||
|
|
||||||
|
highlightHelper.visible = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
highlightHelper.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function zoom(e: WheelEvent): void
|
||||||
|
{
|
||||||
|
Renderer.zoom = clamp(Renderer.zoom * 1 + (e.deltaY * -0.001), 1, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
console.log("Average query time: %s µs", overallTimer / overallSamples * 1000);
|
||||||
|
}, 1000);
|
||||||
|
|
@ -9,7 +9,7 @@ export default class Quadtree<T extends AABB>
|
||||||
#nodes: Node[];
|
#nodes: Node[];
|
||||||
#content: T[];
|
#content: T[];
|
||||||
|
|
||||||
#dirty: boolean = false;
|
#dirty: boolean = true;
|
||||||
|
|
||||||
constructor(bounds: AABB, maxDepth?: number, maxElmts?: number)
|
constructor(bounds: AABB, maxDepth?: number, maxElmts?: number)
|
||||||
{
|
{
|
||||||
|
|
@ -22,9 +22,9 @@ export default class Quadtree<T extends AABB>
|
||||||
|
|
||||||
this.#nodes.push({ children: new LinkedList<number>(), count: 0 });
|
this.#nodes.push({ children: new LinkedList<number>(), count: 0 });
|
||||||
}
|
}
|
||||||
fetch(point: Point): T[]
|
fetch(x: number, y: number): T[]
|
||||||
{
|
{
|
||||||
return this.query({x1: point.x, x2: point.x, y1: point.y, y2: point.y});
|
return this.query({x1: x, x2: x, y1: y, y2: y});
|
||||||
}
|
}
|
||||||
query(aabb: AABB): T[]
|
query(aabb: AABB): T[]
|
||||||
{
|
{
|
||||||
|
|
@ -97,6 +97,30 @@ export default class Quadtree<T extends AABB>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
traverse(cb: (prop: NodeProp) => void): void
|
||||||
|
{
|
||||||
|
const stack: NodeProp[] = [];
|
||||||
|
stack.push({ index: 0, depth: 0, bounds: this.#bounds });
|
||||||
|
|
||||||
|
while(stack.length > 0)
|
||||||
|
{
|
||||||
|
const nodeProp = stack.pop()!;
|
||||||
|
|
||||||
|
cb(nodeProp);
|
||||||
|
|
||||||
|
//If the node contains elements
|
||||||
|
if (this.#nodes[nodeProp.index].count === -1)
|
||||||
|
{
|
||||||
|
const children = this.#nodes[nodeProp.index].children.toArray();
|
||||||
|
const mx = nodeProp.bounds.x1 + (nodeProp.bounds.x2 - nodeProp.bounds.x1) / 2, my = nodeProp.bounds.y1 + (nodeProp.bounds.y2 - nodeProp.bounds.y1) / 2;
|
||||||
|
|
||||||
|
stack.push({ index: children[0], depth: nodeProp.depth + 1, bounds: { x1: nodeProp.bounds.x1, x2: mx, y1: nodeProp.bounds.y1, y2: my } });
|
||||||
|
stack.push({ index: children[1], depth: nodeProp.depth + 1, bounds: { x1: mx, x2: nodeProp.bounds.x2, y1: nodeProp.bounds.y1, y2: my } });
|
||||||
|
stack.push({ index: children[2], depth: nodeProp.depth + 1, bounds: { x1: nodeProp.bounds.x1, x2: mx, y1: my, y2: nodeProp.bounds.y2 } });
|
||||||
|
stack.push({ index: children[3], depth: nodeProp.depth + 1, bounds: { x1: mx, x2: nodeProp.bounds.x2, y1: my, y2: nodeProp.bounds.y2 } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#find_leaves(index: number, depth: number, bounds: AABB, elmtBounds: AABB): NodeProp[]
|
#find_leaves(index: number, depth: number, bounds: AABB, elmtBounds: AABB): NodeProp[]
|
||||||
{
|
{
|
||||||
|
|
@ -110,26 +134,26 @@ export default class Quadtree<T extends AABB>
|
||||||
|
|
||||||
//If the node contains elements
|
//If the node contains elements
|
||||||
if(this.#nodes[nodeProp.index].count !== -1)
|
if(this.#nodes[nodeProp.index].count !== -1)
|
||||||
result.push({index: index, depth: depth, bounds: bounds});
|
result.push(nodeProp);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Check intersection on each 4 sides of the node
|
//Check intersection on each 4 sides of the node
|
||||||
const children = this.#nodes[nodeProp.index].children.toArray();
|
const children = this.#nodes[nodeProp.index].children.toArray();
|
||||||
const mx = bounds.x1 + (bounds.x2 - bounds.x1) / 2, my = bounds.y1 + (bounds.y2 - bounds.y1) / 2;
|
const mx = nodeProp.bounds.x1 + (nodeProp.bounds.x2 - nodeProp.bounds.x1) / 2, my = nodeProp.bounds.y1 + (nodeProp.bounds.y2 - nodeProp.bounds.y1) / 2;
|
||||||
|
|
||||||
if(elmtBounds.y1 <= my)
|
if(elmtBounds.y1 <= my)
|
||||||
{
|
{
|
||||||
if(elmtBounds.x1 <= mx)
|
if(elmtBounds.x1 <= mx)
|
||||||
stack.push({ index: children[0], depth: depth + 1, bounds: { x1: bounds.x1, x2: mx, y1: bounds.y1, y2: my }});
|
stack.push({ index: children[0], depth: nodeProp.depth + 1, bounds: { x1: nodeProp.bounds.x1, x2: mx, y1: nodeProp.bounds.y1, y2: my }});
|
||||||
if(elmtBounds.x2 > mx)
|
if(elmtBounds.x2 > mx)
|
||||||
stack.push({ index: children[1], depth: depth + 1, bounds: { x1: mx, x2: bounds.x2, y1: bounds.y1, y2: my }});
|
stack.push({ index: children[1], depth: nodeProp.depth + 1, bounds: { x1: mx, x2: nodeProp.bounds.x2, y1: nodeProp.bounds.y1, y2: my }});
|
||||||
}
|
}
|
||||||
if(elmtBounds.y2 > my)
|
if(elmtBounds.y2 > my)
|
||||||
{
|
{
|
||||||
if(elmtBounds.x1 <= mx)
|
if(elmtBounds.x1 <= mx)
|
||||||
stack.push({ index: children[2], depth: depth + 1, bounds: { x1: bounds.x1, x2: mx, y1: my, y2: bounds.y2 }});
|
stack.push({ index: children[2], depth: nodeProp.depth + 1, bounds: { x1: nodeProp.bounds.x1, x2: mx, y1: my, y2: nodeProp.bounds.y2 }});
|
||||||
if(elmtBounds.x2 > mx)
|
if(elmtBounds.x2 > mx)
|
||||||
stack.push({ index: children[3], depth: depth + 1, bounds: { x1: mx, x2: bounds.x2, y1: my, y2: bounds.y2 }});
|
stack.push({ index: children[3], depth: nodeProp.depth + 1, bounds: { x1: mx, x2: nodeProp.bounds.x2, y1: my, y2: nodeProp.bounds.y2 }});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import * as Three from 'three';
|
import * as Three from 'three';
|
||||||
import { FRUSTUMSIZE } from '../consts';
|
import { FRUSTUMSIZE } from '../consts';
|
||||||
|
import Stats from 'stats.js';
|
||||||
|
import { Point } from '../physics/common';
|
||||||
|
|
||||||
export default class Renderer
|
export default class Renderer
|
||||||
{
|
{
|
||||||
|
|
@ -8,6 +10,11 @@ export default class Renderer
|
||||||
|
|
||||||
static renderer: Three.WebGLRenderer;
|
static renderer: Three.WebGLRenderer;
|
||||||
static camera: Three.OrthographicCamera;
|
static camera: Three.OrthographicCamera;
|
||||||
|
|
||||||
|
static #zoom: number;
|
||||||
|
static #pos: Point = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
static #stats: Stats;
|
||||||
static init(): Boolean
|
static init(): Boolean
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -19,6 +26,12 @@ export default class Renderer
|
||||||
this.camera = new Three.OrthographicCamera();
|
this.camera = new Three.OrthographicCamera();
|
||||||
this.camera.position.z = 500;
|
this.camera.position.z = 500;
|
||||||
|
|
||||||
|
this.#zoom = 1;
|
||||||
|
|
||||||
|
const stats = this.#stats = new Stats();
|
||||||
|
stats.showPanel(0);
|
||||||
|
document.body.appendChild(stats.dom);
|
||||||
|
|
||||||
this.#resize();
|
this.#resize();
|
||||||
window.addEventListener("resize", this.#resize.bind(this));
|
window.addEventListener("resize", this.#resize.bind(this));
|
||||||
|
|
||||||
|
|
@ -30,15 +43,35 @@ export default class Renderer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static get zoom(): number
|
||||||
|
{
|
||||||
|
return this.#zoom;
|
||||||
|
}
|
||||||
|
static set zoom(v: number)
|
||||||
|
{
|
||||||
|
this.#zoom = v;
|
||||||
|
this.#resize();
|
||||||
|
}
|
||||||
|
static move(x: number, y: number): void
|
||||||
|
{
|
||||||
|
this.#pos.x += x;
|
||||||
|
this.#pos.y += y;
|
||||||
|
|
||||||
|
this.camera.position.x += x;
|
||||||
|
this.camera.position.y += y;
|
||||||
|
}
|
||||||
|
static screenSpaceToCameraSpace(x: number, y: number, offset: boolean): Point {
|
||||||
|
return { x: ((x / window.innerWidth - 0.5) * FRUSTUMSIZE * this.aspect - (offset ? this.#pos.x : 0)) / this.#zoom, y: (- (y / window.innerHeight - 0.5) * FRUSTUMSIZE - (offset ? this.#pos.x : 0)) / this.zoom };
|
||||||
|
}
|
||||||
static #resize(): void
|
static #resize(): void
|
||||||
{
|
{
|
||||||
const aspect = this.aspect = window.innerWidth / window.innerHeight;
|
const aspect = this.aspect = window.innerWidth / window.innerHeight;
|
||||||
this.renderer.setSize( window.innerWidth, window.innerHeight );
|
this.renderer.setSize( window.innerWidth, window.innerHeight );
|
||||||
|
|
||||||
this.camera.left = FRUSTUMSIZE * aspect / - 2;
|
this.camera.left = FRUSTUMSIZE * aspect / - 2 / this.#zoom;
|
||||||
this.camera.right = FRUSTUMSIZE * aspect / 2;
|
this.camera.right = FRUSTUMSIZE * aspect / 2 / this.#zoom;
|
||||||
this.camera.top = FRUSTUMSIZE / 2;
|
this.camera.top = FRUSTUMSIZE / 2 / this.#zoom;
|
||||||
this.camera.bottom = FRUSTUMSIZE / - 2;
|
this.camera.bottom = FRUSTUMSIZE / - 2 / this.#zoom;
|
||||||
|
|
||||||
this.camera.updateProjectionMatrix();
|
this.camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
|
@ -46,7 +79,9 @@ export default class Renderer
|
||||||
}
|
}
|
||||||
static render(delta?: number): void
|
static render(delta?: number): void
|
||||||
{
|
{
|
||||||
|
this.#stats.begin();
|
||||||
this.renderer.render(this.scene, this.camera);
|
this.renderer.render(this.scene, this.camera);
|
||||||
|
this.#stats.end();
|
||||||
}
|
}
|
||||||
static startRendering(): void
|
static startRendering(): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue