From 4e3d25c27a07a71b8346587d00b22c68b245eff5 Mon Sep 17 00:00:00 2001 From: Aigars Zeiza Date: Fri, 4 Jul 2025 20:04:42 +0300 Subject: [PATCH] nested entity relative scaling --- sandbox/nestedEntities/nestedEntities.html | 25 ++++++ sandbox/nestedEntities/nestedEntities.js | 98 ++++++++++++++++++++++ src/entity/Entity.ts | 24 +++--- 3 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 sandbox/nestedEntities/nestedEntities.html create mode 100644 sandbox/nestedEntities/nestedEntities.js diff --git a/sandbox/nestedEntities/nestedEntities.html b/sandbox/nestedEntities/nestedEntities.html new file mode 100644 index 00000000..e30de16c --- /dev/null +++ b/sandbox/nestedEntities/nestedEntities.html @@ -0,0 +1,25 @@ + + + Draco loader sample + + + + + + + + + +
+ +
+ + diff --git a/sandbox/nestedEntities/nestedEntities.js b/sandbox/nestedEntities/nestedEntities.js new file mode 100644 index 00000000..f0c9f93d --- /dev/null +++ b/sandbox/nestedEntities/nestedEntities.js @@ -0,0 +1,98 @@ +/* eslint-disable no-undef */ +import { + control, + Entity, + Object3d, + Renderer, + Vec3, + Mat4, + RenderNode, + EntityCollection, + scene, +} from "../../lib/og.es.js"; + +let renderer = new Renderer("frame", { + msaa: 8, + controls: [new control.SimpleNavigation({ speed: 0.01 }), new control.GeoObjectEditor()], + autoActivate: true +}); + +class MyScene extends RenderNode { + constructor() { + super("MyScene"); + } + + init() { + const baseObj = Object3d.createCube(0.4, 2, 0.4).translate(new Vec3(0, 1, 0)).setMaterial({ + ambient: "#882a2a", + diffuse: "#fb3434", + shininess: 1 + }); + + const frustumObj = Object3d.createFrustum(3, 2, 1).setMaterial({ + ambient: "#236028", + diffuse: "#1cdd23", + shininess: 1 + }); + + const cylinderObj = Object3d.createCylinder(1, 0, 1) + .applyMat4(new Mat4().setRotation(new Vec3(1, 0, 0), (90 * Math.PI) / 180)) + .setMaterial({ + ambient: "#773381", + diffuse: "#ef00ff", + shininess: 1 + }); + + let parentEntity = new Entity({ + cartesian: new Vec3(0, 0, 0), + independentPicking: true, + geoObject: { + color: "rgb(90,90,90)", + scale: 1, + instanced: true, + tag: `baseObj`, + object3d: baseObj + } + }); + + let childEntity = new Entity({ + cartesian: new Vec3(0, 1, 0), + independentPicking: true, + relativePosition: true, + geoObject: { + color: "rgb(90,90,90)", + instanced: true, + tag: `frustumObj`, + object3d: frustumObj + } + }); + + let childChildEntity = new Entity({ + cartesian: new Vec3(0, 3, -1), + independentPicking: true, + relativePosition: true, + geoObject: { + color: "rgb(90,90,90)", + instanced: true, + tag: `cylinderObj`, + object3d: cylinderObj + } + }); + + childEntity.appendChild(childChildEntity); + parentEntity.appendChild(childEntity); + + let collection = new EntityCollection({ + entities: [parentEntity] + }); + + collection.addTo(this); + + this.renderer.activeCamera.set(new Vec3(-4, 11, 13), new Vec3(1, 0, 0)); + + this.renderer.activeCamera.update(); + } +} + +renderer.addNodes([new scene.Axes(), new MyScene()]); + diff --git a/src/entity/Entity.ts b/src/entity/Entity.ts index 85fa40c8..c1b37e24 100644 --- a/src/entity/Entity.ts +++ b/src/entity/Entity.ts @@ -299,6 +299,7 @@ class Entity { protected _yawRad: number; protected _rollRad: number; protected _scale: Vec3; + protected _absoluteScale: Vec3; protected _qFrame: Quat; protected _qRot: Quat; public _absoluteQRot: Quat; @@ -357,6 +358,7 @@ class Entity { this._rollRad = options.roll || 0; this._scale = utils.createVector3(options.scale, new Vec3(1, 1, 1)); + this._absoluteScale = new Vec3(); this._qFrame = Quat.IDENTITY; this._qRot = Quat.IDENTITY; @@ -596,11 +598,8 @@ class Entity { * @param {Vec3} scale - Scale factor */ public setScale3v(scale: Vec3) { - this._scale.copy(scale); - - this.geoObject && this.geoObject.setScale3v(this._scale); - + this._updateAbsolutePosition(); for (let i = 0; i < this.childEntities.length; i++) { let chi = this.childEntities[i]; if (chi.forceGlobalScale) { @@ -617,19 +616,16 @@ class Entity { * @param {number} val - Scale factor */ public setScale(val: number) { - this._scale.set(val, val, val); - - this.geoObject && this.geoObject.setScale(val); - + this._updateAbsolutePosition(); for (let i = 0; i < this.childEntities.length; i++) { let chi = this.childEntities[i]; if (chi.forceGlobalScale) { - chi.setScale(val); + chi.setScale3v(this._scale); } else { chi.setScale3v(this.childEntities[i].getScale()); } - } + } } /** @@ -871,7 +867,7 @@ class Entity { if (this.parent && this._relativePosition) { let scd = this._getScaleByDistance(); - pos = absolutCartesian.sub(this.parent.getAbsoluteCartesian()).scale(1 / scd); + pos = absolutCartesian.sub(this.parent.getAbsoluteCartesian()).scale(1 / scd).divA(this._absoluteScale); pos = this.parent._absoluteQRot.conjugate().mulVec3(pos); } @@ -945,13 +941,15 @@ class Entity { let parent = this.parent; if (parent && this._relativePosition) { + this._scale.mulRes(parent._absoluteScale, this._absoluteScale); + this._qFrame.copy(parent._qFrame); this._rootCartesian.copy(parent._rootCartesian); this._qRot.setPitchYawRoll(this._pitchRad, this._yawRad, this._rollRad); parent._absoluteQRot.mulRes(this._qRot, this._absoluteQRot); - let rotCart = parent._absoluteQRot.mulVec3(this._cartesian.add(this._localPosition)); + let rotCart = parent._absoluteQRot.mulVec3(this._cartesian.add(this._localPosition)).mulA(this._absoluteScale); parent._absoluteLocalPosition.addRes(rotCart, this._absoluteLocalPosition); } else { this._qFrame = Quat.IDENTITY; @@ -963,12 +961,14 @@ class Entity { } else { this._qRot.setPitchYawRoll(this._pitchRad, this._yawRad, this._rollRad, this._qFrame); } + this._absoluteScale.copy(this._scale); this._absoluteQRot.copy(this._qRot); this._rootCartesian.copy(this._cartesian); this._absoluteLocalPosition.copy(this._localPosition); } if (this.geoObject) { + this.geoObject.setScale3v(this._absoluteScale); this.geoObject.setRotation(this._absoluteQRot); this.geoObject.setPosition3v(this._rootCartesian); this.geoObject.setLocalPosition3v(this._absoluteLocalPosition);