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 Quadtree from '../physics/quadtree.class';
|
||||||
import { FreeList, clamp } from '../common';
|
import { FreeList, clamp } from '../common';
|
||||||
|
|
||||||
const _position = new Three.Vector3();
|
const _mat = new Three.Matrix4();
|
||||||
const _rotation = new Three.Quaternion();
|
|
||||||
const _euler = new Three.Euler();
|
|
||||||
const _scale = new Three.Vector3();
|
|
||||||
|
|
||||||
export default class Asset
|
export default class Asset
|
||||||
{
|
{
|
||||||
mat: Three.Matrix4;
|
|
||||||
layer: number;
|
|
||||||
selected: boolean = false;
|
selected: boolean = false;
|
||||||
|
|
||||||
//@ts-expect-error
|
#layer: number;
|
||||||
#aabb: AABB;
|
#aabb: AABB;
|
||||||
|
|
||||||
#posX: number;
|
#posX: number;
|
||||||
|
|
@ -23,8 +18,9 @@ export default class Asset
|
||||||
#rot: number;
|
#rot: number;
|
||||||
#scaleX: number;
|
#scaleX: number;
|
||||||
#scaleY: number;
|
#scaleY: number;
|
||||||
#shearX: number;
|
|
||||||
#shearY: number;
|
#sin: number;
|
||||||
|
#cos: number;
|
||||||
|
|
||||||
#index: number;
|
#index: number;
|
||||||
#quad?: 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 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>();
|
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.#posX = posX ?? 0, this.#posY = posY ?? 0, this.#scaleX = scaleX ?? 0, this.#scaleY = scaleY ?? 0;
|
||||||
this.mat = mat ?? new Three.Matrix4();
|
this.#rot = rotation ?? 0, this.#cos = Math.cos(this.#rot), this.#sin = Math.sin(this.#rot);
|
||||||
this.mat.decompose(_position, _rotation, _scale);
|
this.#layer = layer ?? 0;
|
||||||
|
|
||||||
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.#index = Asset.assets.insert(this);
|
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 {
|
get aabb(): AABB {
|
||||||
return this.#aabb;
|
return this.#aabb;
|
||||||
}
|
}
|
||||||
|
get layer(): number {
|
||||||
|
return this.#layer;
|
||||||
|
}
|
||||||
get posX(): number {
|
get posX(): number {
|
||||||
return this.#posX;
|
return this.#posX;
|
||||||
}
|
}
|
||||||
|
|
@ -71,27 +76,6 @@ export default class Asset
|
||||||
get scaleY(): number {
|
get scaleY(): number {
|
||||||
return this.#scaleY;
|
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
|
insert(): Asset
|
||||||
{
|
{
|
||||||
this.#quad = Asset.quadtree.insert(this.#index, this.#aabb);
|
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);
|
this.#quad !== undefined && Asset.quadtree.remove(this.#quad);
|
||||||
Asset.assets.erase(this.#index);
|
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;
|
Asset.instance.instanceMatrix.needsUpdate = true;
|
||||||
|
|
||||||
return this;
|
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;
|
Asset.instance.instanceMatrix.needsUpdate = true;
|
||||||
|
|
||||||
if(quad)
|
if(updateQuad)
|
||||||
{
|
{
|
||||||
this.#quad !== undefined && Asset.quadtree.remove(this.#quad);
|
this.#quad !== undefined && Asset.quadtree.remove(this.#quad);
|
||||||
this.#quad = Asset.quadtree.insert(this.#index, this.#aabb);
|
this.#quad = Asset.quadtree.insert(this.#index, this.#aabb);
|
||||||
|
|
@ -123,83 +106,51 @@ export default class Asset
|
||||||
}
|
}
|
||||||
moveTo(x: number, y: number): 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;
|
this.#posX = x, this.#posY = y;
|
||||||
e[13] = this.#posY = y;
|
|
||||||
|
Asset.instance.instanceMatrix.setComponent(this.#index, 12, x);
|
||||||
|
Asset.instance.instanceMatrix.setComponent(this.#index, 13, y);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
rotateTo(rad: number): Asset
|
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;
|
Asset.instance.instanceMatrix.setComponent(this.#index, 0, this.#cos * this.#scaleX);
|
||||||
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, 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;
|
this.#aabb.x1 = -(this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX;
|
||||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
this.#aabb.x2 = (this.#scaleX * Math.abs(this.#cos) + this.#scaleY * Math.abs(this.#sin)) / 2 + this.#posX;
|
||||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
this.#aabb.y1 = -(this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY;
|
||||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
this.#aabb.y2 = (this.#scaleX * Math.abs(this.#sin) + this.#scaleY * Math.abs(this.#cos)) / 2 + this.#posY;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
matchAABB(aabb: AABB): Asset
|
matchAABB(aabb: AABB): Asset
|
||||||
{
|
{
|
||||||
|
const oldAABB = this.#aabb;
|
||||||
|
|
||||||
this.#aabb = aabb;
|
this.#aabb = aabb;
|
||||||
|
|
||||||
this.#scaleX = aabb.x2 - aabb.x1;
|
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.#scaleY = aabb.y2 - aabb.y1;
|
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;
|
console.log(this.#posX, this.#posY, this.#scaleX, this.#scaleY);
|
||||||
this.#posY = aabb.y1 + this.#scaleY / 2;
|
|
||||||
|
|
||||||
const e = this.mat.elements;
|
Asset.instance.instanceMatrix.setComponent(this.#index, 0, this.#cos * this.#scaleX);
|
||||||
const cos = Math.cos(this.#rot), sin = Math.sin(this.#rot);
|
Asset.instance.instanceMatrix.setComponent(this.#index, 1, this.#sin * this.#scaleX);
|
||||||
|
Asset.instance.instanceMatrix.setComponent(this.#index, 4, -this.#sin * this.#scaleY);
|
||||||
e[0] = cos * this.#scaleX + -sin * this.#shearY;
|
Asset.instance.instanceMatrix.setComponent(this.#index, 5, this.#cos * this.#scaleY);
|
||||||
e[1] = sin * this.#scaleX + cos * this.#shearX;
|
Asset.instance.instanceMatrix.setComponent(this.#index, 12, this.#posX);
|
||||||
e[4] = cos * this.#shearX + -sin * this.#scaleY;
|
Asset.instance.instanceMatrix.setComponent(this.#index, 13, this.#posY);
|
||||||
e[5] = sin * this.#shearX + cos * this.#scaleY;
|
|
||||||
|
|
||||||
e[12] = this.#posX;
|
|
||||||
e[13] = this.#posY;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/main.ts
19
src/main.ts
|
|
@ -18,23 +18,12 @@ Selector.init();
|
||||||
const r = new Random(0);
|
const r = new Random(0);
|
||||||
let dragMode = DragMode.pan, dragFrom: number | undefined;
|
let dragMode = DragMode.pan, dragFrom: number | undefined;
|
||||||
|
|
||||||
/*for(let i = 0; i < 10; i++)
|
new Asset(0, 0, 20, 10, -Math.PI / 4).update();
|
||||||
{
|
|
||||||
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();
|
|
||||||
|
|
||||||
window.Selector = Selector;
|
window.Selector = Selector;
|
||||||
|
|
||||||
Asset.instance.count = Asset.assets.length;
|
Asset.instance.count = Asset.assets.length;
|
||||||
|
Asset.instance.frustumCulled = false;
|
||||||
Asset.instance.computeBoundingBox();
|
|
||||||
Asset.instance.computeBoundingSphere();
|
|
||||||
|
|
||||||
Renderer.scene.add(Asset.instance);
|
Renderer.scene.add(Asset.instance);
|
||||||
|
|
||||||
|
|
@ -63,9 +52,7 @@ Input.onDragStart((s, button) => {
|
||||||
Input.onDragEnd((s, e, _) => {
|
Input.onDragEnd((s, e, _) => {
|
||||||
if(dragMode === DragMode.select)
|
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));
|
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);
|
if(Input.keys['shift']) Selector.toggle(selection);
|
||||||
else Selector.select(selection);
|
else Selector.select(selection);
|
||||||
|
|
@ -86,7 +73,7 @@ Input.onDrag((delta, start, end, _) => {
|
||||||
}
|
}
|
||||||
else if (dragMode === DragMode.rotate && Selector.selected)
|
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)
|
else if (dragMode === DragMode.scale && Selector.selected)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -238,10 +238,7 @@ export default class Selector
|
||||||
static move(x: number, y: number): void
|
static move(x: number, y: number): void
|
||||||
{
|
{
|
||||||
Selector.selection.forEach(e => e.moveTo(e.posX + x, e.posY + y).update(false));
|
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.#selectionMesh.box.translate(_vector.set(x, y, 0));
|
||||||
Selector.#ghostMesh.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[2].position.add({ x: x, y: y, z: 0 });
|
||||||
Selector.gizmoScale[3].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 centerX = Selector.gizmoScale[0].position.x + (Selector.gizmoScale[3].position.x - Selector.gizmoScale[0].position.x) / 2,
|
||||||
const rad = Math.atan2(-_vector.y, _vector.x);
|
centerY = Selector.gizmoScale[0].position.y + (Selector.gizmoScale[3].position.y - Selector.gizmoScale[0].position.y) / 2;
|
||||||
Selector.selection.forEach(e => e.rotateTo(e.rot + rad).update(false));
|
|
||||||
|
|
||||||
Asset.instance.computeBoundingBox();
|
startX -= centerX;
|
||||||
Asset.instance.computeBoundingSphere();
|
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
|
static scale(dragFrom: number, x: number, y: number): void
|
||||||
{
|
{
|
||||||
|
|
@ -274,9 +275,6 @@ export default class Selector
|
||||||
e.matchAABB(aabb).update(false);
|
e.matchAABB(aabb).update(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Asset.instance.computeBoundingBox();
|
|
||||||
Asset.instance.computeBoundingSphere();
|
|
||||||
|
|
||||||
Selector.#selectionMesh.box.setFromPoints([Selector.gizmoScale[0].position, Selector.gizmoScale[3].position]);
|
Selector.#selectionMesh.box.setFromPoints([Selector.gizmoScale[0].position, Selector.gizmoScale[3].position]);
|
||||||
Selector.#ghostMesh.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