From 92814291e886aec0d5406f161cf6876ac3c5f0b0 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Mon, 17 Jun 2024 08:27:09 +0200 Subject: [PATCH 1/4] Added visisble flag. --- src/com/types.ts | 1 + src/scene/root/lightroot/LightRoot.ts | 1 + src/scene/root/modelroot/ModelRoot.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/com/types.ts b/src/com/types.ts index 98b5b543..b708502c 100644 --- a/src/com/types.ts +++ b/src/com/types.ts @@ -4,6 +4,7 @@ type COMBaseEntity = { id: string; name: string; entityType: 'pov' | 'light' | 'model'; + visible: boolean; } export type COMPov = COMBaseEntity & { position: Vector3Like; diff --git a/src/scene/root/lightroot/LightRoot.ts b/src/scene/root/lightroot/LightRoot.ts index a034c832..27789194 100644 --- a/src/scene/root/lightroot/LightRoot.ts +++ b/src/scene/root/lightroot/LightRoot.ts @@ -61,6 +61,7 @@ export default class DIVELightRoot extends Object3D { if (light.intensity !== undefined && light.intensity !== null) (sceneObject as (DIVEAmbientLight | DIVEPointLight)).SetIntensity(light.intensity); if (light.enabled !== undefined && light.enabled !== null) (sceneObject as (DIVEAmbientLight | DIVEPointLight)).SetEnabled(light.enabled); if (light.color !== undefined && light.color !== null) (sceneObject as (DIVEAmbientLight | DIVEPointLight)).SetColor(new Color(light.color)); + if (light.visible !== undefined && light.visible !== null) (sceneObject as (DIVEAmbientLight | DIVEPointLight)).visible = light.visible; } public DeleteLight(light: Partial): void { diff --git a/src/scene/root/modelroot/ModelRoot.ts b/src/scene/root/modelroot/ModelRoot.ts index 1c9c7d6b..f805bb54 100644 --- a/src/scene/root/modelroot/ModelRoot.ts +++ b/src/scene/root/modelroot/ModelRoot.ts @@ -50,6 +50,7 @@ export default class DIVEModelRoot extends Object3D { if (object.position !== undefined) (sceneObject as Model).SetPosition(object.position); if (object.rotation !== undefined) (sceneObject as Model).SetRotation(object.rotation); if (object.scale !== undefined) (sceneObject as Model).SetScale(object.scale); + if (object.visible !== undefined) (sceneObject as Model).visible = object.visible; } public DeleteModel(object: Partial): void { From 661e99b4c049a586f0250cd24219f53bce27b223 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Mon, 17 Jun 2024 08:31:32 +0200 Subject: [PATCH 2/4] Added tests. --- src/scene/root/lightroot/__test__/LightRoot.test.ts | 2 +- src/scene/root/modelroot/__test__/ModelRoot.test.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scene/root/lightroot/__test__/LightRoot.test.ts b/src/scene/root/lightroot/__test__/LightRoot.test.ts index e185e533..b101f4ed 100644 --- a/src/scene/root/lightroot/__test__/LightRoot.test.ts +++ b/src/scene/root/lightroot/__test__/LightRoot.test.ts @@ -74,7 +74,7 @@ describe('dive/scene/root/lightroot/DIVELightRoot', () => { it('should update basic scene light', () => { const lightRoot = new DIVELightRoot(); - lightRoot.UpdateLight({ id: 'test_id', type: 'scene', name: 'test', position: undefined, enabled: true }); + lightRoot.UpdateLight({ id: 'test_id', type: 'scene', name: 'test', position: undefined, enabled: true, visible: false }); expect(lightRoot.children).toHaveLength(1); expect(lightRoot.children[0].userData.id).toBe('test_id'); }); diff --git a/src/scene/root/modelroot/__test__/ModelRoot.test.ts b/src/scene/root/modelroot/__test__/ModelRoot.test.ts index 3ed18c61..a308064b 100644 --- a/src/scene/root/modelroot/__test__/ModelRoot.test.ts +++ b/src/scene/root/modelroot/__test__/ModelRoot.test.ts @@ -77,6 +77,7 @@ describe('dive/scene/root/modelroot/DIVEModelRoot', () => { await expect(() => modelRoot.UpdateModel({ id: 'test_id', uri: 'not a real uri', + visible: false, })).not.toThrow(); expect(mock_LoadGLTF).toHaveBeenCalledTimes(1); expect(mock_SetModel).toHaveBeenCalledTimes(1); From 6343f5fa3d5d7bb79e924b39b0986f20a715a7b2 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Mon, 17 Jun 2024 08:35:40 +0200 Subject: [PATCH 3/4] Changed inheritance logic for lights. --- src/light/AmbientLight.ts | 21 ++++++++++------ src/light/PointLight.ts | 40 ++++++++++++++++++------------ src/light/SceneLight.ts | 51 ++++++++++++++++++++------------------- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/light/AmbientLight.ts b/src/light/AmbientLight.ts index 9677a478..e92a79f9 100644 --- a/src/light/AmbientLight.ts +++ b/src/light/AmbientLight.ts @@ -1,4 +1,4 @@ -import { AmbientLight, Color } from 'three'; +import { AmbientLight, Color, Object3D } from 'three'; import { PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask'; /** @@ -9,21 +9,28 @@ import { PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask'; * @module */ -export default class DIVEAmbientLight extends AmbientLight { +export default class DIVEAmbientLight extends Object3D { + private _light: AmbientLight; + constructor() { - super(0xffffff, 1); - this.layers.mask = PRODUCT_LAYER_MASK; + super(); + + this.name = 'DIVEAmbientLight'; + + this._light = new AmbientLight(0xffffff, 1); + this._light.layers.mask = PRODUCT_LAYER_MASK; + this.add(this._light); } public SetColor(color: Color): void { - this.color = color; + this._light.color = color; } public SetIntensity(intensity: number): void { - this.intensity = intensity; + this._light.intensity = intensity; } public SetEnabled(enabled: boolean): void { - this.visible = enabled; + this._light.visible = enabled; } } diff --git a/src/light/PointLight.ts b/src/light/PointLight.ts index 72d8afe4..fe183a45 100644 --- a/src/light/PointLight.ts +++ b/src/light/PointLight.ts @@ -1,4 +1,4 @@ -import { PointLight, Color, SphereGeometry, MeshBasicMaterial, Mesh, FrontSide } from 'three'; +import { PointLight, Color, SphereGeometry, MeshBasicMaterial, Mesh, FrontSide, Object3D } from 'three'; import DIVECommunication from '../com/Communication'; import { HELPER_LAYER_MASK, PRODUCT_LAYER_MASK } from '../constant/VisibilityLayerMask'; import { DIVEMoveable } from '../interface/Moveable'; @@ -15,46 +15,54 @@ import type { TransformControls } from 'three/examples/jsm/Addons.js'; * @module */ -export default class DIVEPointLight extends PointLight implements DIVESelectable, DIVEMoveable { +export default class DIVEPointLight extends Object3D implements DIVESelectable, DIVEMoveable { public isMoveable: true = true; public isSelectable: true = true; public gizmo: TransformControls | null = null; + private light: PointLight; + private mesh: Mesh; + constructor() { - super(0xffffff, 1); + super(); + + this.name = 'DIVEPointLight'; + + this.light = new PointLight(0xffffff, 1); - this.layers.mask = PRODUCT_LAYER_MASK; + this.light.layers.mask = PRODUCT_LAYER_MASK; - this.castShadow = true; - this.shadow.mapSize.width = 512; - this.shadow.mapSize.height = 512; + this.light.castShadow = true; + this.light.shadow.mapSize.width = 512; + this.light.shadow.mapSize.height = 512; + this.add(this.light); const geoSize = 0.1; const geometry = new SphereGeometry(geoSize, geoSize * 320, geoSize * 320); - const material = new MeshBasicMaterial({ color: this.color, transparent: true, opacity: 0.8, side: FrontSide }); + const material = new MeshBasicMaterial({ color: this.light.color, transparent: true, opacity: 0.8, side: FrontSide }); - const mesh = new Mesh(geometry, material); - mesh.layers.mask = HELPER_LAYER_MASK; + this.mesh = new Mesh(geometry, material); + this.mesh.layers.mask = HELPER_LAYER_MASK; - this.add(mesh); + this.add(this.mesh); } public SetColor(color: Color): void { - this.color = color; + this.light.color = color; - ((this.children[0] as Mesh).material as MeshBasicMaterial).color = color; + (this.mesh.material as MeshBasicMaterial).color = color; } public SetIntensity(intensity: number): void { - this.intensity = intensity; + this.light.intensity = intensity; - ((this.children[0] as Mesh).material as MeshBasicMaterial).opacity = intensity > 0.8 ? 0.8 : intensity * 0.8; + (this.mesh.material as MeshBasicMaterial).opacity = intensity > 0.8 ? 0.8 : intensity * 0.8; } public SetEnabled(enabled: boolean): void { - this.visible = enabled; + this.light.visible = enabled; } public onMove(): void { diff --git a/src/light/SceneLight.ts b/src/light/SceneLight.ts index ad8cdb0f..3b070b62 100644 --- a/src/light/SceneLight.ts +++ b/src/light/SceneLight.ts @@ -11,50 +11,51 @@ import { Color, DirectionalLight, HemisphereLight, Object3D } from "three"; export default class DIVESceneLight extends Object3D { - private hemiLight: HemisphereLight; - private dirLight: DirectionalLight; + private _hemiLight: HemisphereLight; + private _dirLight: DirectionalLight; constructor() { super(); - this.name = "SceneLight"; + this.name = 'DIVESceneLight'; - this.hemiLight = new HemisphereLight(0xffffff, 0xffffff, 2); - this.hemiLight.layers.mask = PRODUCT_LAYER_MASK; - this.hemiLight.position.set(0, 50, 0); - this.add(this.hemiLight); + this._hemiLight = new HemisphereLight(0xffffff, 0xffffff, 2); + this._hemiLight.layers.mask = PRODUCT_LAYER_MASK; + this._hemiLight.position.set(0, 50, 0); + this.add(this._hemiLight); - this.dirLight = new DirectionalLight(0xffffff, 3); - this.dirLight.layers.mask = PRODUCT_LAYER_MASK; - this.dirLight.position.set(1, 1.75, 1); - this.dirLight.position.multiplyScalar(30); - this.dirLight.castShadow = true; + this._dirLight = new DirectionalLight(0xffffff, 3); + this._dirLight.layers.mask = PRODUCT_LAYER_MASK; + this._dirLight.position.set(1, 1.75, 1); + this._dirLight.position.multiplyScalar(30); + this._dirLight.castShadow = true; - this.dirLight.shadow.mapSize.width = 2048; - this.dirLight.shadow.mapSize.height = 2048; + this._dirLight.shadow.mapSize.width = 2048; + this._dirLight.shadow.mapSize.height = 2048; const d = 5; - this.dirLight.shadow.camera.left = - d; - this.dirLight.shadow.camera.right = d; - this.dirLight.shadow.camera.top = d; - this.dirLight.shadow.camera.bottom = - d; + this._dirLight.shadow.camera.left = - d; + this._dirLight.shadow.camera.right = d; + this._dirLight.shadow.camera.top = d; + this._dirLight.shadow.camera.bottom = - d; - this.dirLight.shadow.camera.far = 3500; - this.add(this.dirLight); + this._dirLight.shadow.camera.far = 3500; + this.add(this._dirLight); } public SetColor(color: Color): void { - this.hemiLight.color = color; - this.dirLight.color = color; + this._hemiLight.color = color; + this._dirLight.color = color; } public SetIntensity(intensity: number): void { - this.hemiLight.intensity = intensity * 2; - this.dirLight.intensity = intensity * 3; + this._hemiLight.intensity = intensity * 2; + this._dirLight.intensity = intensity * 3; } public SetEnabled(enabled: boolean): void { - this.visible = enabled; + this._hemiLight.visible = enabled; + this._dirLight.visible = enabled; } } \ No newline at end of file From 6a1e8f63c914125a3b8c89e0722e3abe7e5e0420 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Mon, 17 Jun 2024 08:51:59 +0200 Subject: [PATCH 4/4] Fixed tests after changes. --- src/light/__test__/AmbientLight.test.ts | 16 +++++++++++---- src/light/__test__/PointLight.test.ts | 27 ++++++++++++++++++------- src/light/__test__/SceneLight.test.ts | 14 +++++++++---- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/light/__test__/AmbientLight.test.ts b/src/light/__test__/AmbientLight.test.ts index 030182b4..511af03a 100644 --- a/src/light/__test__/AmbientLight.test.ts +++ b/src/light/__test__/AmbientLight.test.ts @@ -1,4 +1,4 @@ -import { Color } from 'three'; +import { AmbientLight, Color, Object3D } from 'three'; import DIVEAmbientLight from '../AmbientLight'; jest.mock('three', () => { @@ -12,6 +12,14 @@ jest.mock('three', () => { this.layers = { mask: 0, }; + this.removeFromParent = jest.fn(); + return this; + }), + Object3D: jest.fn(function () { + this.children = []; + this.add = (obj: Object3D) => { + this.children.push(obj); + }; return this; }), } @@ -27,18 +35,18 @@ describe('dive/light/DIVEAmbientLight', () => { it('should set intensity', () => { const testLight = new DIVEAmbientLight(); testLight.SetIntensity(1.0); - expect(testLight.intensity).toBe(1.0); + expect((testLight.children[0] as AmbientLight).intensity).toBe(1.0); }); it('should set color', () => { const testLight = new DIVEAmbientLight(); testLight.SetColor({ test: true } as unknown as Color); - expect(testLight.color).toEqual({ test: true }); + expect((testLight.children[0] as AmbientLight).color).toEqual({ test: true }); }); it('should set enabled', () => { const testLight = new DIVEAmbientLight(); testLight.SetEnabled(false); - expect(testLight.visible).toBe(false); + expect(testLight.children[0].visible).toBe(false); }); }); \ No newline at end of file diff --git a/src/light/__test__/PointLight.test.ts b/src/light/__test__/PointLight.test.ts index 9ca9a5c1..07277d33 100644 --- a/src/light/__test__/PointLight.test.ts +++ b/src/light/__test__/PointLight.test.ts @@ -1,6 +1,6 @@ import DIVEPointLight from '../PointLight.ts'; import DIVECommunication from '../../com/Communication.ts'; -import { Color } from 'three'; +import { Color, MeshBasicMaterial, Object3D, PointLight } from 'three'; const mockAdd = jest.fn(); @@ -10,6 +10,7 @@ jest.mock('three', () => { return {}; }), PointLight: jest.fn(function () { + this.visible = true; this.color = {}; this.intensity = 0; this.layers = { @@ -31,19 +32,30 @@ jest.mock('three', () => { color: {}, }, }]; - this.userData = {}; return this; }), SphereGeometry: jest.fn(function () { return this; }), MeshBasicMaterial: jest.fn(function () { + this.opacity = 1.0; + this.color = new Color(); return this; }), Mesh: jest.fn(function () { this.layers = { mask: 0, }; + this.visible = true; + this.material = new MeshBasicMaterial(); + return this; + }), + Object3D: jest.fn(function () { + this.children = []; + this.add = (obj: Object3D) => { + this.children.push(obj); + }; + this.userData = {}; return this; }), } @@ -64,27 +76,28 @@ describe('dive/light/DIVEPointLight', () => { const testLight = new DIVEPointLight(); testLight.userData.id = 'something'; expect(testLight).toBeDefined(); - expect(mockAdd).toHaveBeenCalledTimes(1); + expect(testLight.userData.id).toBe('something'); + expect(testLight.children).toHaveLength(2); }); it('should set intensity', () => { const testLight = new DIVEPointLight(); testLight.SetIntensity(1.0); - expect(testLight.intensity).toBe(1.0); + expect((testLight.children[0] as PointLight).intensity).toBe(1.0); testLight.SetIntensity(0.6); - expect(testLight.intensity).toBe(0.6); + expect((testLight.children[0] as PointLight).intensity).toBe(0.6); }); it('should set color', () => { const testLight = new DIVEPointLight(); testLight.SetColor({ test: true } as unknown as Color); - expect(testLight.color).toEqual({ test: true }); + expect((testLight.children[0] as PointLight).color).toEqual({ test: true }); }); it('should set enabled', () => { const testLight = new DIVEPointLight(); testLight.SetEnabled(false); - expect(testLight.visible).toBe(false); + expect(testLight.children[0].visible).toBe(false); }); it('should onMove', () => { diff --git a/src/light/__test__/SceneLight.test.ts b/src/light/__test__/SceneLight.test.ts index f8f3938c..66a19867 100644 --- a/src/light/__test__/SceneLight.test.ts +++ b/src/light/__test__/SceneLight.test.ts @@ -1,6 +1,6 @@ import DIVESceneLight from '../SceneLight'; import DIVECommunication from '../../com/Communication'; -import { Color } from 'three'; +import { Color, HemisphereLight as THREEHemisphereLight, DirectionalLight as THREEDirectionalLight, Object3D } from 'three'; jest.mock('../../com/Communication.ts', () => { return { @@ -57,10 +57,14 @@ jest.mock('three', () => { return this; }), Object3D: jest.fn(function () { - this.add = mockAdd; + this.children = []; + this.add = (obj: Object3D) => { + this.children.push(obj); + }; return this; }), HemisphereLight: jest.fn(function () { + this.visible = true; this.layers = { mask: 0, }; @@ -71,6 +75,7 @@ jest.mock('three', () => { return this; }), DirectionalLight: jest.fn(function () { + this.visible = true; this.layers = { mask: 0, }; @@ -100,7 +105,7 @@ describe('dive/light/DIVESceneLight', () => { it('should instantiate', () => { const testLight = new DIVESceneLight(); expect(testLight).toBeDefined(); - expect(mockAdd).toHaveBeenCalledTimes(2); + expect(testLight.children).toHaveLength(2); }); it('should set intensity', () => { @@ -117,6 +122,7 @@ describe('dive/light/DIVESceneLight', () => { it('should set enabled', () => { const testLight = new DIVESceneLight(); testLight.SetEnabled(false); - expect(testLight.visible).toBe(false); + expect(testLight.children[0].visible).toBe(false); + expect(testLight.children[1].visible).toBe(false); }); }); \ No newline at end of file