Three.js light object3d and tween - three.js

I'm struggling in my attempt to light an object, make it tween towards camera and have the light follow the tween.
Basically I want to darken the background and tween a 3D object towards the camera, and set a directional light pointing at it so it has nice, smooth, uniform lighting.
Directional lights i add to the object don't show up, latest I've tried is:
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.position.set( 0, 0, -100);
directionalLight.lookAt(object);
directionalLight.shadowCameraVisible = true;
object.add( directionalLight );
I've also tried PointLights near the camera, these kind of work but it's a very sharp light, not smooth and doesn't seem to light all the objects the same.
Using something like this
hslight1 = new THREE.PointLight( 0xffffff,0.9,100 );
hslight1.position.set(0,10,0);
scene.add( hslight1 );
hslight2 = new THREE.PointLight( 0xffffff,0.9,100 );
hslight2.position.set(0,0,0);
scene.add( hslight2 );
Anyone get any ideas on any way to uniformly light an object3D that is tweening towards the camera using
var dist = (size/screen) * (object.scale.x * 2);
var pLocal = new THREE.Vector3( 0, 0, -dist );
var target = pLocal.applyMatrix4( camera.matrixWorld );
var tweenMove = new TWEEN.Tween(object.position).to(target, 1500).easing(TWEEN.Easing.Cubic.InOut);
tweenMove.onUpdate(function(){object.lookAt(camera.position);});

Fixed this by adding the light to the camera
camera.add( light );

Related

Adding spotlight effect on an object in the scene using three.js

I'm trying to add a spotlight effect on different parts of my scene but for some reason I'm unable to accomplish it. I tried using PointLight and SpotLight but they both didn't work.
Example of the code
var pointLight = new THREE.PointLight( 0xffffff, 1, 10 );
pointLight.position.set(obj.position);
scene.add( pointLight );
The light effect doesn't need to follow the mouse movement. It just needs to appear after specific event trigger.
I'm not sure if the spotLight or the pointLight is the right way to do this.
I appreciate any feedback on what approach I should take and what is the best way to accomplish this animation.
Attempted adding SpotLight like so
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 0, 0, 0 );
spotLight.shadow.mapSize.width = 512;
spotLight.shadow.mapSize.height = 512;
spotLight.target = obj;
spotLight.intensity = 2;
scene.add( spotLight );
var spotLightHelper = new THREE.SpotLightHelper( spotLight );
scene.add( spotLightHelper );

three.js light from camera straight to object

in my three js setting I have the following settings for a directional light:
private aLight: THREE.DirectionalLight;
this.aLight = new THREE.DirectionalLight(0xffffff, 1.0);
this.aLight.position.set(-5, 5, 5);
this.aScene.add(this.aLight);
In order to have the light following my camera and always illuminate my mesh I set the following in my render function:
private onRender() {
this.aLight.position.copy(this.aCamera.getWorldPosition());
window.requestAnimationFrame(_ => this.onRender());
this.aRenderer.render(this.aScene, this.aCamera);
Now, the object is always illuminated:
but if I zoom in the surfaces facing the camera are dark:
I would like to have my light always pointing from my camera to the object. What am I doing wrong?
If you want a light source to be coincident with your camera, the easiest solution is to use a point light and add it as a child of the camera. You can uses a pattern like this:
camera.position.set( 10, 10, 10 );
scene.add( camera ); // required in this case since the camera will have a child
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) ); // optional
// light
var light = new THREE.PointLight( 0xffffff, 1 );
camera.add( light );
If you are using a directional light, remember that a directional light has a target property, an Object3D. So if you zoom in, you will likely have to change target.position. Using a point light, as I explained above, is easier.
three.js r.86

three.js r75 pointLight shadows in wrong places

I have a jsfiddle containing a fixed Sun and Moons and a moving planet Earth which orbits the Sun.
Here is the code for the two Lights (Ambient and Point) and example objects.
var light2 = new THREE.AmbientLight(0x444444);//... for lighting the Sun and other MeshBasicMaterial meshes.
scene.add(light2);
//... PointLight
// http://threejs.org/docs/#Reference/Lights/PointLight
var light3 = new THREE.PointLight( 0xffffff, 10, 150000,1);
light3.castShadow = true;
light3.shadow.camera.near = 1;
light3.shadow.camera.far = 5000;
light3.shadow.camera.fov = 90;
// light3.shadowCameraVisible = true;
light3.shadow.bias = 0.001;
scene.add( light3 );
// SPHERES
var sphereGeom = new THREE.SphereGeometry( 40, 32, 16 );
var SunMaterial = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
this.Sun01 = new THREE.Mesh( sphereGeom.clone(), SunMaterial );
Sun01.position.set(-500, 0, 220);
scene.add( Sun01 );
//Sun01.castShadow = false;
//Sun01.receiveShadow = false;
light3.position.set( Sun01.position.x, Sun01.position.y , Sun01.position.z);
var moonMaterial = new THREE.MeshPhongMaterial( { color: 0xaa00aa } );
var Moon02 = new THREE.Mesh( sphereGeom.clone(), moonMaterial );
Moon02.scale.set( 0.5,0.5,0.5 );
Moon02.position.set(-200, 0, 220);
scene.add( Moon02 );
Moon02.castShadow = true;
Moon02.receiveShadow = false;
There are two problems.
Firstly distant fixed moons are not illuminated by the PointLight even though they are within range.
Secondly shadows from the distant moons appear on the (Sun-orbitting) Earth even though the Earth is nearer the Sun than those fixed moons.
Note that an inner fixed moon (named Moon02, magenta in color) does get illuminated by the PointLight and it does cast a shadow on the Earth.
Here is the Renderer set-up code:-
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0x000022 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
//... Enable Shadows
renderer.shadowMap.enabled = true;//.shadowMapEnabled = true;
//renderer.shadowMap.type = THREE.BasicShadowMap;//
//renderer.shadowMap.type = THREE.PCFShadowMap
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
My Question = What needs to be done to (a) illuminate the outer moons and (b) ensure the shadows of outer moons do not appear on the (inner, nearer-to-Sun) planet Earth.
Simply put, you're spacing things out too far.
Calculating shadows from a point light is very expensive. In fact, THREE.js only added functionality for it a few months ago. I can't find anything solid in the documentation yet, but it seems likely that there's a hard coded limit on how far out shadows will be calculated from a point light.
The solution is easy: reduce the space between your objects. There's absolutely no reason that objects need to be thousands of units away from each other when a dozen will suffice. I solved both of your problems just by reducing all distances and scales by a factor of 10. I also tweaked the intensity of the PointLight because 10 was pretty harsh haha.
// color, intensity, falloff radius, falloff amount
// if falloff radius is 0 then there is no falloff
var light3 = new THREE.PointLight( 0xffffff, 1, 0, 0);

why can't orbit control work with a sphere instead of camera in three js?

I want to spin a sphere, so I wonder if orbit controls could work for that.
However, code below won't work:
var geometry = new THREE.SphereGeometry(16, 16, 16);
var material = new THREE.MeshNormalMaterial();
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var controls = new THREE.OrbitControls(mesh);
//then inside the animation loop
controls.update();
It seems like orbit controls only works when argument is camera. why?
You must pass the camera to the Orbit.
Like this:
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 0, 1000, 1000 );
var controls = new THREE.OrbitControls( camera );
This helps?
I don't think orbit controls work like that, the camera revolves around a point, it doesn't 'spin' that point. You can however change the target of the orbit controls to the sphere's position vector, allowing the camera to revolve around the sphere's position:
controls.target.copy(mesh.position);

how is the final color of a rendered mesh is determined?

We give color while initializing a material. We also specify a color while initializing ambient and directional light sources. How is the final color of the mesh is determined.
I see no change in the final color of mesh when i change the color of the material. However the rendered color of the mesh is changing while i change the color of light sources (ambient or directional).
So
1) what is the use of specifying a color, while initializing a material ?, and
2) How is the final color of the mesh is determined
darkMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
darkMaterialL = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
darkMaterialP = new THREE.MeshPhongMaterial( { color: 0xffff00 } );
var ambientLight = new THREE.AmbientLight(0x00ff00);
var light = new THREE.PointLight(0x000000);
light.position.set(0,150,100);
scene.add(ambientLight);
scene.add(light);
The above are the lights and materials i used.
I wrote a jsfiddle for you to take a look at: http://jsfiddle.net/fnR4E/
var camera, scene, renderer;
var geometry = new Array();
var material = new Array();
var mesh = new Array();
var light;
var angle = 0.1;
init();
render();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 5;
camera.position.y = 5;
scene = new THREE.Scene();
geometry[0] = new THREE.SphereGeometry(1, 8, 6, 0, Math.PI * 2, 0, Math.PI);
geometry[1] = new THREE.SphereGeometry(1, 8, 6, 0, Math.PI * 2, 0, Math.PI);
geometry[2] = new THREE.SphereGeometry(1, 8, 6, 0, Math.PI * 2, 0, Math.PI);
material[0] = new THREE.MeshBasicMaterial({ color: 0xff0000 });
material[1] = new THREE.MeshLambertMaterial({ ambient: 0xffffff, color: 0x00FF00 });
material[2] = new THREE.MeshPhongMaterial({ ambient: 0xffffff, color: 0xdddddd, specular: 0xFFFFFF, shininess: 15 });
mesh[0] = new THREE.Mesh(geometry[0], material[0]);
mesh[1] = new THREE.Mesh(geometry[1], material[1]);
mesh[2] = new THREE.Mesh(geometry[2], material[2]);
var ambientLight = new THREE.AmbientLight(0x007700);
var light = new THREE.PointLight(0xFFFFFF);
light.position.set(0, 2, 0);
scene.add(ambientLight);
scene.add(light);
mesh[0].position.set(-2, 0, 0);
mesh[2].position.set(2, 0, 0);
scene.add(mesh[0]);
scene.add(mesh[1]);
scene.add(mesh[2]);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function render() {
requestAnimationFrame(render);
camera.position.x = 5 * Math.cos(angle);
camera.position.z = 5 * Math.sin(angle);
camera.lookAt(new THREE.Vector3(0, 0, 0));
angle += 0.01;
renderer.render(scene, camera);
}
The first mesh is using MeshBasicMaterial which essentially means it is lit by material color alone, for proof you can change the values of ambientLight and light to whatever you want and it won't effect the rendered color of this mesh.
The following two meshes (the first is MeshLambertMaterial and the second is MeshPhongMaterial) use both lights. For additional reading on the theory behind each of the shading models (Lambertian and Phong) check out these excellent wikipedia articles:
http://en.wikipedia.org/wiki/Lambertian_reflectance
http://en.wikipedia.org/wiki/Phong_reflection_model
Here is a more "practical" explanation of what is going on (but you'll probably at least want to refer to the wiki articles for the equations that are discussed below):
The ambientLight is multiplied by the material 'ambient' value to produce the mesh ambient color. This color only gets used up to the amount specified by the diffuse color of the material. For example, if material ambient value is 0xFFFFFF and AmbientLight is 0x00FF00 then the mesh has a fully green ambient light - but, if the diffuse color of the material ('color') contains NO green color channel (e.g. 0xFF00FF) then there is no ambient light applied to the mesh. Alternatively, if there is a diffuse color of 0x007700 (half of the full green channel) then you will see ambient light on the object of the color 0x007700.
The diffuse color is denoted by the material 'color' value. This is the perceived color of the mesh. In both the Lambert and BlinnPhong shading models this color is multiplied by the dot product of the vertex or fragment normal with the light vector. In essence, this means that the more directly lit a vertex or fragment is - the closer to the full diffuse color it will be. A vertex or fragment that is not directly lit by a light source at all is black. AmbientLight sources are not included in this dot product calculation.
NOTE: Occluding meshes are not accounted for in this dot product calculation. Only the angle between the light source and the vertex or fragment is considered.
Finally, the MeshPhongMaterial uses an additional property called specular. This is the reflective light that produces the "shiny" spot on a mesh. This comes from calculating the angle of reflection against the normal from the light source. The material property 'specular' determines the color of this reflection spot. Once again, AmbientLight sources are not included in this lighting calculation.
NOTE: Once again, occluding meshes are not accounted for in this calculation.
Fixed the problem.

Resources