Three js raycaster WITHOUT camera - three.js

I seem to find only examples to use the raycaster with the camera, but none that just have a raycaster from Point A to Point B.
I have a working raycaster, it retrieves my Helpers, Lines etc. but it seems it does not recognize my sphere.
My first thought was my points are off, so i decided to create a line from my pointA to my pointB with a direction like so:
var pointA = new Vector3( 50, 0, 0 );
var direction = new Vector3( 0, 1, 0 );
direction.normalize();
var distance = 100;
var pointB = new Vector3();
pointB.addVectors ( pointA, direction.multiplyScalar( distance ) );
var geometry = new Geometry();
geometry.vertices.push( pointA );
geometry.vertices.push( pointB );
var material = new LineBasicMaterial( { color : 0xff0000 } );
var line = new Line( geometry, material );
This will show a line from my point (50 0 0) to (50 100 0) right trough my sphere which is at point (50, 50, 0) so my pointA and direction values are correct.
Next i add a raycaster:
To avoid conflicts with any side effects i recreated my points here:
var raycaster = new Raycaster(new Vector3( 50, 0, 0 ), new Vector3( 0, 1, 0 ).normalize());
var intersects = raycaster.intersectObject(target);
console.log(intersects);
Seems pretty straight forward to me, i also tried to use raycaster.intersectObjects(scene.children) but it gives Lines, helpers etc. but not my sphere.
What am i doing wrong? I am surely missing something here.
IMG of the line and the sphere:

What you see is explained in the following github issue:
https://github.com/mrdoob/three.js/issues/11449
The problem is that the ray emitted from THREE.Raycaster does not directly hit a face but its vertex which results in no intersection.
There are several workarounds to solve this issue e.g. slightly shift the geometry or the ray. For your case:
var raycaster = new THREE.Raycaster( new THREE.Vector3( 50, 0, 0 ), new THREE.Vector3( 0, 1, 0.01 ).normalize() );
However, a better solution is to fix the engine and make the test more robust.
Demo: https://jsfiddle.net/kzwmoug2/3/
three.js R106

Related

Why is texture not rendering on vertices in Three.js (missing UVs)

I have created a scene with THREE.js. Most of the surfaces are BoxGeometries with zero width and a texture applied. Everything works well, including transparent windows on the house. When I went to add roof, I needed to make angled flat panels and triangular spaces. I decided to use a technique borrowed from another StackOverflow page (How to create a custom mesh on THREE.JS?).
The mesh is rendering, but not the texture. I've tried with different texture images and it does change the COLOR of the rendered panel, but still no visible texture. I'm missing something. If I can get this to work, I'll start using more vertex-based meshes to fill in my building. Why isn't the texture rendering?
//texture
var texture = new THREE.ImageUtils.loadTexture("shingles.jpg");
texture["shingles"] = new THREE.MeshBasicMaterial({ map:texture, side:THREE.DoubleSide});
//roof
var v1 = new THREE.Vector3(farRight,level+height,back);
var v2 = new THREE.Vector3(farRight,level+height,front);
var v3 = new THREE.Vector3((farRight+farLeft)/2,level+(3*height/2),front-(3*width/2));
var v4 = new THREE.Vector3((farRight+farLeft)/2,level+(3*height/2),back+(3*width/2));
var geom = new THREE.Geometry();
geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);
geom.vertices.push(v4);
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.faces.push( new THREE.Face3( 3, 0, 2 ) );
var object = new THREE.Mesh( geom, textures["shingles"] );
scene.add(object);
----------------Updated with full answer-------------------------------
As noted in the accepted answer, I missed adding the UV vectors. After some reading I was able to figure out how they work and get the textures to map appropriately. I'm including the full solution here for future reference. First two snippets of code.
var v3 = new THREE.Vector3((farRight+farLeft)/2,level+(3*height/2),front-(3*width/2));
var v4 = new THREE.Vector3((farRight+farLeft)/2,level+(3*height/2),back+(3*width/2));
var v5 = new THREE.Vector3(farLeft,level+height,back);
var v6 = new THREE.Vector3(farLeft,level+height,front);
geom = new THREE.Geometry();
geom.vertices.push(v3);
geom.vertices.push(v4);
geom.vertices.push(v5);
geom.vertices.push(v6);
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.faces.push( new THREE.Face3( 3, 0, 2 ) );
geom.faceVertexUvs[0].push([new THREE.Vector2(.3, 1),
new THREE.Vector2(.7, 1),
new THREE.Vector2(1, 0)]);
geom.faceVertexUvs[0].push([new THREE.Vector2(0, 0),
new THREE.Vector2(.3, 1),
new THREE.Vector2(1, 0)]);
object = new THREE.Mesh( geom, textures["shingles"] );
scene.add(object);
var v1 = new THREE.Vector3(farRight,level+height,back);
var v4 = new THREE.Vector3((farRight+farLeft)/2,level+(3*height/2),back+(3*width/2));
var v5 = new THREE.Vector3(farLeft,level+height,back);
geom = new THREE.Geometry();
geom.vertices.push(v1);
geom.vertices.push(v4);
geom.vertices.push(v5);
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.faceVertexUvs[0].push([new THREE.Vector2(0, 0),
new THREE.Vector2(.5, 1),
new THREE.Vector2(1, 0)]);
object = new THREE.Mesh( geom, textures["shingles"] );
scene.add(object);
Now a picture and an explanation. The two geometries in the code above are highlighted in the picture. Because I got fancy, vertices 3 and 4 are slightly inward making a trapezoid shape. Likewise the UV vertices that correspond to those points are .3 and .7 inward from the corners to make a trapezoid. The triangular geometry has two points at the base and one at the top-middle.
Basically, create the vertices, add the vertices, define the faces, and (this is the part I missed) add UV vertices corresponding to the locations in the texture.
You will need to add texture coordinates as well.. (aka uv coordinates). There is a field called faceVertexUVs that has to be filled out. You will need to set 0,0 for the top left corner of each face, 1,0 for top right, 0,1 for bottom left and 1,1 for bottom right corner.

Draw line in direction of raycaster in three.js

In three.js, I'm using PointerLock controls the make a basic first person shooter.
I use
function onDocumentMouseDown( event ) {
var raycaster = new THREE.Raycaster();
mouse3D.normalize();
controls.getDirection( mouse3D );
raycaster.set( controls.getObject().position, mouse3D );
var intersects = raycaster.intersectObjects( objects );
...
}
to detect a collision with an object, which means you "shot" the object.
Now, I want to visualize the path the bullet took. I was thinking about drawing a line from where the user is looking to, in direction of the raycaster, but I can't figure out how to do this... Anyone who can help me? I'm new to three.js, never thought drawing a line would be this hard.
Update:
I'm trying to draw a line using:
var geometry = new THREE.Geometry();
geometry.vertices.push(...);
geometry.vertices.push(...);
var line = new THREE.Line(geometry, material);
scene.add(line);
but I can't figure out what to put in place of the "..." . How can I detect which point the line should go to? And how to determine which point it starts from? The player is able to move and even jump so the starting point is always different too.
You can use the following (using r83):
// Draw a line from pointA in the given direction at distance 100
var pointA = new THREE.Vector3( 0, 0, 0 );
var direction = new THREE.Vector3( 10, 0, 0 );
direction.normalize();
var distance = 100; // at what distance to determine pointB
var pointB = new THREE.Vector3();
pointB.addVectors ( pointA, direction.multiplyScalar( distance ) );
var geometry = new THREE.Geometry();
geometry.vertices.push( pointA );
geometry.vertices.push( pointB );
var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
var line = new THREE.Line( geometry, material );
scene.add( line );
Codepen at: https://codepen.io/anon/pen/evNqGy
You can use something like this:
function animate_Line(frame, totalFrames) {
//Calculate how much of the line should be drawn every iteration
var delta = lineDistance/(totalFrames);
var deltaSpeed = delta * frame;
for(var i=0; i<f_Ray_List[0].length; i++) {
for(var j=0; j<f_Ray_List[1].length; j++) {
//Change Offsets
line.geometry.vertices[1].y = line.geometry.vertices[0].y - deltaSpeed;
//Update Rays = true (Make FRT rays draw-able)
line.geometry.verticesNeedUpdate = true;
}
}
}
where frame is the current frame (a counter in your animate function), totalFrames would be the amount of frames that the line would take to be animated. The lineDistance can be calculated by using this:
lineDistance = line.geometry.vertices[0].y - line.vertices[1].y; //Add this line where you create the line object.
and remember to call line.geometry.verticesNeedUpdate = true; in every line individually, so that the line would able to be animated.
Notice that this is only based on Line.y axis. This would not be great at first. I'm currently working on converting this to Polar coordinates instead but I have no idea what is going on hahah.

three.js: rotational matrix to place THREE.group along new axis

(Please also refer to my illustration of the problem: http://i.stack.imgur.com/SfwwP.png)
problem description and ideas
I am creating several objects in the standard XYZ coordinate system.
Those are added to a THREE.group.
Please think of the group as a wall with several frames and image hung on it.
I want to create my frame objects with eg. dimension of (40, 20, 0.5). So I get a rather flat landscape formatted frame/artwork. I create and place several of those. Then I add them to the group, which I wanted to freely rotate in the world along two vectors start and end.
The problem I am struggling with is how to rotate and position the group from a given vector start to a give vector end.
So far I tried to solve it with a THREE.Matrix4().lookAt :
var group = new THREE.Group();
startVec = new THREE.Vector3( 100, 0, -100 );
endVec = new THREE.Vector3( -200, 0, 200 );
matrix = new THREE.Matrix4().lookAt(startVec, endVec, new THREE.Vector3( 0, 1, 0 ));
group.matrixAutoUpdate = false;
var object1 = new THREE.Mesh(new THREE.BoxGeometry(0.5, 20, 40), mat);
// etc. -> notice the swapping of X and Z coordinates I have to do.
group.add(object1);
group.applyMatrix(matrix);
You can see the example on jsfiddle:
http://jsfiddle.net/y6b9Lumw/1/
If you open jsfiddle, you can see that the objects are not placed along the line from start to end, although I their are placed along the groups internal X-Axis like: addBox(new THREE.Vector3( i * 30, 0 , 0 ));
Full code:
<html>
<head>
<title>testing a rotation matrix</title>
<style>body { margin: 0; } canvas { width: 100%; height: 100% } </style>
</head> <body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script>
<script>
var scene, camera, renderer, light, matrix;
var startVec, endVec;
var boxes;
function addBox(v) {
var boxmesh;
var boxgeom = new THREE.BoxGeometry( 15, 5, 1 );
var boxmaterial = new THREE.MeshLambertMaterial( {color: 0xdd2222} );
boxmesh = new THREE.Mesh( boxgeom, boxmaterial );
//boxmesh.matrix.makeRotationY(Math.PI / 2);
boxmesh.matrix.setPosition(v);
boxmesh.matrixAutoUpdate = false;
boxes.add(boxmesh);
}
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0x222222 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( -20, 30, 300 );
var light = new THREE.PointLight (0xCCCCCC, 0.5 );
scene.add(light);
startVec = new THREE.Vector3( 100, 0, -100 );
endVec = new THREE.Vector3( -200, 0, 200 );
matrix = new THREE.Matrix4().lookAt(startVec, endVec, new THREE.Vector3( 0, 1, 0 ));
boxes = new THREE.Group();
for (var i = -100; i < 100; i++) {
addBox(new THREE.Vector3( i * 30, 0 , 0 ));
}
boxes.matrixAutoUpdate = false;
boxes.applyMatrix(matrix);
scene.add(boxes);
var linegeometry = new THREE.Geometry();
linegeometry.vertices.push( startVec, endVec);
var line = new THREE.Line(linegeometry, new THREE.LineBasicMaterial({color: 0x33eeef}));
scene.add(line);
render();
}
function render(){
requestAnimationFrame(render);
renderer.render(scene, camera);
}
init();
</script>
</body> </html>
This works only nicely to some extend. As the look vector is usually oriented along the Z-Axis (i think it is (0,0,1)). So unfortunately the objects inside the group get rotated like that aswell.
This is actually what you would expect from a lookAt() rotational transformation. It's not what I would like to have though, as this places all the children in the group, on their Z-Axis, instead of their X-Axis.
In order to have things look properly I had to initialize my groups children with X and Z swapped.
Instead of:
var object1 = new THREE.BoxGeometry( 40, 20, 0.5 );
I have to do:
var object1 = new THREE.BoxGeometry( 0.5, 20, 40 );
same if I want to translate objects in the group on the X-Axis, I have to use the Z-Axis, as that is the look-vector along which the whole wall is oriented by the matrix transformation.
my question is:
How does my matrix have to be constructed/look like to accomplish what I want: Normally create objects, and then have their X-Axis placed along vector start and vector end, like placing artworks on a wall, which can be moved around?
I thought about creating a matrix, whose X-Axis is end.sub(start), so the vector from start end end, might this be what I need to do? If so, how would I construct it?
problem illustration with an image
I tried to illustrate my sitation in two images. One being the wall, one being the wall inside the world, with the same objects attached to the wall (see top of the post).
In the first figure you see the local coordinate system of the group, with two added children, one translated along X.
In the second figure, you can see the same localsystem inside the world how I would like it to be. The green axes are the world axes. The start and end vectors are shown aswell. You can see, both boxes, are properly placed along that line.
I would like to answer my own question by disregarding the idea of manipulating the matrix myself. Thx to #WestLangley I adapted my idea to the following by setting the groups quaternion via .setFromUnitVectors.
So the rotation is derived from the rotation from the x-axis to the direction vector of start and end, as explained in three.js' documentation:
"Sets this quaternion to the rotation required to rotate direction vector vFrom to direction vector vTo."
(http://threejs.org/docs/#Reference/Math/Quaternion.setFromUnitVectors)
Below is the relevant part of my solution:
// define the starting and ending vector of the wall
start = new THREE.Vector3( -130, -40, 300 );
end = new THREE.Vector3( 60, 20, -100 );
// dir is the direction from start to end, normalized
var dir = new THREE.Vector3().copy(end).sub(start).normalize();
// position wall in the middle of start and end
var middle = new THREE.Vector3().copy(start).lerp(end, 0.5);
wall.position.copy(middle);
// rotate wall by applying rotation from X-Axis to dir
wall.quaternion.setFromUnitVectors( new THREE.Vector3(1, 0, 0), dir );
The result can be seen here: http://jsfiddle.net/L9dmqqvy/1/

draw arrow helper along THREE.Line or two vectors

Is it possible to draw arrow helper, with two vectors (x1,y1,z1)(x2,y2,z2), please give your suggestion and guidance on it..
Thanks in advance...
you can get the direction from the 2 vectors like this and create the arrow helper
var from = new THREE.Vector3( 2, 2, 2 );
var to = new THREE.Vector3( 0, 0, 0 );
var direction = to.clone().sub(from);
var length = direction.length();
var arrowHelper = new THREE.ArrowHelper(direction.normalize(), from, length, 0xff0000 );
scene.add( arrowHelper );
Js fiddle working
http://jsfiddle.net/pardo/bgyem42v/3/

Ray intersection when using morphtargets not working

Slightly complex, so bear with me:
Ray intersect works perfectly when an object has no morphTargets.
When an object has morphTargets only the original position can be intersected, that is to say, if I morph a model from 0,0,0 to 50,50,50 the ray will not intersect with the object at 50,50,50, instead, when I mouse over 0,0,0 I get an intersection (even though the object is no longer there!?).
Is there some sort of flag I need to turn on to make three.js aware that the verts have moved?
Edit, code added.
This makes my mesh and adds it to the objects array (which ray intersect uses):
function createDeer( deerGeometry, materials ) {
mesh = new THREE.MorphAnimMesh( deerGeometry, new THREE.MeshLambertMaterial( { color: 0xE8E8E8, ambient: 0xE8E8E8, morphTargets: true, vertexColors: THREE.FaceColors } ) );
mesh.scale.set( 3, 3, 3 );
mesh.position.set( 0, -3, 0 );
mesh.rotation.set( 0, 0, 0 );
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.geometry.dynamic = true;
scene.add( mesh );
objects.push( mesh );
}
Ray intersection happens on mouseDown (there's a mouseOver as well, same thing), like I said, the code works fine, it's just intersecting with the original unmorphed mesh:
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( objects );
if ( intersects.length > 0 ) {
SELECTED = intersects[ 0 ].object;
for(var i=0; i<objects.length; i++)
{
if(SELECTED.position.x == objects[0].position.x) {
thisObject = i;
}
}
}
var intersects = ray.intersectObject( plane );
container.style.cursor = 'pointer';
}
}
I've decided the problem must be related to the fact that the position of the deer (as in the mesh transform) never changes, however the vertices do move away, and as the ray intersect is comparing object positions perhaps the problem is here?
I've made a pull request that has been merged and fixes this.
Note that for it to work, the boundingSphere of the object needs to contain the full extent of the morphing
The MorphTarget animation takes place entirely on GPU (in the shaders code) while the ray intersection is always computed on CPU. So in fact, there's no easy way to achieve what you're describing here.

Resources