Optimize quadtree
This commit is contained in:
parent
1d907c8ab9
commit
209a070464
|
|
@ -1,6 +1,7 @@
|
|||
import * as Three from 'three';
|
||||
import * as CONST from '../consts';
|
||||
import { AABB } from '../physics/common';
|
||||
import Quadtree from '../physics/quadtree.class';
|
||||
|
||||
const UP = new Three.Vector3(0, 0, 1);
|
||||
|
||||
|
|
@ -9,26 +10,41 @@ const _rotation = new Three.Quaternion();
|
|||
const _euler = new Three.Euler();
|
||||
const _scale = new Three.Vector3();
|
||||
|
||||
export default class Asset implements AABB
|
||||
export default class Asset
|
||||
{
|
||||
mat: Three.Matrix4;
|
||||
layer: number;
|
||||
|
||||
#selected = false;
|
||||
#dirty = false;
|
||||
|
||||
//@ts-ignore
|
||||
//@ts-expect-error
|
||||
#aabb: AABB;
|
||||
|
||||
static instance = new Three.InstancedMesh(CONST.QUAD, new Three.MeshBasicMaterial({ color: new Three.Color( 0xffffff ) }), 1000000);
|
||||
#index: number;
|
||||
#quad?: number;
|
||||
|
||||
static instance: Three.InstancedMesh = new Three.InstancedMesh(CONST.QUAD, new Three.MeshBasicMaterial({ color: new Three.Color(0xffffff) }), 1000000);
|
||||
static assets: Asset[] = [];
|
||||
|
||||
constructor(mat?: Three.Matrix4, layer?: number)
|
||||
{
|
||||
this.mat = mat ?? new Three.Matrix4();
|
||||
this.#updateAABB();
|
||||
this.layer = layer ?? 0;
|
||||
|
||||
this.#index = Asset.assets.push(this) - 1;
|
||||
}
|
||||
#updateAABB() {
|
||||
get aabb(): AABB
|
||||
{
|
||||
return this.#aabb;
|
||||
}
|
||||
insert(quad: Quadtree): void
|
||||
{
|
||||
this.#quad = quad.insert(this.#index, this.#aabb);
|
||||
}
|
||||
remove(quad: Quadtree): void
|
||||
{
|
||||
this.#quad !== undefined && quad.remove(this.#quad);
|
||||
}
|
||||
#updateAABB(): void {
|
||||
const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 };
|
||||
|
||||
const e = this.mat.elements;
|
||||
|
|
@ -49,18 +65,6 @@ export default class Asset implements AABB
|
|||
y2: Math.max(y1, y2, y3, y4)
|
||||
};
|
||||
}
|
||||
get x1() {
|
||||
return this.#aabb.x1;
|
||||
}
|
||||
get y1() {
|
||||
return this.#aabb.y1;
|
||||
}
|
||||
get x2() {
|
||||
return this.#aabb.x2;
|
||||
}
|
||||
get y2() {
|
||||
return this.#aabb.y2;
|
||||
}
|
||||
move(x: number, y: number): Asset
|
||||
{
|
||||
this.mat.decompose(_position, _rotation, _scale);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class FreeList<T>
|
|||
}
|
||||
export class IntList
|
||||
{
|
||||
#data: Uint32Array;
|
||||
#data: number[];
|
||||
#fields: number;
|
||||
#capacity: number = DEFAULT_SIZE;
|
||||
#length: number = 0;
|
||||
|
|
@ -63,7 +63,7 @@ export class IntList
|
|||
if(fields <= 0)
|
||||
throw new Error("Invalid field count");
|
||||
|
||||
this.#data = new Uint32Array(this.#capacity * fields);
|
||||
this.#data = new Array(this.#capacity * fields);
|
||||
this.#fields = fields;
|
||||
}
|
||||
get length(): number
|
||||
|
|
@ -105,8 +105,7 @@ export class IntList
|
|||
{
|
||||
this.#capacity *= 2;
|
||||
|
||||
//@ts-ignore
|
||||
this.#data.buffer.transferToFixedLength(this.#capacity);
|
||||
this.#data.length = this.#capacity * this.#fields;
|
||||
}
|
||||
|
||||
return this.#length++;
|
||||
|
|
@ -140,7 +139,22 @@ export class IntList
|
|||
|
||||
toArray(): number[]
|
||||
{
|
||||
return Array.from(this.#data);
|
||||
return this.#data.slice(0, this.#length);
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
printReadable(names: string[] = []): void
|
||||
{
|
||||
const size = this.#length * this.#fields;
|
||||
for(let i = 0; i < size; i)
|
||||
{
|
||||
const obj: Record<string, number> = {};
|
||||
for(let j = 0; j < this.#fields; ++i, ++j)
|
||||
{
|
||||
obj[names[j] ?? j] = this.#data[i];
|
||||
}
|
||||
console.log(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class Stack<T>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export {
|
|||
QUAD
|
||||
};
|
||||
|
||||
export const FRUSTUMSIZE = 16;
|
||||
export const RESOLUTION_X = 2048;
|
||||
export const RESOLUTION_Y = 2048;
|
||||
|
||||
export const MAX_DEPTH = 8;
|
||||
35
src/main.ts
35
src/main.ts
|
|
@ -2,45 +2,38 @@ import * as THREE from 'three';
|
|||
import Renderer from './renderer/renderer.class';
|
||||
import Asset from './assets/asset.class';
|
||||
import Quadtree from './physics/quadtree.class';
|
||||
import { FRUSTUMSIZE } from './consts';
|
||||
import { RESOLUTION_X, RESOLUTION_Y } from './consts';
|
||||
import Input from './renderer/input.class';
|
||||
import { Random, clamp } from './common';
|
||||
import Selector from './renderer/selector.class';
|
||||
|
||||
if(!ArrayBuffer.prototype.hasOwnProperty("transferToFixedLength"))
|
||||
{
|
||||
throw new Error("Your web browser doesn't includes the latest features needed to make this website work properly.\nPlease upgrade your browser and try again.");
|
||||
}
|
||||
|
||||
Renderer.init();
|
||||
Input.init(Renderer.canvas);
|
||||
Selector.init();
|
||||
|
||||
const r = new Random(0);
|
||||
const quad = new Quadtree({ x1: -RESOLUTION_X / 2, x2: RESOLUTION_X / 2, y1: -RESOLUTION_Y / 2, y2: RESOLUTION_Y / 2 }, 6, 10);
|
||||
|
||||
const quad = new Quadtree({x1: -FRUSTUMSIZE * Renderer.aspect / 2, x2: FRUSTUMSIZE * Renderer.aspect / 2, y1: -FRUSTUMSIZE / 2, y2: FRUSTUMSIZE / 2});
|
||||
|
||||
const assets: Asset[] = [];
|
||||
for(let i = 0; i < 10000; i++)
|
||||
{
|
||||
assets[i] = new Asset(new THREE.Matrix4(), 1);
|
||||
const asset = new Asset(new THREE.Matrix4(), 1);
|
||||
|
||||
assets[i]
|
||||
.move(r.nextFloat(-0.5 * FRUSTUMSIZE * Renderer.aspect, 0.5 * FRUSTUMSIZE * Renderer.aspect), r.nextFloat(-0.5 * FRUSTUMSIZE, 0.5 * FRUSTUMSIZE))
|
||||
asset.move(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y))
|
||||
.rotate(r.nextFloat(Math.PI * 2))
|
||||
.scale(r.nextFloat(0.01, 0.15), r.nextFloat(0.01, 0.15))
|
||||
.scale(r.nextFloat(10, 30), r.nextFloat(10, 30));
|
||||
|
||||
Asset.instance.setMatrixAt(i, assets[i].mat);
|
||||
quad.insert(i, assets[i]);
|
||||
Asset.instance.setMatrixAt(i, asset.mat);
|
||||
asset.insert(quad);
|
||||
}
|
||||
|
||||
Asset.instance.count = assets.length;
|
||||
Asset.instance.count = Asset.assets.length;
|
||||
|
||||
Asset.instance.computeBoundingBox();
|
||||
Asset.instance.computeBoundingSphere();
|
||||
|
||||
Renderer.scene.add(Asset.instance);
|
||||
|
||||
//quad.debug();
|
||||
Renderer.startRendering();
|
||||
|
||||
Input.onDragStart((_, button) => { if(button & 1) Selector.hide(); });
|
||||
|
|
@ -48,8 +41,8 @@ Input.onDragEnd((start, end, button) => {
|
|||
if(button & 1)
|
||||
{
|
||||
const s = performance.now();
|
||||
const selection = quad.query({x1: Math.min(start.x, end.x), x2: Math.max(start.x, end.x), y1: Math.min(start.y, end.y), y2: Math.max(start.y, end.y)}).map(e => assets[e]);
|
||||
console.log("Fetching %s out of %s elements in %sms", selection.length, assets.length, performance.now() - s);
|
||||
const selection = quad.query({x1: Math.min(start.x, end.x), x2: Math.max(start.x, end.x), y1: Math.min(start.y, end.y), y2: Math.max(start.y, end.y)}).map(e => Asset.assets[e]);
|
||||
console.log("Fetching %s out of %s elements in %sms", selection.length, Asset.assets.length, performance.now() - s);
|
||||
|
||||
if(Input.keys['Shift']) Selector.toggle(selection);
|
||||
else Selector.select(selection);
|
||||
|
|
@ -59,11 +52,11 @@ Input.onDrag((delta, start, end, button) => { if(button & 1) Selector.preview(st
|
|||
Input.onClick((point, button) => {
|
||||
if(button & 1)
|
||||
{
|
||||
const selection = quad.fetch(point.x, point.y).map(e => assets[e]);
|
||||
const selection = quad.fetch(point.x, point.y).map(e => Asset.assets[e]);
|
||||
|
||||
if(Input.keys['Shift']) Selector.toggle(selection);
|
||||
else Selector.select(selection);
|
||||
}
|
||||
});
|
||||
Input.onWheel(delta => Renderer.zoom = clamp(Renderer.zoom * 1 + (delta * -0.001), 1, 5));
|
||||
Input.onMove(p => { if(!Input.dragging) Selector.ghost(assets[quad.fetch(p.x, p.y)[0]]); });
|
||||
Input.onWheel(delta => Renderer.zoom = clamp(Renderer.zoom * 1 + (delta * -0.001), 0.9, 5));
|
||||
Input.onMove(p => { if (!Input.dragging) Selector.ghost(Asset.assets[quad.fetch(p.x, p.y)[0]]); });
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import Asset from "../assets/asset.class";
|
||||
|
||||
export interface Point
|
||||
{
|
||||
x: number;
|
||||
|
|
@ -11,22 +13,12 @@ export interface AABB
|
|||
y2: number;
|
||||
}
|
||||
|
||||
export function intersectsObj(a: AABB, b: AABB | Point): Boolean
|
||||
{
|
||||
if(b.hasOwnProperty("x") && b.hasOwnProperty("y"))
|
||||
{
|
||||
b = b as Point;
|
||||
|
||||
return a.x1 <= b.x && a.x2 >= b.x && a.y1 <= b.y && a.y2 >= b.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = b as AABB;
|
||||
|
||||
return a.x1 <= b.x2 && a.x2 >= b.x1 && a.y1 <= b.y2 && a.y2 >= b.y1;
|
||||
}
|
||||
}
|
||||
export function intersects(aLeft: number, aTop: number, aRight: number, aBottom: number, bLeft: number, bTop: number, bRight: number, bBottom: number): Boolean
|
||||
export function intersects(aLeft: number, aTop: number, aRight: number, aBottom: number, bLeft: number, bTop: number, bRight: number, bBottom: number): boolean
|
||||
{
|
||||
return aLeft <= bRight && aRight >= bLeft && aTop <= bBottom && aBottom >= bTop;
|
||||
}
|
||||
export function intersectsAsset(left: number, top: number, right: number, bottom: number, id: number): boolean
|
||||
{
|
||||
const aabb = Asset.assets[id].aabb;
|
||||
return intersects(left, top, right, bottom, aabb.x1, aabb.y1, aabb.x2, aabb.y2);
|
||||
}
|
||||
|
|
@ -1,13 +1,8 @@
|
|||
import { FreeList, IntList, LinkedList } from "../common";
|
||||
import { IntList } from "../common";
|
||||
import Renderer from "../renderer/renderer.class";
|
||||
import { AABB, intersects } from "./common";
|
||||
import { AABB, intersectsAsset } from "./common";
|
||||
import * as THREE from 'three';
|
||||
|
||||
/**
|
||||
* A node that contains elments is called a leaf. Its count is equals to the amount of children it holds.
|
||||
* A node that contains other nodes is called a branch. Its count is equals to -1.
|
||||
* The AABB of each node isn't stored and is computed on the go. (Not memory friendly in JS ?)
|
||||
*/
|
||||
enum QuadConsts
|
||||
{
|
||||
ENodeINext = 0,
|
||||
|
|
@ -23,8 +18,13 @@ enum QuadConsts
|
|||
}
|
||||
|
||||
const _process = new IntList(1);
|
||||
const _nodeProcess = new IntList(QuadConsts.PropCount);
|
||||
const _nodes = new IntList(QuadConsts.PropCount);
|
||||
|
||||
/**
|
||||
* A node that contains elments is called a leaf. Its count is equals to the amount of children it holds.
|
||||
* A node that contains other nodes is called a branch. Its count is equals to -1.
|
||||
* The AABB of each node isn't stored and is computed on the go.
|
||||
*/
|
||||
export default class Quadtree
|
||||
{
|
||||
#bounds: AABB;
|
||||
|
|
@ -40,6 +40,11 @@ export default class Quadtree
|
|||
constructor(bounds: AABB, maxDepth?: number, maxElmts?: number)
|
||||
{
|
||||
this.#bounds = bounds;
|
||||
this.#bounds.x1 = Math.round(this.#bounds.x1);
|
||||
this.#bounds.x2 = Math.round(this.#bounds.x2);
|
||||
this.#bounds.y1 = Math.round(this.#bounds.y1);
|
||||
this.#bounds.y2 = Math.round(this.#bounds.y2);
|
||||
|
||||
this.#maxDepth = maxDepth ?? this.#maxDepth;
|
||||
this.#maxElmts = maxElmts ?? this.#maxElmts;
|
||||
|
||||
|
|
@ -55,7 +60,7 @@ export default class Quadtree
|
|||
{
|
||||
_process.clear();
|
||||
|
||||
const leaves = this.#findLeaves(0, 0, this.#bounds.x1, this.#bounds.x2, this.#bounds.y1, this.#bounds.y2, aabb.x1, aabb.x2, aabb.y1, aabb.y2);
|
||||
const leaves = this.#findLeaves(0, 0, this.#bounds.x1, this.#bounds.x2, this.#bounds.y1, this.#bounds.y2, Math.floor(aabb.x1), Math.floor(aabb.x2), Math.floor(aabb.y1), Math.floor(aabb.y2));
|
||||
|
||||
const tmp: Record<number, boolean> = {};
|
||||
|
||||
|
|
@ -68,14 +73,11 @@ export default class Quadtree
|
|||
{
|
||||
const elmt = this.#enodes.get(node, QuadConsts.ENodeIElmt);
|
||||
|
||||
const left = this.#content.get(elmt, QuadConsts.ElmtILft),
|
||||
right = this.#content.get(elmt, QuadConsts.ElmtIRgt),
|
||||
top = this.#content.get(elmt, QuadConsts.ElmtITop),
|
||||
bottom = this.#content.get(elmt, QuadConsts.ElmtIBtm);
|
||||
const id = this.#content.get(elmt, QuadConsts.ElmtIId);
|
||||
|
||||
if(!tmp[elmt] && intersects(aabb.x1, aabb.y1, aabb.x2, aabb.y2, left, top, right, bottom))
|
||||
if (!tmp[elmt] && intersectsAsset(aabb.x1, aabb.y1, aabb.x2, aabb.y2, id))
|
||||
{
|
||||
_process.set(_process.push(), 0, elmt);
|
||||
_process.set(_process.push(), 0, id);
|
||||
tmp[elmt] = true;
|
||||
}
|
||||
node = this.#enodes.get(node, QuadConsts.ENodeINext);
|
||||
|
|
@ -88,10 +90,10 @@ export default class Quadtree
|
|||
{
|
||||
const index = this.#content.insert();
|
||||
|
||||
this.#content.set(index, QuadConsts.ElmtILft, aabb.x1);
|
||||
this.#content.set(index, QuadConsts.ElmtIRgt, aabb.x2);
|
||||
this.#content.set(index, QuadConsts.ElmtITop, aabb.y1);
|
||||
this.#content.set(index, QuadConsts.ElmtIBtm, aabb.y2);
|
||||
this.#content.set(index, QuadConsts.ElmtILft, Math.floor(aabb.x1));
|
||||
this.#content.set(index, QuadConsts.ElmtIRgt, Math.floor(aabb.x2));
|
||||
this.#content.set(index, QuadConsts.ElmtITop, Math.floor(aabb.y1));
|
||||
this.#content.set(index, QuadConsts.ElmtIBtm, Math.floor(aabb.y2));
|
||||
this.#content.set(index, QuadConsts.ElmtIId, id);
|
||||
|
||||
this.#insertNode(0, 0, this.#bounds.x1, this.#bounds.x2, this.#bounds.y1, this.#bounds.y2, index);
|
||||
|
|
@ -190,26 +192,26 @@ export default class Quadtree
|
|||
}
|
||||
traverse(cb: (index: number, depth: number, left: number, top: number, right: number, bottom: number, leaf: boolean) => void): void
|
||||
{
|
||||
_nodeProcess.clear();
|
||||
_nodes.clear();
|
||||
|
||||
insert(_nodeProcess, 0, 0, this.#bounds.x1, this.#bounds.x2, this.#bounds.y1, this.#bounds.y2);
|
||||
insert(_nodes, 0, 0, this.#bounds.x1, this.#bounds.x2, this.#bounds.y1, this.#bounds.y2);
|
||||
|
||||
while(_nodeProcess.length > 0)
|
||||
while(_nodes.length > 0)
|
||||
{
|
||||
const last = _nodeProcess.length - 1;
|
||||
const last = _nodes.length - 1;
|
||||
|
||||
const node = _nodeProcess.get(last, QuadConsts.PropIIdx);
|
||||
const left = _nodeProcess.get(last, QuadConsts.PropILft);
|
||||
const right = _nodeProcess.get(last, QuadConsts.PropIRgt);
|
||||
const top = _nodeProcess.get(last, QuadConsts.PropITop);
|
||||
const bottom = _nodeProcess.get(last, QuadConsts.PropIBtm);
|
||||
const depth = _nodeProcess.get(last, QuadConsts.PropIDpt);
|
||||
const node = _nodes.get(last, QuadConsts.PropIIdx);
|
||||
const left = _nodes.get(last, QuadConsts.PropILft);
|
||||
const right = _nodes.get(last, QuadConsts.PropIRgt);
|
||||
const top = _nodes.get(last, QuadConsts.PropITop);
|
||||
const bottom = _nodes.get(last, QuadConsts.PropIBtm);
|
||||
const depth = _nodes.get(last, QuadConsts.PropIDpt);
|
||||
|
||||
_nodeProcess.pop();
|
||||
_nodes.pop();
|
||||
|
||||
const count = this.#nodes.get(node, QuadConsts.NodeICount);
|
||||
|
||||
cb(left, top, right, bottom, node, depth, count !== -1);
|
||||
cb(node, depth, left, top, right, bottom, count !== -1);
|
||||
|
||||
//If it's a branch
|
||||
if (count === -1)
|
||||
|
|
@ -217,14 +219,14 @@ export default class Quadtree
|
|||
const fc = this.#nodes.get(node, QuadConsts.NodeIFirst);
|
||||
const mx = left + (right - left) / 2, my = top + (bottom - top) / 2;
|
||||
|
||||
insert(_nodeProcess, fc + 0, depth + 1, left, mx, top, my);
|
||||
insert(_nodeProcess, fc + 1, depth + 1, mx, right, top, my);
|
||||
insert(_nodeProcess, fc + 2, depth + 1, left, mx, my, bottom);
|
||||
insert(_nodeProcess, fc + 3, depth + 1, mx, right, my, bottom);
|
||||
insert(_nodes, fc + 0, depth + 1, left, mx, top, my);
|
||||
insert(_nodes, fc + 1, depth + 1, mx, right, top, my);
|
||||
insert(_nodes, fc + 2, depth + 1, left, mx, my, bottom);
|
||||
insert(_nodes, fc + 3, depth + 1, mx, right, my, bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
render(): void
|
||||
debug(): void
|
||||
{
|
||||
Renderer.scene.remove(...this.#debugRect);
|
||||
this.#debugRect = [];
|
||||
|
|
@ -234,26 +236,30 @@ export default class Quadtree
|
|||
});
|
||||
|
||||
Renderer.scene.add(...this.#debugRect);
|
||||
|
||||
// this.#nodes.printReadable(["first", "count"]);
|
||||
// this.#enodes.printReadable(["index", "next"]);
|
||||
// this.#content.printReadable(["left", "right", "top", "bottom", "index", "depth"]);
|
||||
}
|
||||
|
||||
#findLeaves(index: number, depth: number, lleft: number, lright: number, ltop: number, lbottom: number, eleft: number, eright: number, etop: number, ebottom: number): IntList
|
||||
{
|
||||
const leaves = new IntList(QuadConsts.PropCount);
|
||||
_nodeProcess.clear();
|
||||
insert(_nodeProcess, index, depth, lleft, lright, ltop, lbottom);
|
||||
_nodes.clear();
|
||||
insert(_nodes, index, depth, lleft, lright, ltop, lbottom);
|
||||
|
||||
while (_nodeProcess.length > 0)
|
||||
while (_nodes.length > 0)
|
||||
{
|
||||
const last = _nodeProcess.length - 1;
|
||||
const last = _nodes.length - 1;
|
||||
|
||||
const nodeLeft = _nodeProcess.get(last, QuadConsts.PropILft);
|
||||
const nodeRight = _nodeProcess.get(last, QuadConsts.PropIRgt);
|
||||
const nodeTop = _nodeProcess.get(last, QuadConsts.PropITop);
|
||||
const nodeBottom = _nodeProcess.get(last, QuadConsts.PropIBtm);
|
||||
const nodeIndex = _nodeProcess.get(last, QuadConsts.PropIIdx);
|
||||
const nodeDepth = _nodeProcess.get(last, QuadConsts.PropIDpt);
|
||||
const nodeLeft = _nodes.get(last, QuadConsts.PropILft);
|
||||
const nodeRight = _nodes.get(last, QuadConsts.PropIRgt);
|
||||
const nodeTop = _nodes.get(last, QuadConsts.PropITop);
|
||||
const nodeBottom = _nodes.get(last, QuadConsts.PropIBtm);
|
||||
const nodeIndex = _nodes.get(last, QuadConsts.PropIIdx);
|
||||
const nodeDepth = _nodes.get(last, QuadConsts.PropIDpt);
|
||||
|
||||
_nodeProcess.pop();
|
||||
_nodes.pop();
|
||||
|
||||
if(this.#nodes.get(nodeIndex, QuadConsts.NodeICount) !== -1)
|
||||
insert(leaves, nodeIndex, nodeDepth, nodeLeft, nodeRight, nodeTop, nodeBottom);
|
||||
|
|
@ -266,16 +272,16 @@ export default class Quadtree
|
|||
if(etop <= my)
|
||||
{
|
||||
if(eleft <= mx) //Add a new
|
||||
insert(_nodeProcess, fc + 0, nodeDepth + 1, nodeLeft, mx, nodeTop, my);
|
||||
insert(_nodes, fc + 0, nodeDepth + 1, nodeLeft, mx, nodeTop, my);
|
||||
if(eright > mx)
|
||||
insert(_nodeProcess, fc + 1, nodeDepth + 1, mx, nodeRight, nodeTop, my);
|
||||
insert(_nodes, fc + 1, nodeDepth + 1, mx, nodeRight, nodeTop, my);
|
||||
}
|
||||
if(ebottom > my)
|
||||
{
|
||||
if(eleft <= mx)
|
||||
insert(_nodeProcess, fc + 2, nodeDepth + 1, nodeLeft, mx, my, nodeBottom);
|
||||
insert(_nodes, fc + 2, nodeDepth + 1, nodeLeft, mx, my, nodeBottom);
|
||||
if(eright > mx)
|
||||
insert(_nodeProcess, fc + 3, nodeDepth + 1, mx, nodeRight, my, nodeBottom);
|
||||
insert(_nodes, fc + 3, nodeDepth + 1, mx, nodeRight, my, nodeBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,14 +334,14 @@ export default class Quadtree
|
|||
this.#nodes.set(index, QuadConsts.NodeICount, -1);
|
||||
|
||||
for(let i = 0; i < _process.length; ++i)
|
||||
this.#insertNode(index, depth, left, top, right, bottom, _process.get(i, 0));
|
||||
this.#insertNode(index, depth, left, right, top, bottom, _process.get(i, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#nodes.set(index, QuadConsts.NodeICount, this.#nodes.get(index, QuadConsts.NodeICount) + 1);
|
||||
}
|
||||
}
|
||||
#insertNode(index: number, depth: number, left: number, top: number, right: number, bottom: number, elmt: number): void
|
||||
#insertNode(index: number, depth: number, left: number, right: number, top: number, bottom: number, elmt: number): void
|
||||
{
|
||||
const leaves = this.#findLeaves(index, depth, left, right, top, bottom, this.#content.get(elmt, QuadConsts.ElmtILft), this.#content.get(elmt, QuadConsts.ElmtIRgt), this.#content.get(elmt, QuadConsts.ElmtITop), this.#content.get(elmt, QuadConsts.ElmtIBtm));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as Three from 'three';
|
||||
import { FRUSTUMSIZE } from '../consts';
|
||||
import { RESOLUTION_X, RESOLUTION_Y } from '../consts';
|
||||
import Stats from 'stats.js';
|
||||
import { Point } from '../physics/common';
|
||||
|
||||
|
|
@ -65,17 +65,17 @@ export default class Renderer
|
|||
this.camera.position.y += y;
|
||||
}
|
||||
static screenSpaceToCameraSpace(x: number, y: number, omit: boolean = false): Point {
|
||||
return { x: ((x / window.innerWidth - 0.5) * FRUSTUMSIZE * this.aspect) / this.#zoom + (omit ? 0 : this.#pos.x), y: (- (y / window.innerHeight - 0.5) * FRUSTUMSIZE) / this.zoom + (omit ? 0 : this.#pos.y) };
|
||||
return { x: ((x / window.innerWidth - 0.5) * RESOLUTION_X * this.aspect) / this.#zoom + (omit ? 0 : this.#pos.x), y: (- (y / window.innerHeight - 0.5) * RESOLUTION_Y) / this.zoom + (omit ? 0 : this.#pos.y) };
|
||||
}
|
||||
static #resize(): void
|
||||
{
|
||||
const aspect = this.aspect = window.innerWidth / window.innerHeight;
|
||||
this.renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
|
||||
this.camera.left = FRUSTUMSIZE * aspect / - 2 / this.#zoom;
|
||||
this.camera.right = FRUSTUMSIZE * aspect / 2 / this.#zoom;
|
||||
this.camera.top = FRUSTUMSIZE / 2 / this.#zoom;
|
||||
this.camera.bottom = FRUSTUMSIZE / - 2 / this.#zoom;
|
||||
this.camera.left = RESOLUTION_X * aspect / - 2 / this.#zoom;
|
||||
this.camera.right = RESOLUTION_X * aspect / 2 / this.#zoom;
|
||||
this.camera.top = RESOLUTION_Y / 2 / this.#zoom;
|
||||
this.camera.bottom = RESOLUTION_Y / - 2 / this.#zoom;
|
||||
|
||||
this.camera.updateProjectionMatrix();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default class Selector
|
|||
return;
|
||||
}
|
||||
|
||||
Selector.#ghostMesh.box.setFromArray([asset.x1, asset.y1, 0, asset.x2, asset.y2, 0]);
|
||||
Selector.#ghostMesh.box.setFromArray([asset.aabb.x1, asset.aabb.y1, 0, asset.aabb.x2, asset.aabb.y2, 0]);
|
||||
Selector.#ghostMesh.updateMatrix();
|
||||
|
||||
Selector.#ghostMesh.visible = true;
|
||||
|
|
@ -65,11 +65,11 @@ export default class Selector
|
|||
Selector.#selected = true;
|
||||
|
||||
Selector.#selectionMesh.box.setFromArray([
|
||||
assets.map(e => e.x1).reduce((p, v) => Math.min(p, v), Infinity),
|
||||
assets.map(e => e.y1).reduce((p, v) => Math.min(p, v), Infinity),
|
||||
assets.map(e => e.aabb.x1).reduce((p, v) => Math.min(p, v), Infinity),
|
||||
assets.map(e => e.aabb.y1).reduce((p, v) => Math.min(p, v), Infinity),
|
||||
0,
|
||||
assets.map(e => e.x2).reduce((p, v) => Math.max(p, v), -Infinity),
|
||||
assets.map(e => e.y2).reduce((p, v) => Math.max(p, v), -Infinity),
|
||||
assets.map(e => e.aabb.x2).reduce((p, v) => Math.max(p, v), -Infinity),
|
||||
assets.map(e => e.aabb.y2).reduce((p, v) => Math.max(p, v), -Infinity),
|
||||
0
|
||||
]);
|
||||
Selector.#selectionMesh.updateMatrix();
|
||||
|
|
|
|||
Loading…
Reference in New Issue