瀏覽代碼

Improved PointLightHelper.

Mr.doob 4 月之前
父節點
當前提交
3dca42fa2d
共有 5 個文件被更改,包括 150 次插入104 次删除
  1. 14 0
      editor/index.html
  2. 0 26
      editor/js/Editor.js
  3. 14 0
      editor/js/Viewport.js
  4. 118 60
      src/helpers/PointLightHelper.js
  5. 4 18
      test/unit/src/helpers/PointLightHelper.tests.js

+ 14 - 0
editor/index.html

@@ -122,6 +122,20 @@
 
 						editor.selectByUuid( selected );
 
+						// Update PointLightHelper showRange for restored selection
+
+						for ( const id in editor.helpers ) {
+
+							const helper = editor.helpers[ id ];
+
+							if ( helper.isPointLightHelper ) {
+
+								helper.showRange = ( helper.light === editor.selected );
+
+							}
+
+						}
+
 					}
 
 				} );

+ 0 - 26
editor/js/Editor.js

@@ -396,32 +396,6 @@ Editor.prototype = {
 
 					helper = new THREE.PointLightHelper( object, 1 );
 
-					helper.matrix = new THREE.Matrix4();
-					helper.matrixAutoUpdate = true;
-
-					const light = object;
-					const editor = this;
-
-					helper.updateMatrixWorld = function () {
-
-						light.getWorldPosition( this.position );
-
-						const distance = editor.viewportCamera.position.distanceTo( this.position );
-						this.scale.setScalar( distance / 30 );
-
-						this.updateMatrix();
-						this.matrixWorld.copy( this.matrix );
-
-						const children = this.children;
-
-						for ( let i = 0, l = children.length; i < l; i ++ ) {
-
-							children[ i ].updateMatrixWorld();
-
-						}
-
-					};
-
 				} else if ( object.isDirectionalLight ) {
 
 					helper = new THREE.DirectionalLightHelper( object, 1 );

+ 14 - 0
editor/js/Viewport.js

@@ -412,6 +412,20 @@ function Viewport( editor ) {
 		selectionBox.visible = false;
 		transformControls.detach();
 
+		// Hide range on all PointLightHelpers, then show for selected
+
+		for ( const id in editor.helpers ) {
+
+			const helper = editor.helpers[ id ];
+
+			if ( helper.isPointLightHelper ) {
+
+				helper.showRange = ( helper.light === object );
+
+			}
+
+		}
+
 		if ( object !== null && object !== scene && object !== camera ) {
 
 			box.setFromObject( object, true );

+ 118 - 60
src/helpers/PointLightHelper.js

@@ -1,40 +1,79 @@
-import { Mesh } from '../objects/Mesh.js';
-import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js';
-import { SphereGeometry } from '../geometries/SphereGeometry.js';
+import { LineSegments } from '../objects/LineSegments.js';
+import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
+import { Float32BufferAttribute } from '../core/BufferAttribute.js';
+import { BufferGeometry } from '../core/BufferGeometry.js';
+import { Vector3 } from '../math/Vector3.js';
+
+const _cameraWorldPosition = /*@__PURE__*/ new Vector3();
+
+function createCirclesGeometry() {
+
+	const geometry = new BufferGeometry();
+	const positions = [];
+	const segments = 32;
+
+	for ( let i = 0, j = 1; i < segments; i ++, j ++ ) {
+
+		const p1 = ( i / segments ) * Math.PI * 2;
+		const p2 = ( j / segments ) * Math.PI * 2;
+
+		// XY plane circle
+		positions.push( Math.cos( p1 ), Math.sin( p1 ), 0 );
+		positions.push( Math.cos( p2 ), Math.sin( p2 ), 0 );
+
+		// XZ plane circle
+		positions.push( Math.cos( p1 ), 0, Math.sin( p1 ) );
+		positions.push( Math.cos( p2 ), 0, Math.sin( p2 ) );
+
+		// YZ plane circle
+		positions.push( 0, Math.cos( p1 ), Math.sin( p1 ) );
+		positions.push( 0, Math.cos( p2 ), Math.sin( p2 ) );
+
+	}
+
+	geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+
+	return geometry;
+
+}
 
 /**
- * This displays a helper object consisting of a spherical mesh for
- * visualizing an instance of {@link PointLight}.
+ * This displays a helper object consisting of three orthogonal circles
+ * for visualizing an instance of {@link PointLight}.
+ * The circles maintain constant screen-space size regardless of distance.
  *
  * ```js
- * const pointLight = new THREE.PointLight( 0xff0000, 1, 100 );
+ * const pointLight = new THREE.PointLight( 0xff0000, 1 );
  * pointLight.position.set( 10, 10, 10 );
  * scene.add( pointLight );
  *
- * const sphereSize = 1;
- * const pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
+ * const pointLightHelper = new THREE.PointLightHelper( pointLight );
  * scene.add( pointLightHelper );
  * ```
  *
- * @augments Mesh
+ * @augments LineSegments
  */
-class PointLightHelper extends Mesh {
+class PointLightHelper extends LineSegments {
 
 	/**
 	 * Constructs a new point light helper.
 	 *
 	 * @param {PointLight} light - The light to be visualized.
-	 * @param {number} [sphereSize=1] - The size of the sphere helper.
-	 * @param {number|Color|string} [color] - The helper's color. If not set, the helper will take
-	 * the color of the light.
+	 * @param {number} [size=1] - The size of the helper.
 	 */
-	constructor( light, sphereSize, color ) {
+	constructor( light, size = 1 ) {
 
-		const geometry = new SphereGeometry( sphereSize, 4, 2 );
-		const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
+		const geometry = createCirclesGeometry();
+		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
 
 		super( geometry, material );
 
+		// Range/distance circles
+		const rangeGeometry = createCirclesGeometry();
+		const rangeMaterial = new LineBasicMaterial( { fog: false, toneMapped: false, opacity: 0.5, transparent: true } );
+		this.range = new LineSegments( rangeGeometry, rangeMaterial );
+		this.add( this.range );
+
 		/**
 		 * The light being visualized.
 		 *
@@ -43,43 +82,29 @@ class PointLightHelper extends Mesh {
 		this.light = light;
 
 		/**
-		 * The color parameter passed in the constructor.
-		 * If not set, the helper will take the color of the light.
+		 * The size of the helper.
 		 *
-		 * @type {number|Color|string}
+		 * @type {number}
 		 */
-		this.color = color;
-
-		this.type = 'PointLightHelper';
-
-		this.matrix = this.light.matrixWorld;
-		this.matrixAutoUpdate = false;
-
-		this.update();
-
-
-		/*
-	// TODO: delete this comment?
-	const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
-	const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
-
-	this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
-	this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
-
-	const d = light.distance;
-
-	if ( d === 0.0 ) {
+		this.size = size;
 
-		this.lightDistance.visible = false;
+		/** @private */
+		this._showRange = false;
 
-	} else {
+		this.range.visible = false;
 
-		this.lightDistance.scale.set( d, d, d );
+		/**
+		 * This flag can be used for type testing.
+		 *
+		 * @type {boolean}
+		 * @readonly
+		 * @default true
+		 */
+		this.isPointLightHelper = true;
 
-	}
+		this.type = 'PointLightHelper';
 
-	this.add( this.lightDistance );
-	*/
+		this.matrixAutoUpdate = false;
 
 	}
 
@@ -92,40 +117,73 @@ class PointLightHelper extends Mesh {
 		this.geometry.dispose();
 		this.material.dispose();
 
+		this.range.geometry.dispose();
+		this.range.material.dispose();
+
 	}
 
 	/**
-	 * Updates the helper to match the position of the
-	 * light being visualized.
+	 * Whether to show the range circles indicating the light's distance.
+	 *
+	 * @type {boolean}
+	 * @default false
+	 */
+	get showRange() {
+
+		return this._showRange;
+
+	}
+
+	set showRange( value ) {
+
+		this._showRange = value;
+		this.range.visible = value && this.light.distance > 0;
+
+	}
+
+	/**
+	 * Updates the helper.
 	 */
 	update() {
 
+	}
+
+	onBeforeRender( renderer, scene, camera ) {
+
 		this.light.updateWorldMatrix( true, false );
+		this.position.setFromMatrixPosition( this.light.matrixWorld );
+
+		// Calculate scale for constant screen-space size
 
-		if ( this.color !== undefined ) {
+		_cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
+		const distance = this.position.distanceTo( _cameraWorldPosition );
 
-			this.material.color.set( this.color );
+		if ( camera.isPerspectiveCamera ) {
+
+			const fov = camera.fov * ( Math.PI / 180 );
+			const scale = distance * Math.tan( fov / 2 ) * this.size * 0.04;
+			this.scale.setScalar( scale );
 
 		} else {
 
-			this.material.color.copy( this.light.color );
+			const scale = this.size * 2 / camera.zoom;
+			this.scale.setScalar( scale );
 
 		}
 
-		/*
-		const d = this.light.distance;
-
-		if ( d === 0.0 ) {
+		this.updateMatrix();
+		this.matrixWorld.copy( this.matrix );
 
-			this.lightDistance.visible = false;
+		// Update range circles based on light distance
 
-		} else {
+		if ( this.range.visible ) {
 
-			this.lightDistance.visible = true;
-			this.lightDistance.scale.set( d, d, d );
+			const lightDistance = this.light.distance;
+			this.range.scale.setScalar( lightDistance / this.scale.x );
+			this.range.updateMatrix();
+			this.range.matrixWorld.multiplyMatrices( this.matrixWorld, this.range.matrix );
 
 		}
-		*/
 
 	}
 

+ 4 - 18
test/unit/src/helpers/PointLightHelper.tests.js

@@ -1,6 +1,5 @@
 import { PointLightHelper } from '../../../../src/helpers/PointLightHelper.js';
 
-import { Mesh } from '../../../../src/objects/Mesh.js';
 import { PointLight } from '../../../../src/lights/PointLight.js';
 
 export default QUnit.module( 'Helpers', () => {
@@ -8,30 +7,17 @@ export default QUnit.module( 'Helpers', () => {
 	QUnit.module( 'PointLightHelper', () => {
 
 		const parameters = {
-			sphereSize: 1,
+			size: 1,
 			color: 0xaaaaaa,
 			intensity: 0.5,
-			distance: 100,
 			decay: 2
 		};
 
-		// INHERITANCE
-		QUnit.test( 'Extending', ( assert ) => {
-
-			const light = new PointLight( parameters.color );
-			const object = new PointLightHelper( light, parameters.sphereSize, parameters.color );
-			assert.strictEqual(
-				object instanceof Mesh, true,
-				'PointLightHelper extends from Mesh'
-			);
-
-		} );
-
 		// INSTANCING
 		QUnit.test( 'Instancing', ( assert ) => {
 
 			const light = new PointLight( parameters.color );
-			const object = new PointLightHelper( light, parameters.sphereSize, parameters.color );
+			const object = new PointLightHelper( light, parameters.size );
 			assert.ok( object, 'Can instantiate a PointLightHelper.' );
 
 		} );
@@ -40,7 +26,7 @@ export default QUnit.module( 'Helpers', () => {
 		QUnit.test( 'type', ( assert ) => {
 
 			const light = new PointLight( parameters.color );
-			const object = new PointLightHelper( light, parameters.sphereSize, parameters.color );
+			const object = new PointLightHelper( light, parameters.size );
 			assert.ok(
 				object.type === 'PointLightHelper',
 				'PointLightHelper.type should be PointLightHelper'
@@ -54,7 +40,7 @@ export default QUnit.module( 'Helpers', () => {
 			assert.expect( 0 );
 
 			const light = new PointLight( parameters.color );
-			const object = new PointLightHelper( light, parameters.sphereSize, parameters.color );
+			const object = new PointLightHelper( light, parameters.size );
 			object.dispose();
 
 		} );

粤ICP备19079148号