Fix rotation, change matrix update implementation
This commit is contained in:
parent
6f7a8cc3d2
commit
9cf5ccaf81
|
|
@ -4,18 +4,13 @@ import { AABB } from '../physics/common';
|
|||
import Quadtree from '../physics/quadtree.class';
|
||||
import { FreeList, clamp } from '../common';
|
||||
|
||||
const _position = new Three.Vector3();
|
||||
const _rotation = new Three.Quaternion();
|
||||
const _euler = new Three.Euler();
|
||||
const _scale = new Three.Vector3();
|
||||
const _mat = new Three.Matrix4();
|
||||
|
||||
export default class Asset
|
||||
{
|
||||
mat: Three.Matrix4;
|
||||
layer: number;
|
||||
selected: boolean = false;
|
||||
|
||||
//@ts-expect-error
|
||||
#layer: number;
|
||||
#aabb: AABB;
|
||||
|
||||
#posX: number;
|
||||
|
|
@ -23,8 +18,9 @@ export default class Asset
|
|||
#rot: number;
|
||||
#scaleX: number;
|
||||
#scaleY: number;
|
||||
#shearX: number;
|
||||
#shearY: number;
|
||||
|
||||
#sin: number;
|
||||
#cos: number;
|
||||
|
||||
#index: number;
|
||||
#quad?: number;
|
||||
|
|
@ -33,29 +29,38 @@ export default class Asset
|
|||
static quadtree: Quadtree = new Quadtree({ x1: -CONST.RESOLUTION_X / 2, x2: CONST.RESOLUTION_X / 2, y1: -CONST.RESOLUTION_Y / 2, y2: CONST.RESOLUTION_Y / 2 }, 6, 10);
|
||||
static assets: FreeList<Asset> = new FreeList<Asset>();
|
||||
|
||||
constructor(mat?: Three.Matrix4, layer?: number)
|
||||
constructor(posX?: number, posY?: number, scaleX?: number, scaleY?: number, rotation?: number, layer?: number)
|
||||
{
|
||||
//TODO: Remake the value computation to include shear determination
|
||||
this.mat = mat ?? new Three.Matrix4();
|
||||
this.mat.decompose(_position, _rotation, _scale);
|
||||
|
||||
this.#posX = _position.x;
|
||||
this.#posY = _position.y;
|
||||
this.#rot = _euler.setFromQuaternion(_rotation).z;
|
||||
this.#scaleX = _scale.x;
|
||||
this.#scaleY = _scale.y;
|
||||
|
||||
this.#shearX = 0;
|
||||
this.#shearY = 0;
|
||||
|
||||
this.#updateAABB();
|
||||
this.layer = layer ?? 0;
|
||||
this.#posX = posX ?? 0, this.#posY = posY ?? 0, this.#scaleX = scaleX ?? 0, this.#scaleY = scaleY ?? 0;
|
||||
this.#rot = rotation ?? 0, this.#cos = Math.cos(this.#rot), this.#sin = Math.sin(this.#rot);
|
||||
this.#layer = layer ?? 0;
|
||||
|
||||
this.#index = Asset.assets.insert(this);
|
||||
|
||||
console.log(this);
|
||||
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 0, this.#cos * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 1, this.#sin * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 4, -this.#sin * this.#scaleY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 5, this.#cos * this.#scaleY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 12, this.#posX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 13, this.#posY);
|
||||
Asset.instance.instanceMatrix.addUpdateRange(this.#index * 16, 16);
|
||||
Asset.instance.instanceMatrix.needsUpdate = true;
|
||||
|
||||
this.#aabb = {
|
||||
x1: -(this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX,
|
||||
x2: (this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX,
|
||||
y1: -(this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY,
|
||||
y2: (this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY,
|
||||
}
|
||||
}
|
||||
get aabb(): AABB {
|
||||
return this.#aabb;
|
||||
}
|
||||
get layer(): number {
|
||||
return this.#layer;
|
||||
}
|
||||
get posX(): number {
|
||||
return this.#posX;
|
||||
}
|
||||
|
|
@ -71,27 +76,6 @@ export default class Asset
|
|||
get scaleY(): number {
|
||||
return this.#scaleY;
|
||||
}
|
||||
#updateAABB(): void {
|
||||
const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 };
|
||||
|
||||
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)
|
||||
};
|
||||
}
|
||||
insert(): Asset
|
||||
{
|
||||
this.#quad = Asset.quadtree.insert(this.#index, this.#aabb);
|
||||
|
|
@ -102,18 +86,17 @@ export default class Asset
|
|||
{
|
||||
this.#quad !== undefined && Asset.quadtree.remove(this.#quad);
|
||||
Asset.assets.erase(this.#index);
|
||||
Asset.instance.setMatrixAt(this.#index, this.mat.identity());
|
||||
Asset.instance.setMatrixAt(this.#index, _mat);
|
||||
Asset.instance.instanceMatrix.addUpdateRange(this.#index * 16, 16);
|
||||
Asset.instance.instanceMatrix.needsUpdate = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
update(quad: boolean = true): Asset
|
||||
update(updateQuad: boolean = true): Asset
|
||||
{
|
||||
this.#updateAABB();
|
||||
Asset.instance.setMatrixAt(this.#index, this.mat);
|
||||
Asset.instance.instanceMatrix.needsUpdate = true;
|
||||
|
||||
if(quad)
|
||||
if(updateQuad)
|
||||
{
|
||||
this.#quad !== undefined && Asset.quadtree.remove(this.#quad);
|
||||
this.#quad = Asset.quadtree.insert(this.#index, this.#aabb);
|
||||
|
|
@ -123,83 +106,51 @@ export default class Asset
|
|||
}
|
||||
moveTo(x: number, y: number): Asset
|
||||
{
|
||||
const e = this.mat.elements;
|
||||
this.#aabb.x1 -= this.#posX - x;
|
||||
this.#aabb.x2 -= this.#posX - x;
|
||||
this.#aabb.y1 -= this.#posY - y;
|
||||
this.#aabb.y2 -= this.#posY - y;
|
||||
|
||||
e[12] = this.#posX = x;
|
||||
e[13] = this.#posY = y;
|
||||
this.#posX = x, this.#posY = y;
|
||||
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 12, x);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 13, y);
|
||||
|
||||
return this;
|
||||
}
|
||||
rotateTo(rad: number): Asset
|
||||
{
|
||||
this.#rot = rad % (Math.PI * 2);
|
||||
this.#rot = (rad + Math.PI) % (2*Math.PI) - Math.PI, this.#cos = Math.cos(this.#rot), this.#sin = Math.sin(this.#rot);
|
||||
|
||||
const e = this.mat.elements;
|
||||
const cos = Math.cos(rad), sin = Math.sin(rad), tanX = Math.tan(this.#shearX), tanY = Math.tan(this.#shearY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 0, this.#cos * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 1, this.#sin * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 4, -this.#sin * this.#scaleY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 5, this.#cos * this.#scaleY);
|
||||
|
||||
e[0] = cos * this.#scaleX + -sin * this.#shearY;
|
||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
||||
|
||||
return this;
|
||||
}
|
||||
scaleTo(x: number, y: number): Asset
|
||||
{
|
||||
x = clamp(x, 0.1, CONST.RESOLUTION_X);
|
||||
y = clamp(y, 0.1, CONST.RESOLUTION_Y);
|
||||
|
||||
this.#scaleX = x;
|
||||
this.#scaleY = y;
|
||||
|
||||
const e = this.mat.elements;
|
||||
const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot);
|
||||
|
||||
e[0] = cos * this.#scaleX + -sin * this.#shearY;
|
||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
||||
|
||||
return this;
|
||||
}
|
||||
shearTo(x: number, y: number): Asset
|
||||
{
|
||||
x = clamp(x, 0.1, CONST.RESOLUTION_X);
|
||||
y = clamp(y, 0.1, CONST.RESOLUTION_Y);
|
||||
|
||||
this.#shearX = x;
|
||||
this.#shearY = y;
|
||||
|
||||
const e = this.mat.elements;
|
||||
const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot);
|
||||
|
||||
e[0] = cos * this.#scaleX + -sin * this.#shearY;
|
||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
||||
this.#aabb.x1 = -(this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX;
|
||||
this.#aabb.x2 = (this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX;
|
||||
this.#aabb.y1 = -(this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY;
|
||||
this.#aabb.y2 = (this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY;
|
||||
|
||||
return this;
|
||||
}
|
||||
matchAABB(aabb: AABB): Asset
|
||||
{
|
||||
const oldAABB = this.#aabb;
|
||||
|
||||
this.#aabb = aabb;
|
||||
|
||||
this.#scaleX = aabb.x2 - aabb.x1;
|
||||
this.#scaleY = aabb.y2 - aabb.y1;
|
||||
this.#posX = this.#aabb.x1 + (this.#aabb.x2 - this.#aabb.x1) / 2, this.#posY = this.#aabb.y1 + (this.#aabb.y2 - this.#aabb.y1) / 2;
|
||||
this.#scaleX *= (this.#aabb.x2 - this.#aabb.x1) / (oldAABB.x2 - oldAABB.x1), this.#scaleY *= (this.#aabb.y2 - this.#aabb.y1) / (oldAABB.y2 - oldAABB.y1);
|
||||
|
||||
this.#posX = aabb.x1 + this.#scaleX / 2;
|
||||
this.#posY = aabb.y1 + this.#scaleY / 2;
|
||||
console.log(this.#posX, this.#posY, this.#scaleX, this.#scaleY);
|
||||
|
||||
const e = this.mat.elements;
|
||||
const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot);
|
||||
|
||||
e[0] = cos * this.#scaleX + -sin * this.#shearY;
|
||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
||||
|
||||
e[12] = this.#posX;
|
||||
e[13] = this.#posY;
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 0, this.#cos * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 1, this.#sin * this.#scaleX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 4, -this.#sin * this.#scaleY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 5, this.#cos * this.#scaleY);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 12, this.#posX);
|
||||
Asset.instance.instanceMatrix.setComponent(this.#index, 13, this.#posY);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
19
src/main.ts
19
src/main.ts
|
|
@ -18,23 +18,12 @@ Selector.init();
|
|||
const r = new Random(0);
|
||||
let dragMode = DragMode.pan, dragFrom: number | undefined;
|
||||
|
||||
/*for(let i = 0; i < 10; i++)
|
||||
{
|
||||
new Asset(new THREE.Matrix4(), 1).rotateTo(r.nextFloat(Math.PI * 2))
|
||||
.scaleTo(r.nextFloat(10, 30), r.nextFloat(10, 30))
|
||||
.moveTo(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y))
|
||||
.update();
|
||||
}*/
|
||||
window.asset = new Asset().moveTo(0, 0).rotateTo(Math.PI / 3).scaleTo(20, 20).update();
|
||||
new Asset().moveTo(40, 0).rotateTo(0).scaleTo(20, 20).update();
|
||||
new Asset().moveTo(-40, 0).rotateTo(0).scaleTo(20, 20).update();
|
||||
new Asset(0, 0, 20, 10, -Math.PI / 4).update();
|
||||
|
||||
window.Selector = Selector;
|
||||
|
||||
Asset.instance.count = Asset.assets.length;
|
||||
|
||||
Asset.instance.computeBoundingBox();
|
||||
Asset.instance.computeBoundingSphere();
|
||||
Asset.instance.frustumCulled = false;
|
||||
|
||||
Renderer.scene.add(Asset.instance);
|
||||
|
||||
|
|
@ -63,9 +52,7 @@ Input.onDragStart((s, button) => {
|
|||
Input.onDragEnd((s, e, _) => {
|
||||
if(dragMode === DragMode.select)
|
||||
{
|
||||
const n = performance.now();
|
||||
const selection = Asset.quadtree.query({x1: Math.min(s.x, e.x), x2: Math.max(s.x, e.x), y1: Math.min(s.y, e.y), y2: Math.max(s.y, e.y)}).map(e => Asset.assets.get(e));
|
||||
console.log("Fetching %s out of %s elements in %sms", selection.length, Asset.assets.length, performance.now() - n);
|
||||
|
||||
if(Input.keys['shift']) Selector.toggle(selection);
|
||||
else Selector.select(selection);
|
||||
|
|
@ -86,7 +73,7 @@ Input.onDrag((delta, start, end, _) => {
|
|||
}
|
||||
else if (dragMode === DragMode.rotate && Selector.selected)
|
||||
{
|
||||
Selector.rotate(delta.x, delta.y);
|
||||
Selector.rotate(end.x - delta.x, end.y - delta.y, end.x, end.y);
|
||||
}
|
||||
else if (dragMode === DragMode.scale && Selector.selected)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -238,10 +238,7 @@ export default class Selector
|
|||
static move(x: number, y: number): void
|
||||
{
|
||||
Selector.selection.forEach(e => e.moveTo(e.posX + x, e.posY + y).update(false));
|
||||
|
||||
Asset.instance.computeBoundingBox();
|
||||
Asset.instance.computeBoundingSphere();
|
||||
|
||||
|
||||
Selector.#selectionMesh.box.translate(_vector.set(x, y, 0));
|
||||
Selector.#ghostMesh.box.translate(_vector.set(x, y, 0));
|
||||
|
||||
|
|
@ -250,14 +247,18 @@ export default class Selector
|
|||
Selector.gizmoScale[2].position.add({ x: x, y: y, z: 0 });
|
||||
Selector.gizmoScale[3].position.add({ x: x, y: y, z: 0 });
|
||||
}
|
||||
static rotate(x: number, y: number): void
|
||||
static rotate(startX: number, startY: number, endX: number, endY: number): void
|
||||
{
|
||||
_vector.set(x, y, 0).normalize()
|
||||
const rad = Math.atan2(-_vector.y, _vector.x);
|
||||
Selector.selection.forEach(e => e.rotateTo(e.rot + rad).update(false));
|
||||
const centerX = Selector.gizmoScale[0].position.x + (Selector.gizmoScale[3].position.x - Selector.gizmoScale[0].position.x) / 2,
|
||||
centerY = Selector.gizmoScale[0].position.y + (Selector.gizmoScale[3].position.y - Selector.gizmoScale[0].position.y) / 2;
|
||||
|
||||
Asset.instance.computeBoundingBox();
|
||||
Asset.instance.computeBoundingSphere();
|
||||
startX -= centerX;
|
||||
startY -= centerY;
|
||||
endX -= centerX;
|
||||
endY -= centerY;
|
||||
|
||||
const rad = Math.atan2(startX*endY-startY*endX,startX*endX+startY*endY);
|
||||
Selector.selection.forEach(e => e.rotateTo(e.rot + rad).update(false));
|
||||
}
|
||||
static scale(dragFrom: number, x: number, y: number): void
|
||||
{
|
||||
|
|
@ -274,9 +275,6 @@ export default class Selector
|
|||
e.matchAABB(aabb).update(false);
|
||||
});
|
||||
|
||||
Asset.instance.computeBoundingBox();
|
||||
Asset.instance.computeBoundingSphere();
|
||||
|
||||
Selector.#selectionMesh.box.setFromPoints([Selector.gizmoScale[0].position, Selector.gizmoScale[3].position]);
|
||||
Selector.#ghostMesh.box.setFromPoints([Selector.gizmoScale[0].position, Selector.gizmoScale[3].position]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue