jupyter-widgets / pythreejs

A Jupyter - Three.js bridge
https://pythreejs.readthedocs.io
Other
951 stars 188 forks source link

`DirectionalLight` has no target #81

Closed vidartf closed 6 years ago

vidartf commented 7 years ago

Three's DirectionalLight should have a target in addition to position. I also notice that the position and castShadow attributes of DirectionalLight are not correctly synced to the browser (at least, according to the console log).

For the following Python code:

light = pythreejs.DirectionalLight(
    intensity=0.6,
    position=[20., -20., 10.],
    castShadow=True,
    color='red',
)

The following is logged in the browser console:


THREE.DirectionalLight:

castShadow: false,
children: Array[0]
color: THREE.Color
eulerOrder: (...)
frustumCulled: true
id: 96
intensity: 0.6
layers: THREE.Layers
matrix: THREE.Matrix4
matrixAutoUpdate: true
matrixWorld: THREE.Matrix4
matrixWorldNeedsUpdate: false
modelViewMatrix: THREE.Matrix4
name: ""
needsUpdate: true
normalMatrix: THREE.Matrix3
parent: THREE.Scene
position: THREE.Vector3
quaternion: THREE.Quaternion
receiveShadow: undefined
renderOrder: 0
rotation: THREE.Euler
rotationAutoUpdate: true
scale: THREE.Vector3
shadow: THREE.LightShadow
target: THREE.Object3D
threejs_view: child
type: "DirectionalLight"
up: THREE.Vector3
useQuaternion: (...)
userData: Object
uuid: "57BA8404-C7C1-46C7-A1AC-6D456318C9C1"
visible: true
__proto__: THREE.Light

It does however work for Meshes.

vidartf commented 7 years ago

Note: I added the light to the scene, and not the camera (which I see is common in the examples). This was done as I do not want the light to rotate together with the camera.

jasongrout commented 7 years ago

Can you see if #82 solves the castShadow not updating problem?

jasongrout commented 7 years ago

Please note that all 3d objects have a look_at method which can set the 'target': d=DirectionalLight(); d.look_at(d.position, target.position).

vidartf commented 7 years ago

@jasongrout Regarding the look_at function, as far as I can tell it sets the rotation of the object? If so, this won't work for DirectionalLight. From its docs:

A Note about Position, Target and rotation: A common point of confusion for directional lights is that setting the rotation has no effect. This is because three.js's DirectionalLight is the equivalent to what is often called a 'Target Direct Light' in other applications. This means that its direction is calculated as pointing from the light's position to the target's position (as opposed to a a 'Free Direct Light' that just has a rotation component). The reason for this is to allow the light to cast shadows - the shadow camera needs a position to calculate shadows from.

The target is of course not strictly needed - one could instead to an appropriate modification of the position - but the abstraction is nice to have (especially as you can set the target to another object).

jasongrout commented 7 years ago

Thanks for quoting the docs. It looks like we need to expose the target then. Perhaps the target should be another object3d, which the light will follow?

vidartf commented 7 years ago

The docs says that it will accept anything that has a valid position attribute, but specifying it as another object3d should work well enough.

vidartf commented 7 years ago

This works partially in master: You can set the target after light initialization, but if set in the constructor call as a keyword argument the target object disappears. The mechanisms dealing with such objects (InitializedThreeType) need an overhaul.