Ray intersection and child camera - three.js

I've been playing with three.js for few weeks now and got few inconsistencies on ray casting.
Here is a simplified version demonstrating one of the bug I encoutered :
http://jsfiddle.net/eMrhb/12/
The camera is added to the sphere mesh for further use of TrackBallControl for example.
scene.add(mesh);
mesh.add(camera);
Clicking a few times on the sphere and opening the console, show us none of the expected intersections between the ray and the mesh.
Adding the camera to the scene (http://jsfiddle.net/eMrhb/9/), solves the problem:
scene.add(mesh);
scene.add(camera);
But I could use a much more complex hierarchy between my scene objects and the camera to suit my needs.
Is this a limitation? If it is, is there any workarounds I could use?

Yes, this is fixable.
If the camera is a child of another object that is rotated and or translated, then your have to use a different pattern in ray casting.
Instead of this familiar pattern:
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
You have to use this pattern instead:
var position = camera.matrixWorld.getPosition().clone();
var ray = new THREE.Ray( position, vector.subSelf( position ).normalize() );
three.js r.53

Related

Three.js - change camera POV on click

Some project background:
I have a Sprite particle field that is randomly generated. The camera is located at position 0, 0, 0. The particle field is all around the camera. I'm using Raycaster to be able to select the particle that is clicked on and change it's color. Once clicked I would like the camera to focus on this particle. I'm also attempting to use Tween to glide the particle into view.
I've attempted several different methods and none of them work. They are described here:
A traditional lookAt method that used Raycaster to pick up the intersect point from clicking.
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
var intersects = raycaster.intersectObjects( this.starfield.children );
this.camera.lookAt(intersects[0].object.position)
A distanceTo method where the distance between the camera and the intersect coordinates is used to move the camera. This only moves the camera along the z plane. It wont actually change its POV.
var cameraPosition = new THREE.Vector3(this.camera.position.x, this.camera.position.y, this.camera.position.z);
var intersectPosition = new THREE.Vector3(intersects[0].object.position.x, intersects[0].object.position.y , intersects[0].object.position.z );
var zoomPos = intersectPosition.distanceTo( cameraPosition );
const newCameraPosition = cameraPosition.addVectors(this.camera.position, vector.setLength(zoomPos));
I calculated the angle of rotation for each X, Y, and Z axis via tan and cos equations. I then attempted to rotate the camera by those degrees. I even tried converting them to radians to see if that would make a difference with the rotation method. It didnt :(
I don't know what else to do. At this stage I'm completely open to a different approach as long as I get this camera working. I'm very stuck,
any help would be greatly appreciated!
Instead of using
intersects[0].object.position
try using
intersects[0].point
.point is the world space position of the hit.
.objectis the object the triangle belongs to. .object.position is just the origin of that object, in this case the particle system. The particle positions themselves are relative to this origin.

How to add lights to a Mesh generated by BufferGeometry and drawed as TriangleStrips?

I'm trying to add lights to a scene where there is a Mesh created by BufferGeometry. The mesh.drawMode is THREE.TriangleStripDrawMode. I don't know why light is not applying to the mesh.
There is an example bellow:
https://jsbin.com/jofasabeji/edit?js,output
Is there a flag to be activated (like face culling)?
Thanks!
Your geometry is missing vertex normals.
You can specify the normals yourself, or -- if you find the result acceptable -- you can call:
geometry.computeVertexNormals();
Alternatively, you can avoid setting vertex normals if you set the material property to flat-shading (and your material supports it):
material.shading = THREE.FlatShading;
Also, you need to set a reasonable intensity for your light:
var light = new THREE.PointLight( 0xffffff, 1 );
three.js r.85

THREE.JS Raycasting to a child of the camera

I have a object (plane) that is a child of the camera so its 'fixed to the screen'.
plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10, 10, 10), material);
plane.position.set(0,0,-5);
camera.add(plane);
On this plane I have another object which I want to move, to I am sending raycasts to the plane.
if(INTERSECTED){
handleEvent();
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject( plane);
if(intersects.length>0){
//what is happening here?
//these points are definitely not on the plane!
var x = intersects[0].point.x;
var y = intersects[0].point.y;
var z = intersects[0].point.z;
INTERSECTED.position.set(x,y,z);
console.log(x,y,z);
}
}
The positions on which the rays hit the plane doesn't make any sense for me!
Please help me out, I'm stuck!
Thanks!
Here is the fiddle:
jsfiddle.net/74jLjz6q/2
PS: I found this post, with a similar problem, where the camera was a child of another object.. I couldn't find any help for my problem there..
THREE.js Raycasting from a child camera to the scene
Okey, I got it by trail and error:
It had to be the other way around (world to local).
I'm not sure if I really understood this..
So, the points are provided in world space. (..Because THREE.Raycaster always does?)
And it has to be in local space because the plane is a child of the camera.
Is that right?
(AND I had to substract the distance between the camera and the plane manually.)
plane.worldToLocal( intersects[0].point );
INTERSECTED.position.set(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z-5);
The updated and working fiddle (The cube finally stays on the plane! :) ):
http://jsfiddle.net/74jLjz6q/9/

EdgesHelper as child of a Cube get double rotation speed

When I add an EdgesHelper of a cube to the scene, then rotate the cube, the EdgesHelper follows the rotation.
But if I add EdgesHelper as child of cube, it rotates at double speed.
https://jsfiddle.net/aj3cv4tx/4/ +49
var cube = new THREE.Mesh( geometry, mesh );
var egh = new THREE.EdgesHelper( cube, 0x00ffff );
cube.add(egh); // causes different ratation speed
//scene.add(egh); // this one is ok
How can I fix its rotation speed?
What you are seeing is a consequence of how EdgesHelper (and some of the other helpers) have been implemented.
If you want to use EdgesHelper, you have to adhere to two rules:
EdgesHelper must be added to the scene, directly.
The scene can't have a transform applied (for example, be rotated).
three.js r.74

Set transparency of face by index in THREE.js

I've managed to set the colour of a mesh face using:
geometry.faces[i].color.setHex('0xff00ff');
Is there a function to set the transparency to true and opacity to say 0.5?
I'm sure there is one, just have no idea of the syntax.
Actually, you cannot achieve that by changing your geometry. Because transparency controlled by materials.
But there's way to do this.
First, each face has materialIndex (Face manual).
Next, Each mesh, drawn within three.js scene has material. And there's special material of type THREE.MeshFaceMaterial (MeshFaceMaterial manual), which takes array of materials as argument.
When faces are drawn, three.js renderer takes face's materialIndex and uses corresponding material from this material array or, if mesh contains single material type.
So you could do something like:
var opacMaterial = new THREE.MeshLambertMaterial({
transparent:true,
opacity:0.7
});
var solidMaterial = new THREE.MeshLambertMaterial({
transparent:false,
color:new THREE.Color(1,0,0)
});
var mesh = new THREE.Mesh(
geometry,
new THREE.MultiMaterial([solidMaterial, opacMaterial])
);
By default, if your geometry have materialIndex == 0 for each faces, you will see solidMaterial drawn.
If you want to make it transparent do something like this;
geometry.faces[i].materialIndex = 1;
Don't forget to update geometry in mesh: (How to update geometry in mesh question.)
Also, aware, if you have materialIndex in your faces greater than length of material array, you will get awkward error inside of deep of THREE.js

Resources