From a0dc0ceace9a47c87342654fd764f624078934d0 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 24 Apr 2025 15:04:57 +0200 Subject: [PATCH 01/10] Add helpers for directional and hemisphere lights --- src/renderer.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/renderer.ts b/src/renderer.ts index fb09138..10c4b3c 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -55,8 +55,17 @@ export class URDFRenderer extends THREE.WebGLRenderer { this._controls = new OrbitControls(this._camera, this.domElement); this._initControls(); - } + this.printSceneLights(); + } + printSceneLights() { + console.log('Scene Lights:'); + this._scene.children.forEach(obj => { + if (obj.type.includes('Light')) { + console.log(obj); + } + }); + } /** * Initializes the camera */ @@ -134,6 +143,14 @@ export class URDFRenderer extends THREE.WebGLRenderer { directionalLight.shadow.camera.far = 40; this._scene.add(directionalLight); + // Add a helper for the directional light with black color + const directionalLightHelper = new THREE.DirectionalLightHelper( + directionalLight, + 2, + new THREE.Color(0x000000) // Black color for helper + ); + this._scene.add(directionalLightHelper); + const ambientLight = new THREE.AmbientLight('#fff'); ambientLight.intensity = 0.5; ambientLight.position.set(0, 5, 0); @@ -145,6 +162,14 @@ export class URDFRenderer extends THREE.WebGLRenderer { ); hemisphereLight.intensity = 1; this._scene.add(hemisphereLight); + + // Add a helper for the hemisphere light with black color + const hemisphereLightHelper = new THREE.HemisphereLightHelper( + hemisphereLight, + 2 + ); + hemisphereLightHelper.material.color.set(0x000000); // Black color for helper + this._scene.add(hemisphereLightHelper); } /** From d9d2f77a20d38797d4af346a8101b50ab1eb52d7 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Fri, 25 Apr 2025 11:30:06 +0200 Subject: [PATCH 02/10] Add lighting controls --- src/controls.ts | 127 +++++++++++++++++++++++++++++++++++++++++++++- src/layout.ts | 65 ++++++++++++++++++++++++ src/renderer.ts | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index 690e28d..73b56a3 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -16,6 +16,7 @@ export class URDFControls extends GUI { private _workspaceFolder: any; private _sceneFolder: any; private _jointsFolder: any; + private _lightsFolder: any; private _workingPath = ''; controls: any = { @@ -25,7 +26,8 @@ export class URDFControls extends GUI { grid: {}, height: {} }, - joints: {} + joints: {}, + lights: {} }; /** @@ -58,6 +60,9 @@ export class URDFControls extends GUI { this._jointsFolder = this.addFolder('Joints'); this._jointsFolder.domElement.setAttribute('class', 'dg joints-folder'); + + this._lightsFolder = this.addFolder('Lights'); + this._lightsFolder.domElement.setAttribute('class', 'dg lights-folder'); } /** @@ -81,6 +86,13 @@ export class URDFControls extends GUI { return this._jointsFolder; } + /** + * Retrieves the folder with lights settings + */ + get lightsFolder() { + return this._lightsFolder; + } + /** * Checks if a given object is empty {} * @@ -263,4 +275,117 @@ export class URDFControls extends GUI { } }); } + /** + * Creates controls for the different lights in the scene + * + * @returns - The controls to trigger callbacks when light settings change + */ + createLightControls() { + if (this._isEmpty(this.controls.lights)) { + // Create subfolders for each light + const directionalFolder = + this._lightsFolder.addFolder('Directional Light'); + const ambientFolder = this._lightsFolder.addFolder('Ambient Light'); + const hemisphereFolder = this._lightsFolder.addFolder('Hemisphere Light'); + + // Initialize settings for each light type + const directionalSettings = { + X: 3, + Y: 10, + Z: 3, + Color: [255, 255, 255], + Intensity: 1.0 + }; + + const ambientSettings = { + Color: [255, 255, 255], + Intensity: 0.5 + }; + + const hemisphereSettings = { + SkyColor: [255, 255, 255], + GroundColor: [38, 50, 56], // Default hex: #263238 + Intensity: 1.0 + }; + + // Position limits and steps + const minPosition = -20; + const maxPosition = 20; + const positionStep = 0.1; + + // Intensity limits and steps + const minIntensity = 0; + const maxIntensity = 2; + const intensityStep = 0.05; + + // Directional light controls + this.controls.lights.directional = { + position: { + x: directionalFolder.add( + directionalSettings, + 'X', + minPosition, + maxPosition, + positionStep + ), + y: directionalFolder.add( + directionalSettings, + 'Y', + minPosition, + maxPosition, + positionStep + ), + z: directionalFolder.add( + directionalSettings, + 'Z', + minPosition, + maxPosition, + positionStep + ) + }, + color: directionalFolder.addColor(directionalSettings, 'Color'), + intensity: directionalFolder.add( + directionalSettings, + 'Intensity', + minIntensity, + maxIntensity, + intensityStep + ) + }; + + // Ambient light controls + this.controls.lights.ambient = { + color: ambientFolder.addColor(ambientSettings, 'Color'), + intensity: ambientFolder.add( + ambientSettings, + 'Intensity', + minIntensity, + maxIntensity, + intensityStep + ) + }; + + // Hemisphere light controls + this.controls.lights.hemisphere = { + skyColor: hemisphereFolder.addColor(hemisphereSettings, 'SkyColor'), + groundColor: hemisphereFolder.addColor( + hemisphereSettings, + 'GroundColor' + ), + intensity: hemisphereFolder.add( + hemisphereSettings, + 'Intensity', + minIntensity, + maxIntensity, + intensityStep + ) + }; + + // Open main lights folder and directional subfolder + this._lightsFolder.open(); + directionalFolder.open(); + } + + return this.controls.lights; + } } diff --git a/src/layout.ts b/src/layout.ts index 790745c..829a4a3 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -165,6 +165,7 @@ export class URDFLayout extends PanelLayout { this._setPathControls(); this._setSceneControls(); this._setJointControls(); + this._setLightControls(); } /** @@ -214,6 +215,70 @@ export class URDFLayout extends PanelLayout { }); } + /** + * Set callback for changing directional light position in the controls panel. + */ + private _setLightControls(): void { + const lightControl = this._controlsPanel.createLightControls(); + + // Directional light callbacks + const directional = lightControl.directional; + + // Position controls + directional.position.x.onChange((newX: number) => { + const y = directional.position.y.getValue(); + const z = directional.position.z.getValue(); + this._renderer.setDirectionalLightPosition(newX, y, z); + }); + + directional.position.y.onChange((newY: number) => { + const x = directional.position.x.getValue(); + const z = directional.position.z.getValue(); + this._renderer.setDirectionalLightPosition(x, newY, z); + }); + + directional.position.z.onChange((newZ: number) => { + const x = directional.position.x.getValue(); + const y = directional.position.y.getValue(); + this._renderer.setDirectionalLightPosition(x, y, newZ); + }); + + // Color and intensity controls + directional.color.onChange((newColor: number[]) => { + this._renderer.setDirectionalLightColor(newColor); + }); + + directional.intensity.onChange((newIntensity: number) => { + this._renderer.setDirectionalLightIntensity(newIntensity); + }); + + // Ambient light callbacks + const ambient = lightControl.ambient; + + ambient.color.onChange((newColor: number[]) => { + this._renderer.setAmbientLightColor(newColor); + }); + + ambient.intensity.onChange((newIntensity: number) => { + this._renderer.setAmbientLightIntensity(newIntensity); + }); + + // Hemisphere light callbacks + const hemisphere = lightControl.hemisphere; + + hemisphere.skyColor.onChange((newColor: number[]) => { + this._renderer.setHemisphereLightSkyColor(newColor); + }); + + hemisphere.groundColor.onChange((newColor: number[]) => { + this._renderer.setHemisphereLightGroundColor(newColor); + }); + + hemisphere.intensity.onChange((newIntensity: number) => { + this._renderer.setHemisphereLightIntensity(newIntensity); + }); + } + /** * Set value for robot joint * diff --git a/src/renderer.ts b/src/renderer.ts index 10c4b3c..d25a836 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -251,6 +251,138 @@ export class URDFRenderer extends THREE.WebGLRenderer { this.redraw(); } + /** + * Updates the position of the directional light + * + * @param x - The new x position + * @param y - The new y position + * @param z - The new z position + */ + setDirectionalLightPosition(x: number, y: number, z: number): void { + const directionalLight = this._scene.children.find( + obj => obj.type === 'DirectionalLight' + ) as THREE.DirectionalLight; + + if (directionalLight) { + directionalLight.position.set(x, y, z); + this.redraw(); + } + } + + /** + * Updates the color of the directional light + * + * @param newColor - The new color as [R, G, B] array 0-255 + */ + setDirectionalLightColor(newColor: number[]): void { + const directionalLight = this._scene.children.find( + obj => obj.type === 'DirectionalLight' + ) as THREE.DirectionalLight; + + if (directionalLight) { + directionalLight.color = new THREE.Color(...newColor.map(x => x / 255)); + this.redraw(); + } + } + + /** + * Updates the intensity of the directional light + * + * @param intensity - The new intensity value + */ + setDirectionalLightIntensity(intensity: number): void { + const directionalLight = this._scene.children.find( + obj => obj.type === 'DirectionalLight' + ) as THREE.DirectionalLight; + + if (directionalLight) { + directionalLight.intensity = intensity; + this.redraw(); + } + } + + /** + * Updates the color of the ambient light + * + * @param newColor - The new color as [R, G, B] array 0-255 + */ + setAmbientLightColor(newColor: number[]): void { + const ambientLight = this._scene.children.find( + obj => obj.type === 'AmbientLight' + ) as THREE.AmbientLight; + + if (ambientLight) { + ambientLight.color = new THREE.Color(...newColor.map(x => x / 255)); + this.redraw(); + } + } + + /** + * Updates the intensity of the ambient light + * + * @param intensity - The new intensity value + */ + setAmbientLightIntensity(intensity: number): void { + const ambientLight = this._scene.children.find( + obj => obj.type === 'AmbientLight' + ) as THREE.AmbientLight; + + if (ambientLight) { + ambientLight.intensity = intensity; + this.redraw(); + } + } + + /** + * Updates the hemisphere light sky color + * + * @param newColor - The new color as [R, G, B] array 0-255 + */ + setHemisphereLightSkyColor(newColor: number[]): void { + const hemisphereLight = this._scene.children.find( + obj => obj.type === 'HemisphereLight' + ) as THREE.HemisphereLight; + + if (hemisphereLight) { + hemisphereLight.color = new THREE.Color(...newColor.map(x => x / 255)); + this.redraw(); + } + } + + /** + * Updates the hemisphere light ground color + * + * @param newColor - The new color as [R, G, B] array 0-255 + */ + setHemisphereLightGroundColor(newColor: number[]): void { + const hemisphereLight = this._scene.children.find( + obj => obj.type === 'HemisphereLight' + ) as THREE.HemisphereLight; + + if (hemisphereLight) { + hemisphereLight.groundColor = new THREE.Color( + ...newColor.map(x => x / 255) + ); + this.redraw(); + } + } + + /** + * Updates the hemisphere light intensity + * + * @param intensity - The new intensity value + */ + setHemisphereLightIntensity(intensity: number): void { + const hemisphereLight = this._scene.children.find( + obj => obj.type === 'HemisphereLight' + ) as THREE.HemisphereLight; + + if (hemisphereLight) { + hemisphereLight.intensity = intensity; + this.redraw(); + } + } + /** * Refreshes the viewer by re-rendering the scene and its elements */ From 14458944b1261b78ded86f150b75574b81f2ce15 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Sun, 4 May 2025 21:55:29 +0200 Subject: [PATCH 03/10] Add helper toggle and make directional controls spherical --- src/controls.ts | 75 ++++++++++++++++++++++++++++++++------ src/layout.ts | 66 +++++++++++++++++++++++++++------- src/renderer.ts | 95 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 205 insertions(+), 31 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 73b56a3..d4f926b 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -287,14 +287,22 @@ export class URDFControls extends GUI { this._lightsFolder.addFolder('Directional Light'); const ambientFolder = this._lightsFolder.addFolder('Ambient Light'); const hemisphereFolder = this._lightsFolder.addFolder('Hemisphere Light'); + const helpersFolder = this._lightsFolder.addFolder('Light Helpers'); // Initialize settings for each light type const directionalSettings = { - X: 3, - Y: 10, - Z: 3, + // Spherical coordinates are more intuitive for light positioning + Distance: 10.9, // Initial distance from origin + Altitude: Math.PI / 4, // Initial altitude angle (radians) + Azimuth: Math.PI / 4, // Initial azimuth angle (radians) Color: [255, 255, 255], - Intensity: 1.0 + Intensity: 1.0, + // Adding target controls + Target: { + X: 0, + Y: 0, + Z: 0 + } }; const ambientSettings = { @@ -308,35 +316,73 @@ export class URDFControls extends GUI { Intensity: 1.0 }; + const helperSettings = { + DirectionalHelper: true, + HemisphereHelper: true + }; + // Position limits and steps const minPosition = -20; const maxPosition = 20; const positionStep = 0.1; + // Spherical coordinate limits and steps + const minDistance = 0.1; + const maxDistance = 30; + const distanceStep = 0.1; + const minAngle = -Math.PI; + const maxAngle = Math.PI; + const angleStep = 0.01; + // Intensity limits and steps const minIntensity = 0; const maxIntensity = 2; const intensityStep = 0.05; - // Directional light controls + // Target controls for directional light + const targetFolder = directionalFolder.addFolder('Target'); this.controls.lights.directional = { position: { - x: directionalFolder.add( + // Using spherical coordinates instead of Cartesian + distance: directionalFolder.add( + directionalSettings, + 'Distance', + minDistance, + maxDistance, + distanceStep + ), + altitude: directionalFolder.add( + directionalSettings, + 'Altitude', + minAngle, + maxAngle, + angleStep + ), + azimuth: directionalFolder.add( directionalSettings, + 'Azimuth', + minAngle, + maxAngle, + angleStep + ) + }, + target: { + x: targetFolder.add( + directionalSettings.Target, 'X', minPosition, maxPosition, positionStep ), - y: directionalFolder.add( - directionalSettings, + y: targetFolder.add( + directionalSettings.Target, 'Y', minPosition, maxPosition, positionStep ), - z: directionalFolder.add( - directionalSettings, + z: targetFolder.add( + directionalSettings.Target, 'Z', minPosition, maxPosition, @@ -381,6 +427,15 @@ export class URDFControls extends GUI { ) }; + // Light helpers controls + this.controls.lights.helpers = { + directionalHelper: helpersFolder.add( + helperSettings, + 'DirectionalHelper' + ), + hemisphereHelper: helpersFolder.add(helperSettings, 'HemisphereHelper') + }; + // Open main lights folder and directional subfolder this._lightsFolder.open(); directionalFolder.open(); diff --git a/src/layout.ts b/src/layout.ts index 829a4a3..cb53d2d 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -224,23 +224,54 @@ export class URDFLayout extends PanelLayout { // Directional light callbacks const directional = lightControl.directional; - // Position controls - directional.position.x.onChange((newX: number) => { - const y = directional.position.y.getValue(); - const z = directional.position.z.getValue(); - this._renderer.setDirectionalLightPosition(newX, y, z); + // Position controls using spherical coordinates + directional.position.distance.onChange((newDistance: number) => { + const altitude = directional.position.altitude.getValue(); + const azimuth = directional.position.azimuth.getValue(); + this._renderer.setDirectionalLightPositionSpherical( + newDistance, + altitude, + azimuth + ); }); - directional.position.y.onChange((newY: number) => { - const x = directional.position.x.getValue(); - const z = directional.position.z.getValue(); - this._renderer.setDirectionalLightPosition(x, newY, z); + directional.position.altitude.onChange((newAltitude: number) => { + const distance = directional.position.distance.getValue(); + const azimuth = directional.position.azimuth.getValue(); + this._renderer.setDirectionalLightPositionSpherical( + distance, + newAltitude, + azimuth + ); }); - directional.position.z.onChange((newZ: number) => { - const x = directional.position.x.getValue(); - const y = directional.position.y.getValue(); - this._renderer.setDirectionalLightPosition(x, y, newZ); + directional.position.azimuth.onChange((newAzimuth: number) => { + const distance = directional.position.distance.getValue(); + const altitude = directional.position.altitude.getValue(); + this._renderer.setDirectionalLightPositionSpherical( + distance, + altitude, + newAzimuth + ); + }); + + // Target position controls for directional light + directional.target.x.onChange((newX: number) => { + const y = directional.target.y.getValue(); + const z = directional.target.z.getValue(); + this._renderer.setDirectionalLightTarget(newX, y, z); + }); + + directional.target.y.onChange((newY: number) => { + const x = directional.target.x.getValue(); + const z = directional.target.z.getValue(); + this._renderer.setDirectionalLightTarget(x, newY, z); + }); + + directional.target.z.onChange((newZ: number) => { + const x = directional.target.x.getValue(); + const y = directional.target.y.getValue(); + this._renderer.setDirectionalLightTarget(x, y, newZ); }); // Color and intensity controls @@ -252,6 +283,15 @@ export class URDFLayout extends PanelLayout { this._renderer.setDirectionalLightIntensity(newIntensity); }); + // Light helper visibility toggles + lightControl.helpers.directionalHelper.onChange((visible: boolean) => { + this._renderer.setDirectionalLightHelperVisibility(visible); + }); + + lightControl.helpers.hemisphereHelper.onChange((visible: boolean) => { + this._renderer.setHemisphereLightHelperVisibility(visible); + }); + // Ambient light callbacks const ambient = lightControl.ambient; diff --git a/src/renderer.ts b/src/renderer.ts index d25a836..6cac5a7 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -25,6 +25,8 @@ export class URDFRenderer extends THREE.WebGLRenderer { private _colorGround = new THREE.Color(); private _gridHeight = 0; private _robotIndex = -1; + private _directionalLightHelper: THREE.DirectionalLightHelper | null = null; + private _hemisphereLightHelper: THREE.HemisphereLightHelper | null = null; /** * Creates a renderer to manage the scene elements @@ -143,13 +145,13 @@ export class URDFRenderer extends THREE.WebGLRenderer { directionalLight.shadow.camera.far = 40; this._scene.add(directionalLight); - // Add a helper for the directional light with black color - const directionalLightHelper = new THREE.DirectionalLightHelper( + // Add a helper for the directional light + this._directionalLightHelper = new THREE.DirectionalLightHelper( directionalLight, 2, - new THREE.Color(0x000000) // Black color for helper + new THREE.Color(0x000000) ); - this._scene.add(directionalLightHelper); + this._scene.add(this._directionalLightHelper); const ambientLight = new THREE.AmbientLight('#fff'); ambientLight.intensity = 0.5; @@ -163,13 +165,13 @@ export class URDFRenderer extends THREE.WebGLRenderer { hemisphereLight.intensity = 1; this._scene.add(hemisphereLight); - // Add a helper for the hemisphere light with black color - const hemisphereLightHelper = new THREE.HemisphereLightHelper( + // Add a helper for the hemisphere light + this._hemisphereLightHelper = new THREE.HemisphereLightHelper( hemisphereLight, 2 ); - hemisphereLightHelper.material.color.set(0x000000); // Black color for helper - this._scene.add(hemisphereLightHelper); + this._hemisphereLightHelper.material.color.set(0x000000); // Black color for helper + this._scene.add(this._hemisphereLightHelper); } /** @@ -187,6 +189,80 @@ export class URDFRenderer extends THREE.WebGLRenderer { this._scene.children[hemisphereIndex] = hemisphereLight; } + /** + * Toggle the visibility of the directional light helper + * + * @param visible - Whether the helper should be visible + */ + setDirectionalLightHelperVisibility(visible: boolean): void { + if (this._directionalLightHelper) { + this._directionalLightHelper.visible = visible; + this.redraw(); + } + } + + /** + * Toggle the visibility of the hemisphere light helper + * + * @param visible - Whether the helper should be visible + */ + setHemisphereLightHelperVisibility(visible: boolean): void { + if (this._hemisphereLightHelper) { + this._hemisphereLightHelper.visible = visible; + this.redraw(); + } + } + + /** + * Updates the target of the directional light + * + * @param x - The x coordinate of the target + * @param y - The y coordinate of the target + * @param z - The z coordinate of the target + */ + setDirectionalLightTarget(x: number, y: number, z: number): void { + const directionalLight = this._scene.children.find( + obj => obj.type === 'DirectionalLight' + ) as THREE.DirectionalLight; + + if (directionalLight) { + directionalLight.target.position.set(x, y, z); + if (this._directionalLightHelper) { + this._directionalLightHelper.update(); + } + this.redraw(); + } + } + + /** + * Updates the position of the directional light using spherical coordinates + * + * @param distance - Distance from target + * @param altitude - Angle in radians from the horizontal plane (elevation) + * @param azimuth - Angle in radians around the vertical axis + */ + setDirectionalLightPositionSpherical( + distance: number, + altitude: number, + azimuth: number + ): void { + const directionalLight = this._scene.children.find( + obj => obj.type === 'DirectionalLight' + ) as THREE.DirectionalLight; + + if (directionalLight) { + const x = distance * Math.cos(altitude) * Math.cos(azimuth); + const z = distance * Math.cos(altitude) * Math.sin(azimuth); + const y = distance * Math.sin(altitude); + + directionalLight.position.set(x, y, z); + if (this._directionalLightHelper) { + this._directionalLightHelper.update(); + } + this.redraw(); + } + } + /** * Change the background color of the scene * @@ -265,6 +341,9 @@ export class URDFRenderer extends THREE.WebGLRenderer { if (directionalLight) { directionalLight.position.set(x, y, z); + if (this._directionalLightHelper) { + this._directionalLightHelper.update(); + } this.redraw(); } } From caab092826582f11d69f95a9660da45d89f28e95 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Mon, 5 May 2025 11:10:44 +0200 Subject: [PATCH 04/10] Improve lighting --- src/controls.ts | 26 +++++++------------------- src/layout.ts | 13 +++++++------ src/renderer.ts | 37 +++++++++++++++++++++---------------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index d4f926b..7435fbc 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -287,16 +287,15 @@ export class URDFControls extends GUI { this._lightsFolder.addFolder('Directional Light'); const ambientFolder = this._lightsFolder.addFolder('Ambient Light'); const hemisphereFolder = this._lightsFolder.addFolder('Hemisphere Light'); - const helpersFolder = this._lightsFolder.addFolder('Light Helpers'); // Initialize settings for each light type const directionalSettings = { - // Spherical coordinates are more intuitive for light positioning Distance: 10.9, // Initial distance from origin Altitude: Math.PI / 4, // Initial altitude angle (radians) Azimuth: Math.PI / 4, // Initial azimuth angle (radians) Color: [255, 255, 255], Intensity: 1.0, + ShowHelper: false, // Adding target controls Target: { X: 0, @@ -312,13 +311,9 @@ export class URDFControls extends GUI { const hemisphereSettings = { SkyColor: [255, 255, 255], - GroundColor: [38, 50, 56], // Default hex: #263238 - Intensity: 1.0 - }; - - const helperSettings = { - DirectionalHelper: true, - HemisphereHelper: true + GroundColor: [38, 50, 56], + Intensity: 1.0, + ShowHelper: false // Helper toggle moved here, off by default }; // Position limits and steps @@ -396,7 +391,8 @@ export class URDFControls extends GUI { minIntensity, maxIntensity, intensityStep - ) + ), + showHelper: directionalFolder.add(directionalSettings, 'ShowHelper') }; // Ambient light controls @@ -424,16 +420,8 @@ export class URDFControls extends GUI { minIntensity, maxIntensity, intensityStep - ) - }; - - // Light helpers controls - this.controls.lights.helpers = { - directionalHelper: helpersFolder.add( - helperSettings, - 'DirectionalHelper' ), - hemisphereHelper: helpersFolder.add(helperSettings, 'HemisphereHelper') + showHelper: hemisphereFolder.add(hemisphereSettings, 'ShowHelper') }; // Open main lights folder and directional subfolder diff --git a/src/layout.ts b/src/layout.ts index cb53d2d..00956a0 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -283,15 +283,11 @@ export class URDFLayout extends PanelLayout { this._renderer.setDirectionalLightIntensity(newIntensity); }); - // Light helper visibility toggles - lightControl.helpers.directionalHelper.onChange((visible: boolean) => { + // Helper visibility toggle for directional light + directional.showHelper.onChange((visible: boolean) => { this._renderer.setDirectionalLightHelperVisibility(visible); }); - lightControl.helpers.hemisphereHelper.onChange((visible: boolean) => { - this._renderer.setHemisphereLightHelperVisibility(visible); - }); - // Ambient light callbacks const ambient = lightControl.ambient; @@ -317,6 +313,11 @@ export class URDFLayout extends PanelLayout { hemisphere.intensity.onChange((newIntensity: number) => { this._renderer.setHemisphereLightIntensity(newIntensity); }); + + // Helper visibility toggle for hemisphere light + hemisphere.showHelper.onChange((visible: boolean) => { + this._renderer.setHemisphereLightHelperVisibility(visible); + }); } /** diff --git a/src/renderer.ts b/src/renderer.ts index 6cac5a7..8c902e7 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -134,43 +134,48 @@ export class URDFRenderer extends THREE.WebGLRenderer { * Adds three lights to the scene */ private _addLights(): void { - const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0); + // Directional light + const directionalLight = new THREE.DirectionalLight(0xfff2cc, 1.8); directionalLight.castShadow = true; - directionalLight.position.set(3, 10, 3); - directionalLight.shadow.camera.top = 2; - directionalLight.shadow.camera.bottom = -2; - directionalLight.shadow.camera.left = -2; - directionalLight.shadow.camera.right = 2; - directionalLight.shadow.camera.near = 0.1; - directionalLight.shadow.camera.far = 40; + directionalLight.position.set(5, 12, 6); + directionalLight.shadow.camera.top = 5; + directionalLight.shadow.camera.bottom = -5; + directionalLight.shadow.camera.left = -5; + directionalLight.shadow.camera.right = 5; + directionalLight.shadow.camera.near = 0.5; + directionalLight.shadow.camera.far = 50; this._scene.add(directionalLight); - // Add a helper for the directional light + // Directional light helper this._directionalLightHelper = new THREE.DirectionalLightHelper( directionalLight, 2, new THREE.Color(0x000000) ); + this._directionalLightHelper.visible = false; this._scene.add(this._directionalLightHelper); - const ambientLight = new THREE.AmbientLight('#fff'); - ambientLight.intensity = 0.5; + // Ambient light + const ambientLight = new THREE.AmbientLight(0x404040); + ambientLight.intensity = 0.1; ambientLight.position.set(0, 5, 0); this._scene.add(ambientLight); + // Hemisphere light const hemisphereLight = new THREE.HemisphereLight( - this._colorSky, - this._colorGround + 0x8888ff, // cool sky + 0x442200, // warm ground + 0.4 ); - hemisphereLight.intensity = 1; this._scene.add(hemisphereLight); - // Add a helper for the hemisphere light + // Hemisphere light helper this._hemisphereLightHelper = new THREE.HemisphereLightHelper( hemisphereLight, 2 ); - this._hemisphereLightHelper.material.color.set(0x000000); // Black color for helper + this._hemisphereLightHelper.material.color.set(0x000000); + this._hemisphereLightHelper.visible = false; // Set to hidden by default this._scene.add(this._hemisphereLightHelper); } From e1076d9f64d883433a5c1352209d7428aa234e63 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Mon, 12 May 2025 10:25:50 +0200 Subject: [PATCH 05/10] Remove pointless directional light distance slider --- src/controls.ts | 28 ++++++++-------------------- src/layout.ts | 24 ++---------------------- src/renderer.ts | 5 ++--- 3 files changed, 12 insertions(+), 45 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 7435fbc..15d3f5a 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -290,9 +290,8 @@ export class URDFControls extends GUI { // Initialize settings for each light type const directionalSettings = { - Distance: 10.9, // Initial distance from origin - Altitude: Math.PI / 4, // Initial altitude angle (radians) - Azimuth: Math.PI / 4, // Initial azimuth angle (radians) + Altitude: Math.PI / 4, // 45 degrees elevation + Azimuth: Math.PI / 4, // 45 degrees around vertical axis Color: [255, 255, 255], Intensity: 1.0, ShowHelper: false, @@ -313,39 +312,28 @@ export class URDFControls extends GUI { SkyColor: [255, 255, 255], GroundColor: [38, 50, 56], Intensity: 1.0, - ShowHelper: false // Helper toggle moved here, off by default + ShowHelper: false }; // Position limits and steps - const minPosition = -20; - const maxPosition = 20; + const minPosition = -50; + const maxPosition = 50; const positionStep = 0.1; - // Spherical coordinate limits and steps - const minDistance = 0.1; - const maxDistance = 30; - const distanceStep = 0.1; + // Spherical coordinate angle limits and steps const minAngle = -Math.PI; const maxAngle = Math.PI; const angleStep = 0.01; // Intensity limits and steps const minIntensity = 0; - const maxIntensity = 2; - const intensityStep = 0.05; + const maxIntensity = 10; + const intensityStep = 0.1; // Target controls for directional light const targetFolder = directionalFolder.addFolder('Target'); this.controls.lights.directional = { position: { - // Using spherical coordinates instead of Cartesian - distance: directionalFolder.add( - directionalSettings, - 'Distance', - minDistance, - maxDistance, - distanceStep - ), altitude: directionalFolder.add( directionalSettings, 'Altitude', diff --git a/src/layout.ts b/src/layout.ts index 00956a0..69a0eae 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -225,34 +225,14 @@ export class URDFLayout extends PanelLayout { const directional = lightControl.directional; // Position controls using spherical coordinates - directional.position.distance.onChange((newDistance: number) => { - const altitude = directional.position.altitude.getValue(); - const azimuth = directional.position.azimuth.getValue(); - this._renderer.setDirectionalLightPositionSpherical( - newDistance, - altitude, - azimuth - ); - }); - directional.position.altitude.onChange((newAltitude: number) => { - const distance = directional.position.distance.getValue(); const azimuth = directional.position.azimuth.getValue(); - this._renderer.setDirectionalLightPositionSpherical( - distance, - newAltitude, - azimuth - ); + this._renderer.setDirectionalLightPositionSpherical(newAltitude, azimuth); }); directional.position.azimuth.onChange((newAzimuth: number) => { - const distance = directional.position.distance.getValue(); const altitude = directional.position.altitude.getValue(); - this._renderer.setDirectionalLightPositionSpherical( - distance, - altitude, - newAzimuth - ); + this._renderer.setDirectionalLightPositionSpherical(altitude, newAzimuth); }); // Target position controls for directional light diff --git a/src/renderer.ts b/src/renderer.ts index 8c902e7..0150ff8 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -137,7 +137,7 @@ export class URDFRenderer extends THREE.WebGLRenderer { // Directional light const directionalLight = new THREE.DirectionalLight(0xfff2cc, 1.8); directionalLight.castShadow = true; - directionalLight.position.set(5, 12, 6); + directionalLight.position.set(3, 3, 3); directionalLight.shadow.camera.top = 5; directionalLight.shadow.camera.bottom = -5; directionalLight.shadow.camera.left = -5; @@ -242,12 +242,10 @@ export class URDFRenderer extends THREE.WebGLRenderer { /** * Updates the position of the directional light using spherical coordinates * - * @param distance - Distance from target * @param altitude - Angle in radians from the horizontal plane (elevation) * @param azimuth - Angle in radians around the vertical axis */ setDirectionalLightPositionSpherical( - distance: number, altitude: number, azimuth: number ): void { @@ -256,6 +254,7 @@ export class URDFRenderer extends THREE.WebGLRenderer { ) as THREE.DirectionalLight; if (directionalLight) { + const distance = 3; const x = distance * Math.cos(altitude) * Math.cos(azimuth); const z = distance * Math.cos(altitude) * Math.sin(azimuth); const y = distance * Math.sin(altitude); From 414bb78a79bc999cced1bd224ac6d83a0d482e17 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 15 May 2025 12:00:07 +0200 Subject: [PATCH 06/10] Fix resize cursor --- src/controls.ts | 14 ++++++++++++++ style/base.css | 20 ++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 15d3f5a..d04c0db 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -274,7 +274,21 @@ export class URDFControls extends GUI { document.addEventListener('mouseup', onMouseUp); } }); + + // Show resize cursor when hovering near left edge + this.domElement.addEventListener('mousemove', (e: MouseEvent) => { + const rect = this.domElement.getBoundingClientRect(); + const offsetX = e.clientX - rect.left; + this.domElement.style.cursor = + offsetX < grabZoneWidth || isResizing ? 'ew-resize' : 'auto'; + }); + this.domElement.addEventListener('mouseleave', () => { + if (!isResizing) { + this.domElement.style.cursor = 'auto'; + } + }); } + /** * Creates controls for the different lights in the scene * diff --git a/style/base.css b/style/base.css index 6d84b22..46b53ea 100644 --- a/style/base.css +++ b/style/base.css @@ -29,16 +29,9 @@ box-sizing: border-box; min-width: 150px; max-width: 98%; - padding-bottom: 20px; -} - -/* Add a resize handle on the left border */ -.urdf-gui::before { - content: ''; - position: absolute; - width: 12px; - height: 100%; - cursor: ew-resize; + max-height: 75%; + overflow-y: auto; + overscroll-behavior-y: none; } .urdf-gui li.folder { @@ -154,6 +147,13 @@ margin: -15px 0; } +.urdf-gui .close-button { + width: 100% !important; + color: white !important; + position: sticky !important; + bottom: 0 !important; +} + .urdf-gui li.cr.number.has-slider .property-name { flex: 1 1; padding-right: 15px; From 721aaa7fcab8685515c42cf4cb1bbf9108cffc60 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 15 May 2025 12:27:25 +0200 Subject: [PATCH 07/10] Remove Target folder --- src/controls.ts | 39 ++------------------------------------- src/layout.ts | 19 ------------------- src/renderer.ts | 21 --------------------- 3 files changed, 2 insertions(+), 77 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index d04c0db..3d3596a 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -308,13 +308,7 @@ export class URDFControls extends GUI { Azimuth: Math.PI / 4, // 45 degrees around vertical axis Color: [255, 255, 255], Intensity: 1.0, - ShowHelper: false, - // Adding target controls - Target: { - X: 0, - Y: 0, - Z: 0 - } + ShowHelper: false }; const ambientSettings = { @@ -329,11 +323,6 @@ export class URDFControls extends GUI { ShowHelper: false }; - // Position limits and steps - const minPosition = -50; - const maxPosition = 50; - const positionStep = 0.1; - // Spherical coordinate angle limits and steps const minAngle = -Math.PI; const maxAngle = Math.PI; @@ -344,8 +333,7 @@ export class URDFControls extends GUI { const maxIntensity = 10; const intensityStep = 0.1; - // Target controls for directional light - const targetFolder = directionalFolder.addFolder('Target'); + // Controls for directional light this.controls.lights.directional = { position: { altitude: directionalFolder.add( @@ -363,29 +351,6 @@ export class URDFControls extends GUI { angleStep ) }, - target: { - x: targetFolder.add( - directionalSettings.Target, - 'X', - minPosition, - maxPosition, - positionStep - ), - y: targetFolder.add( - directionalSettings.Target, - 'Y', - minPosition, - maxPosition, - positionStep - ), - z: targetFolder.add( - directionalSettings.Target, - 'Z', - minPosition, - maxPosition, - positionStep - ) - }, color: directionalFolder.addColor(directionalSettings, 'Color'), intensity: directionalFolder.add( directionalSettings, diff --git a/src/layout.ts b/src/layout.ts index 69a0eae..c09b42d 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -235,25 +235,6 @@ export class URDFLayout extends PanelLayout { this._renderer.setDirectionalLightPositionSpherical(altitude, newAzimuth); }); - // Target position controls for directional light - directional.target.x.onChange((newX: number) => { - const y = directional.target.y.getValue(); - const z = directional.target.z.getValue(); - this._renderer.setDirectionalLightTarget(newX, y, z); - }); - - directional.target.y.onChange((newY: number) => { - const x = directional.target.x.getValue(); - const z = directional.target.z.getValue(); - this._renderer.setDirectionalLightTarget(x, newY, z); - }); - - directional.target.z.onChange((newZ: number) => { - const x = directional.target.x.getValue(); - const y = directional.target.y.getValue(); - this._renderer.setDirectionalLightTarget(x, y, newZ); - }); - // Color and intensity controls directional.color.onChange((newColor: number[]) => { this._renderer.setDirectionalLightColor(newColor); diff --git a/src/renderer.ts b/src/renderer.ts index 0150ff8..93a7320 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -218,27 +218,6 @@ export class URDFRenderer extends THREE.WebGLRenderer { } } - /** - * Updates the target of the directional light - * - * @param x - The x coordinate of the target - * @param y - The y coordinate of the target - * @param z - The z coordinate of the target - */ - setDirectionalLightTarget(x: number, y: number, z: number): void { - const directionalLight = this._scene.children.find( - obj => obj.type === 'DirectionalLight' - ) as THREE.DirectionalLight; - - if (directionalLight) { - directionalLight.target.position.set(x, y, z); - if (this._directionalLightHelper) { - this._directionalLightHelper.update(); - } - this.redraw(); - } - } - /** * Updates the position of the directional light using spherical coordinates * From 45da22dcc35c891f62097660e482e05c522456e5 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 15 May 2025 13:16:44 +0200 Subject: [PATCH 08/10] Reorganize folders --- src/controls.ts | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 3d3596a..8438539 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -16,7 +16,6 @@ export class URDFControls extends GUI { private _workspaceFolder: any; private _sceneFolder: any; private _jointsFolder: any; - private _lightsFolder: any; private _workingPath = ''; controls: any = { @@ -49,6 +48,9 @@ export class URDFControls extends GUI { }); // Create folders + this._jointsFolder = this.addFolder('Joints'); + this._jointsFolder.domElement.setAttribute('class', 'dg joints-folder'); + this._workspaceFolder = this.addFolder('Workspace'); this._workspaceFolder.domElement.setAttribute( 'class', @@ -57,12 +59,6 @@ export class URDFControls extends GUI { this._sceneFolder = this.addFolder('Scene'); this._sceneFolder.domElement.setAttribute('class', 'dg scene-folder'); - - this._jointsFolder = this.addFolder('Joints'); - this._jointsFolder.domElement.setAttribute('class', 'dg joints-folder'); - - this._lightsFolder = this.addFolder('Lights'); - this._lightsFolder.domElement.setAttribute('class', 'dg lights-folder'); } /** @@ -86,13 +82,6 @@ export class URDFControls extends GUI { return this._jointsFolder; } - /** - * Retrieves the folder with lights settings - */ - get lightsFolder() { - return this._lightsFolder; - } - /** * Checks if a given object is empty {} * @@ -298,9 +287,9 @@ export class URDFControls extends GUI { if (this._isEmpty(this.controls.lights)) { // Create subfolders for each light const directionalFolder = - this._lightsFolder.addFolder('Directional Light'); - const ambientFolder = this._lightsFolder.addFolder('Ambient Light'); - const hemisphereFolder = this._lightsFolder.addFolder('Hemisphere Light'); + this._sceneFolder.addFolder('Directional Light'); + const ambientFolder = this._sceneFolder.addFolder('Ambient Light'); + const hemisphereFolder = this._sceneFolder.addFolder('Hemisphere Light'); // Initialize settings for each light type const directionalSettings = { @@ -359,7 +348,9 @@ export class URDFControls extends GUI { maxIntensity, intensityStep ), - showHelper: directionalFolder.add(directionalSettings, 'ShowHelper') + showHelper: directionalFolder + .add(directionalSettings, 'ShowHelper') + .name('Show Helper') }; // Ambient light controls @@ -376,11 +367,12 @@ export class URDFControls extends GUI { // Hemisphere light controls this.controls.lights.hemisphere = { - skyColor: hemisphereFolder.addColor(hemisphereSettings, 'SkyColor'), - groundColor: hemisphereFolder.addColor( - hemisphereSettings, - 'GroundColor' - ), + skyColor: hemisphereFolder + .addColor(hemisphereSettings, 'SkyColor') + .name('Sky Color'), + groundColor: hemisphereFolder + .addColor(hemisphereSettings, 'GroundColor') + .name('Ground Color'), intensity: hemisphereFolder.add( hemisphereSettings, 'Intensity', @@ -388,11 +380,13 @@ export class URDFControls extends GUI { maxIntensity, intensityStep ), - showHelper: hemisphereFolder.add(hemisphereSettings, 'ShowHelper') + showHelper: hemisphereFolder + .add(hemisphereSettings, 'ShowHelper') + .name('Show Helper') }; - // Open main lights folder and directional subfolder - this._lightsFolder.open(); + // Open Scene (lights) and directional subfolder + this._sceneFolder.open(); directionalFolder.open(); } From 99b33cdd176aeb5f4888cfae768af90937a984b0 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 15 May 2025 16:35:58 +0100 Subject: [PATCH 09/10] Refactor and lint CSS --- style/base.css | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/style/base.css b/style/base.css index 46b53ea..d78c8fc 100644 --- a/style/base.css +++ b/style/base.css @@ -10,7 +10,7 @@ --gui-color-input-bg: color-mix( in hsl, var(--jp-layout-color1), - var(--jp-layout-color2) + var (--jp-layout-color2) ); --gui-color-font: var(--jp-ui-font-color1); --gui-color-accent: var(--jp-brand-color0); @@ -55,11 +55,23 @@ justify-content: center; } +.urdf-gui li.cr.string .property-name { + flex: 1 1; +} + +.urdf-gui li.cr.color .property-name { + flex: 1 1; +} + .urdf-gui .cr.function .property-name:hover { background: var(--gui-color-accent); border: 1px solid var(--gui-color-accent); } +.urdf-gui li.cr.number.has-slider .property-name { + flex: 1 1; +} + .urdf-gui .cr.color, .urdf-gui .cr.number, .urdf-gui .cr.function, @@ -134,19 +146,7 @@ overflow: scroll; } -/* Style for Dat.GUI's close button */ -.urdf-gui .close-button { - width: 100% !important; - color: white !important; - position: absolute; -} - -/* Expand hover area to reach color pickers */ -.urdf-gui .cr.color .c:hover { - padding: 15px 0; - margin: -15px 0; -} - +/* Style for Dat.GUI's close button (sticky at bottom) */ .urdf-gui .close-button { width: 100% !important; color: white !important; @@ -154,22 +154,30 @@ bottom: 0 !important; } -.urdf-gui li.cr.number.has-slider .property-name { - flex: 1 1; - padding-right: 15px; -} - .urdf-gui li.cr.number.has-slider .property-name:hover { overflow-x: auto; text-overflow: unset; } -/* Adjust the control container */ +.urdf-gui li.cr.string .c, +.urdf-gui li.cr.color .c { + flex: 0 1 180px; + margin-left: auto; +} + +/* Expand hover area to reach color pickers */ +.urdf-gui .cr.color .c:hover { + padding: 15px 0; + margin: -15px 0; +} + .urdf-gui li.cr.number.has-slider .c { flex: 0 1 180px; margin-left: auto; } +li.cr.color > div, +li.cr.string > div, li.cr.number.has-slider > div { display: flex; } From e720faf3ee1c4f85f4b53ab8c39133d73bee5cc3 Mon Sep 17 00:00:00 2001 From: Yahiewi Date: Thu, 15 May 2025 17:09:00 +0100 Subject: [PATCH 10/10] Fix panda lighting --- .../meshes/visual/link0.dae | 86 ------------------- 1 file changed, 86 deletions(-) diff --git a/examples/franka_panda_description/meshes/visual/link0.dae b/examples/franka_panda_description/meshes/visual/link0.dae index dc4c718..021660b 100644 --- a/examples/franka_panda_description/meshes/visual/link0.dae +++ b/examples/franka_panda_description/meshes/visual/link0.dae @@ -50,92 +50,6 @@ - - - - - 1000 1000 1000 - 1 - 0 - 0.00111109 - - - - - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 0 - 0 - 0 - 1000 - 29.99998 - 75 - 0.15 - 0 - 1 - 2 - 0.04999995 - 30.002 - 1 - 3 - 2880 - 3 - 1 - 1 - 0.1 - 0.1 - 1 - - - - - - - 1000 1000 1000 - 1 - 0 - 0.00111109 - - - - - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 0 - 0 - 0 - 1000 - 29.99998 - 75 - 0.15 - 0 - 1 - 2 - 0.04999995 - 30.002 - 1 - 3 - 2880 - 3 - 1 - 1 - 0.1 - 0.1 - 1 - - - -