Working on transform gizmo
This commit is contained in:
parent
8f0100c466
commit
c01f4bd8c6
|
|
@ -4,7 +4,7 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bunx --bun vite",
|
"dev": "bunx --bun vite --port 3000 --cors",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/three": "^0.165.0",
|
"@types/three": "^0.165.0",
|
||||||
"stats.js": "^0.17.0",
|
"stats.js": "^0.17.0",
|
||||||
"three": "^0.165.0",
|
"three": "^0.165.0"
|
||||||
"three-mesh-bvh": "^0.7.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@ export default class Asset
|
||||||
//@ts-expect-error
|
//@ts-expect-error
|
||||||
#aabb: AABB;
|
#aabb: AABB;
|
||||||
|
|
||||||
|
#posX: number;
|
||||||
|
#posY: number;
|
||||||
|
#rot: number;
|
||||||
|
#scaleX: number;
|
||||||
|
#scaleY: number;
|
||||||
|
|
||||||
#index: number;
|
#index: number;
|
||||||
#quad?: number;
|
#quad?: number;
|
||||||
|
|
||||||
|
|
@ -27,6 +33,14 @@ export default class Asset
|
||||||
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.mat.decompose(_position, _rotation, _scale);
|
||||||
|
|
||||||
|
this.#posX = _position.x;
|
||||||
|
this.#posY = _position.y;
|
||||||
|
this.#rot = _euler.setFromQuaternion(_rotation).z;
|
||||||
|
this.#scaleX = _position.x;
|
||||||
|
this.#scaleY = _position.y;
|
||||||
|
|
||||||
this.#updateAABB();
|
this.#updateAABB();
|
||||||
this.layer = layer ?? 0;
|
this.layer = layer ?? 0;
|
||||||
|
|
||||||
|
|
@ -36,14 +50,6 @@ export default class Asset
|
||||||
{
|
{
|
||||||
return this.#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 {
|
#updateAABB(): void {
|
||||||
const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 };
|
const aabb = { x1: -0.5, x2: 0.5, y1: -0.5, y2: 0.5 };
|
||||||
|
|
||||||
|
|
@ -65,89 +71,53 @@ export default class Asset
|
||||||
y2: Math.max(y1, y2, y3, y4)
|
y2: Math.max(y1, y2, y3, y4)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
move(x: number, y: number): Asset
|
insert(quad: Quadtree): void
|
||||||
{
|
{
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
this.#quad = quad.insert(this.#index, this.#aabb);
|
||||||
|
}
|
||||||
_position.x += x;
|
remove(quad: Quadtree): void
|
||||||
_position.y += y;
|
{
|
||||||
|
this.#quad !== undefined && quad.remove(this.#quad);
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
this.#updateAABB();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
moveTo(x: number, y: number): Asset
|
moveTo(x: number, y: number): Asset
|
||||||
{
|
{
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
const e = this.mat.elements;
|
||||||
|
|
||||||
_position.x = x;
|
e[12] = this.#posX = x;
|
||||||
_position.y = y;
|
e[13] = this.#posY = y;
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
this.#updateAABB();
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
rotate(rad: number): Asset
|
|
||||||
{
|
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
_euler.setFromQuaternion(_rotation);
|
|
||||||
_euler.z += rad;
|
|
||||||
_rotation.setFromEuler(_euler);
|
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
this.#updateAABB();
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
rotateTo(rad: number): Asset
|
rotateTo(rad: number): Asset
|
||||||
{
|
{
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
this.#rot = rad;
|
||||||
|
|
||||||
_euler.setFromQuaternion(_rotation);
|
const e = this.mat.elements;
|
||||||
_euler.z = rad;
|
const cos = Math.cos(rad), sin = Math.sin(rad);
|
||||||
_rotation.setFromEuler(_euler);
|
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
e[0] = cos * this.#scaleX;
|
||||||
|
e[1] = -sin * this.#scaleX;
|
||||||
|
e[4] = sin * this.#scaleY;
|
||||||
|
e[5] = cos * this.#scaleY;
|
||||||
|
|
||||||
this.#updateAABB();
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
scale(x: number, y: number): Asset
|
|
||||||
{
|
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
_scale.x *= x;
|
|
||||||
_scale.y *= y;
|
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
|
||||||
|
|
||||||
this.#updateAABB();
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
scaleTo(x: number, y: number): Asset
|
scaleTo(x: number, y: number): Asset
|
||||||
{
|
{
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
this.#scaleX = x;
|
||||||
|
this.#scaleY = y;
|
||||||
|
|
||||||
_scale.x = x;
|
const e = this.mat.elements;
|
||||||
_scale.y = y;
|
const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot);
|
||||||
|
|
||||||
this.mat.compose(_position, _rotation, _scale);
|
e[0] = cos * this.#scaleX;
|
||||||
|
e[1] = -sin * this.#scaleX;
|
||||||
|
e[4] = sin * this.#scaleY;
|
||||||
|
e[5] = cos * this.#scaleY;
|
||||||
|
|
||||||
this.#updateAABB();
|
this.#updateAABB();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
shapeTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): Asset
|
|
||||||
{
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,13 +14,14 @@ Selector.init();
|
||||||
const r = new Random(0);
|
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: -RESOLUTION_X / 2, x2: RESOLUTION_X / 2, y1: -RESOLUTION_Y / 2, y2: RESOLUTION_Y / 2 }, 6, 10);
|
||||||
|
|
||||||
for(let i = 0; i < 10000; i++)
|
for(let i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
const asset = new Asset(new THREE.Matrix4(), 1);
|
const asset = new Asset(new THREE.Matrix4(), 1);
|
||||||
|
|
||||||
asset.move(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y))
|
asset
|
||||||
.rotate(r.nextFloat(Math.PI * 2))
|
.rotateTo(r.nextFloat(Math.PI * 2))
|
||||||
.scale(r.nextFloat(10, 30), r.nextFloat(10, 30));
|
.scaleTo(r.nextFloat(100, 300), r.nextFloat(100, 300))
|
||||||
|
.moveTo(r.nextInt(-0.5 * RESOLUTION_X, 0.5 * RESOLUTION_X), r.nextInt(-0.5 * RESOLUTION_Y, 0.5 * RESOLUTION_Y));
|
||||||
|
|
||||||
Asset.instance.setMatrixAt(i, asset.mat);
|
Asset.instance.setMatrixAt(i, asset.mat);
|
||||||
asset.insert(quad);
|
asset.insert(quad);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import * as Three from 'three';
|
||||||
import { RESOLUTION_X, RESOLUTION_Y } from '../consts';
|
import { RESOLUTION_X, RESOLUTION_Y } from '../consts';
|
||||||
import Stats from 'stats.js';
|
import Stats from 'stats.js';
|
||||||
import { Point } from '../physics/common';
|
import { Point } from '../physics/common';
|
||||||
|
import Selector from './selector.class';
|
||||||
|
|
||||||
export default class Renderer
|
export default class Renderer
|
||||||
{
|
{
|
||||||
|
|
@ -84,6 +85,7 @@ export default class Renderer
|
||||||
static render(delta?: number): void
|
static render(delta?: number): void
|
||||||
{
|
{
|
||||||
this.#stats.begin();
|
this.#stats.begin();
|
||||||
|
Selector.update();
|
||||||
this.renderer.render(this.scene, this.camera);
|
this.renderer.render(this.scene, this.camera);
|
||||||
this.#stats.end();
|
this.#stats.end();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,20 @@ import * as Three from "three";
|
||||||
import Asset from "../assets/asset.class";
|
import Asset from "../assets/asset.class";
|
||||||
import { Point } from "../physics/common";
|
import { Point } from "../physics/common";
|
||||||
import Renderer from "./renderer.class";
|
import Renderer from "./renderer.class";
|
||||||
|
import { QUAD } from '../consts';
|
||||||
|
|
||||||
export default class Selector
|
export default class Selector
|
||||||
{
|
{
|
||||||
static #assets: Asset[];
|
static #assets: Asset[];
|
||||||
static #selected: boolean = false;
|
static #selected: boolean = false;
|
||||||
|
static #previousZoom: number = 1;
|
||||||
|
|
||||||
static #previewMesh: Three.Box3Helper;
|
static #previewMesh: Three.Box3Helper;
|
||||||
static #ghostMesh: Three.Box3Helper;
|
static #ghostMesh: Three.Box3Helper;
|
||||||
static #selectionMesh: Three.Box3Helper;
|
static #selectionMesh: Three.Box3Helper;
|
||||||
|
|
||||||
|
static gizmoScale: Three.Mesh[];
|
||||||
|
|
||||||
static get selected(): boolean
|
static get selected(): boolean
|
||||||
{
|
{
|
||||||
return Selector.#selected;
|
return Selector.#selected;
|
||||||
|
|
@ -26,10 +30,31 @@ export default class Selector
|
||||||
Selector.#ghostMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff);
|
Selector.#ghostMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff);
|
||||||
Selector.#selectionMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff);
|
Selector.#selectionMesh = new Three.Box3Helper(new Three.Box3(), 0xffffff);
|
||||||
|
|
||||||
|
Selector.gizmoScale = [];
|
||||||
|
Selector.gizmoScale[0] = new Three.Mesh(QUAD, new Three.MeshBasicMaterial({ depthTest: false, depthWrite: false, fog: false, toneMapped: false, transparent: true, color: 0x3498DB, opacity: 0.5 }));
|
||||||
|
Selector.gizmoScale[1] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material);
|
||||||
|
Selector.gizmoScale[2] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material);
|
||||||
|
Selector.gizmoScale[3] = new Three.Mesh(QUAD, Selector.gizmoScale[0].material);
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].renderOrder = Infinity;
|
||||||
|
Selector.gizmoScale[1].renderOrder = Infinity;
|
||||||
|
Selector.gizmoScale[2].renderOrder = Infinity;
|
||||||
|
Selector.gizmoScale[3].renderOrder = Infinity;
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].name = "Gizmo for scale (TL)";
|
||||||
|
Selector.gizmoScale[1].name = "Gizmo for scale (TR)";
|
||||||
|
Selector.gizmoScale[2].name = "Gizmo for scale (BL)";
|
||||||
|
Selector.gizmoScale[3].name = "Gizmo for scale (BR)";
|
||||||
|
|
||||||
Renderer.scene.add(Selector.#previewMesh);
|
Renderer.scene.add(Selector.#previewMesh);
|
||||||
Renderer.scene.add(Selector.#ghostMesh);
|
Renderer.scene.add(Selector.#ghostMesh);
|
||||||
Renderer.scene.add(Selector.#selectionMesh);
|
Renderer.scene.add(Selector.#selectionMesh);
|
||||||
|
|
||||||
|
Renderer.scene.add(Selector.gizmoScale[0]);
|
||||||
|
Renderer.scene.add(Selector.gizmoScale[1]);
|
||||||
|
Renderer.scene.add(Selector.gizmoScale[2]);
|
||||||
|
Renderer.scene.add(Selector.gizmoScale[3]);
|
||||||
|
|
||||||
Selector.hide();
|
Selector.hide();
|
||||||
}
|
}
|
||||||
static preview(start: Point, end: Point): void
|
static preview(start: Point, end: Point): void
|
||||||
|
|
@ -64,16 +89,35 @@ export default class Selector
|
||||||
|
|
||||||
Selector.#selected = true;
|
Selector.#selected = true;
|
||||||
|
|
||||||
Selector.#selectionMesh.box.setFromArray([
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||||
assets.map(e => e.aabb.x1).reduce((p, v) => Math.min(p, v), Infinity),
|
for (let i = 0; i < assets.length; i++)
|
||||||
assets.map(e => e.aabb.y1).reduce((p, v) => Math.min(p, v), Infinity),
|
{
|
||||||
0,
|
minX = Math.min(minX, assets[i].aabb.x1);
|
||||||
assets.map(e => e.aabb.x2).reduce((p, v) => Math.max(p, v), -Infinity),
|
minY = Math.min(minY, assets[i].aabb.y1);
|
||||||
assets.map(e => e.aabb.y2).reduce((p, v) => Math.max(p, v), -Infinity),
|
maxX = Math.max(maxX, assets[i].aabb.x2);
|
||||||
0
|
maxY = Math.max(maxY, assets[i].aabb.y2);
|
||||||
]);
|
}
|
||||||
|
|
||||||
|
const scale = Math.max((maxX - minX) / 2, (maxY - minY) / 2)
|
||||||
|
|
||||||
|
Selector.#selectionMesh.box.setFromArray([minX, minY, 0, maxX, maxY, 0]);
|
||||||
Selector.#selectionMesh.updateMatrix();
|
Selector.#selectionMesh.updateMatrix();
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].position.set(minX, minY, 0);
|
||||||
|
Selector.gizmoScale[1].position.set(maxX, minY, 0);
|
||||||
|
Selector.gizmoScale[2].position.set(minX, maxY, 0);
|
||||||
|
Selector.gizmoScale[3].position.set(maxX, maxY, 0);
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[1].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[2].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[3].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].visible = true;
|
||||||
|
Selector.gizmoScale[1].visible = true;
|
||||||
|
Selector.gizmoScale[2].visible = true;
|
||||||
|
Selector.gizmoScale[3].visible = true;
|
||||||
|
|
||||||
Selector.#selectionMesh.visible = true;
|
Selector.#selectionMesh.visible = true;
|
||||||
}
|
}
|
||||||
static toggle(assets: Asset[]): void
|
static toggle(assets: Asset[]): void
|
||||||
|
|
@ -100,5 +144,22 @@ export default class Selector
|
||||||
Selector.#previewMesh.visible = false;
|
Selector.#previewMesh.visible = false;
|
||||||
Selector.#ghostMesh.visible = false;
|
Selector.#ghostMesh.visible = false;
|
||||||
Selector.#selectionMesh.visible = false;
|
Selector.#selectionMesh.visible = false;
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].visible = false;
|
||||||
|
Selector.gizmoScale[1].visible = false;
|
||||||
|
Selector.gizmoScale[2].visible = false;
|
||||||
|
Selector.gizmoScale[3].visible = false;
|
||||||
|
}
|
||||||
|
static update(): void
|
||||||
|
{
|
||||||
|
if (Selector.#previousZoom !== Renderer.zoom && Selector.#selected)
|
||||||
|
{
|
||||||
|
Selector.#previousZoom = Renderer.zoom;
|
||||||
|
|
||||||
|
Selector.gizmoScale[0].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[1].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[2].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
Selector.gizmoScale[3].scale.set(20 / Renderer.zoom, 20 / Renderer.zoom, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue