Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PointLightHelper and SpotLightHelper positioning problem #20311

Closed
2 tasks done
gospodnetic opened this issue Sep 10, 2020 · 13 comments
Closed
2 tasks done

PointLightHelper and SpotLightHelper positioning problem #20311

gospodnetic opened this issue Sep 10, 2020 · 13 comments

Comments

@gospodnetic
Copy link

Description of the problem

When added to the light, PointLightHelper and SpotLightHelper have wrong position.
Their position relative to the light is the same as the position of the light in world coordinates, which causes displacement.

You can see it in the fiddle for PointLightHelper, the box is of size (2,2,2) and the light is displaced by 1 along the x-axis. Correct behavior would be that the origin of the marker coincides with box side, however, it is double the distance.
https://jsfiddle.net/c14r0qmt/8/

I've found that the problem comes from copying the world matrix of the original light:

this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;

https://github.com/mrdoob/three.js/blob/dev/src/helpers/PointLightHelper.js#L14-L15
https://github.com/mrdoob/three.js/blob/dev/src/helpers/SpotLightHelper.js#L18-L19

Removing those lines solves the problem

Three.js version
  • r120
Browser
  • Chrome
@Mugen87
Copy link
Collaborator

Mugen87 commented Sep 10, 2020

The implementation assumes that both helpers are always added to the scene and not as a child to their reference object.

https://jsfiddle.net/4uw91hdk/

@gospodnetic
Copy link
Author

Got it, I was led by the reimplementation of RectAreaLightHelper which does not require that.

Thinking about it, does it make sense to add the helper separately though? IMHO, adding it to the light and not having to care about it separately afterwards makes more sense.

@Mugen87
Copy link
Collaborator

Mugen87 commented Sep 10, 2020

The management of helpers in three.js is not consistent and sometimes confusing as this issue proves. I personally think it's way more intuitive if helper objects are attached to their reference objects and not added to the scene.

I'm not sure if this topic was ever discussed at GitHub but this is a good opportunity to do so.

@WestLangley
Copy link
Collaborator

WestLangley commented Sep 10, 2020

This topic has been discussed, and the convention from the early days of three.js has been helpers must be added a child of the scene.

The exception, now, is RectAreaLightHelper. See #14935.

To make light helpers internally-consistent, see #14658, the primary objective of which is to remove targets from lights.

EDIT: To clarify, if lights were governed by their quaternion, then we could add all light helpers as a child of the light.

@Mugen87
Copy link
Collaborator

Mugen87 commented Sep 10, 2020

This topic has been discussed

Any chances to share the respective GitHub issue? Besides, only because it was discussed once it does not mean the right decision was made.

@WestLangley
Copy link
Collaborator

#3470 is from 2013. Maybe it will be helpful in understanding the history of this.

@mrdoob
Copy link
Owner

mrdoob commented Sep 10, 2020

I have a suggestion.

I think we can override updateMatrixWorld in helpers so it just copies the matrixWorld of the target object.

That way it would not matter where in the scenegraph the user places the helper.

Helpers would behave as expected and users won't have to think about this.

@WestLangley what do you think?

@WestLangley
Copy link
Collaborator

As a test, I got your idea to work with RectAreaLighHelper.

I had to use onBeforeRender(). Consequently, calling update() in the render loop was no longer required. (Do you recall the reason we defined update() instead of onBeforeRender()?)

@mrdoob
Copy link
Owner

mrdoob commented Sep 11, 2020

Do you recall the reason we defined update() instead of onBeforeRender()?

I think onBeforeRender() was not implemented until many years later 👴

@DefinitelyMaybe
Copy link
Contributor

I'd be keen to help out with this.

@Mugen87
Copy link
Collaborator

Mugen87 commented Sep 21, 2020

BTW: If Object3D.matrix should be private at some day, this pattern should be avoided:

this.matrix = light.matrixWorld;

I mean changing the value of Object3D.matrix with the assignment operator. It's not good coding style anway.

I think it would be better if Object3D.matrix and Object3D.matrixWorld are part of this code block (and are at least not writable).

Object.defineProperties( this, {
	position: {
		configurable: true,
		enumerable: true,
		value: position
	},
	rotation: {
		configurable: true,
		enumerable: true,
		value: rotation
	},
	quaternion: {
		configurable: true,
		enumerable: true,
		value: quaternion
	},
	scale: {
		configurable: true,
		enumerable: true,
		value: scale
	},
	modelViewMatrix: {
		value: new Matrix4()
	},
	normalMatrix: {
		value: new Matrix3()
	}
} );

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 16, 2021

I think we can override updateMatrixWorld in helpers so it just copies the matrixWorld of the target object. That way it would not matter where in the scenegraph the user places the helper.

Unfortunately, this design can easily lead to frame-late effects like described in #21427. Having a reference of the target object's world matrix does not mean it is up-to-date.

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 11, 2022

The OP's original problem was actually solved. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants