Visualizing Raycaster - three.js

I am trying to detect an intersection by using a raycast. My current problem is that I am not sure about my raycast aiming into the desired direction. So my general question is: Is there a way to make a raycast visible? And if so: How is it done? This would help me a lot.
Michael

Here is another method to show your raycsters:
scene.add(new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 300, 0xff0000) );

Why dont you draw a line from your origin to the direction of the ray.
To be more specific (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

Related

Get center position of hole in ExtrudeGeometry

I trying to get position of hole in extruded geometry. I created plane and made hole in her geometry. I want get x,y,z coordinates in center of hole. Is there some methods to get it?
Here demo: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
I created shape of plane
let shape = new THREE.Shape();
let width = 30;
let height = 30;
shape.moveTo(-width, height);
shape.lineTo(-width, -height);
shape.lineTo(width, -height);
shape.lineTo(width, height);
shape.lineTo(-width, height);
I created hole path and add it to shape
let hole = new THREE.Path();
hole.absarc(20, 10, 10, 0, Math.PI * 2, false) //first two argumets is x,y coord of hole
shape.holes.push(hole)
I created plane add add extruded geometry
let geometry = new THREE.PlaneGeometry( 30, 30);
let material = new THREE.MeshBasicMaterial( {color: new THREE.Color('#cea6a6'), side: THREE.DoubleSide} );
let mesh = new THREE.Mesh( geometry, material );
let newGeometry = new THREE.ExtrudeGeometry(shape, settings);
mesh.geometry.dispose()
mesh.geometry = newGeometry;
After 4 days I understand how can do it. I simple created line from mesh center to hole config position. Applied quaternion to line and got x,y,z cords of hole.
Maybe there are more optimized solutions, but it only that I could create. I will be glad if someone share more optimized solution :D
Here codepen: https://codepen.io/DYDOI-NSK/pen/XWqJzXG?editors=0011
Here code:
/*
* findCoords - function to find hole coords in 3d space
* data - parameter that require x,y of hole
*/
let findCoords = function (data) {
let vertexes = [];
//Set coords where you was created hole
let hole = new THREE.Vector3(
data.x,
data.y,
0
);
vertexes.push( new THREE.Vector3() );
vertexes.push(hole)
//Create line
const material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
const geometry = new THREE.BufferGeometry().setFromPoints( vertexes );
const line = new THREE.Line( geometry, material );
scene.add(line)
//Set line to center of mesh
line.position.copy(mesh.position)
//Rotate line like rotated mesh
line.applyQuaternion(mesh.quaternion)
//Extract hole coords from second vertex of line
let holeCoord = new THREE.Vector3()
const positionAttribute = line.geometry.getAttribute( 'position' );
holeCoord.fromBufferAttribute( positionAttribute, 1);
return holeCoord;
}

Ray does not accurately determine the intersection

I want to find point of intersection curve and line. Created raycast, but it doesn't work well. The point of the ray is far from the actual intersection.
Webgl 1, threejs 0.109
var sartPoint = new THREE.Vector3( -30, -50, 0 );
var endPoint = new THREE.Vector3( 50, 80, 0 );
var geometry = new THREE.Geometry();
geometry.vertices.push(sartPoint);
geometry.vertices.push(endPoint);
var materialTmp = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 5 } );
var itemTmp = new THREE.Line( geometry, materialTmp );
_this.add( itemTmp, 'lines' );
scene.updateMatrixWorld()
var curve = new THREE.EllipseCurve(
0, 0, // ax, aY
10, 10, // xRadius, yRadius
0, 2 * Math.PI, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
var points = curve.getPoints( 10 );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
var material = new THREE.LineBasicMaterial( { color : 0xff00ff } );
var ellipse = new THREE.Line( geometry, material );
scene.add( ellipse );
var raycaster = new THREE.Raycaster(sartPoint, endPoint.clone().normalize());
var intersects = raycaster.intersectObject( ellipse );
console.log(intersects);
if(intersects.length > 0){
// FIRST dot of intersect
var dotGeometry2 = new THREE.Geometry();
dotGeometry2.vertices.push(intersects[0].point);
var dotMaterial2 = new THREE.PointsMaterial( { size: 5, color: 0x00ff00 } );
var dot2 = new THREE.Points( dotGeometry2, dotMaterial2 );
_this.add( dot2, 'points' );
}
The second argument to the Raycaster constructor is a direction vector. Instead of:
endPoint.clone().normalize()
I think you want:
endPoint.clone().sub(startPoint).normalize()
It is work if
curve.getPoints( 10 );
When
curve.getPoints( 100 );
That doesn't work.

ThreeJS raycasting is different in R81 than R71

I have a plane with a mesh on it. My code draws a ball when the user double clicks on the mesh. This works just fine in R71 but as soon as I switched to R81 raycaster doesn't return an intersect. Here's the code:
In init():
// Plane
plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry( 1000, 1000, 3, 3 ),
new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: .5, transparent: true } )
);
plane.visible = false;
scene.add( plane );
planes.push(plane);
In doubleClickEvent():
event.preventDefault();
var mouse = new THREE.Vector2((event.clientX / window.innerWidth ) * 2 - 1, -(((event.clientY / window.innerHeight ) * 2 - 1)));
var directionVector = new THREE.Vector3();
directionVector.set(mouse.x, mouse.y, 0.1);
directionVector.unproject(camera);
directionVector.sub(camera.position);
directionVector.normalize();
raycaster.set(camera.position, directionVector);
intersects = raycaster.intersectObjects(planes);
if (intersects.length) {
var sphereParent = new THREE.Object3D();
var sphereGeometry = new THREE.SphereGeometry(.1, 16, 8);
var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphereParent.add(sphere);
sphereParent.position.set(intersects[0].point.x, intersects[0].point.y, 0.0);
scene.add(sphereParent);
objects.push(sphereParent);
}
If I change
intersects = raycaster.intersectObjects(planes);
to
intersects = raycaster.intersectObjects(scene.children);
the ball gets drawn but it gets drawn on the wrong position.
Any ideas?
I found the answer. The reason why the raycast isn't working is because the plane's visibility is false. The solution is to change the visibility of the material visibility rather the plane.

three.js How to render a simple white dot/point/pixel

I'm using THREE.WebGLRenderer and I would like to draw a few same-sized white dots at specific positions in 3D space.
Should I use sprites, calculate the 2D screen coordinates and use SpriteMaterial.useScreenCoordinate?
Should I simply recalculate the size of the sprites using the distance of them to the camera?
Can I use SpriteMaterial.scaleByViewport or SpriteMaterial.sizeAttenuation? Is there any documentation for this?
Is there something like GL_POINTS? It would be nice to just define 1 vertex and get a colored pixel at that position. Should I experiment with PointCloud?
Thanks for any hints!
Edit: All points should have the same size on the screen.
Using .sizeAttenuation and a single-vertex PointCloud works, but it feels a bit… overengineered:
var dotGeometry = new THREE.Geometry();
dotGeometry.vertices.push(new THREE.Vector3( 0, 0, 0));
var dotMaterial = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );
For r125
The excerpt is taken from threejs official example. After some modification here how made it to work.
var dotGeometry = new BufferGeometry();
dotGeometry.setAttribute( 'position', new Float32BufferAttribute( [0,0,0], 3 ) );
var dotMaterial = new PointsMaterial( { size: 0.1, color: 0x00ff00 } );
var dot = new Points( dotGeometry, dotMaterial );
scene.add( dot );
Yet another update: The interface for attribute has changed somewhat:
For r139
const dotGeometry = new THREE.BufferGeometry();
dotGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array([0,0,0]), 3));
const dotMaterial = new THREE.PointsMaterial({ size: 0.1, color: 0xff0000 });
const dot = new THREE.Points(dotGeometry, dotMaterial);
scene.add(dot);

Check if point is inside a custom mesh geometry

What would be the easiest way to check if a point is inside a custom (irregular) mesh geometry?
If your mesh is close-up. You can use the THREE.js built-in ray-caster. Sample code is as
const point = new THREE.Vector3(2,2,2) // Your point
const geometry = new THREE.BoxBufferGeometry( 5, 5, 5 )
const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } )
const mesh = new THREE.Mesh( geometry, material )
const raycaster = new THREE.Raycaster()
raycaster.set(point, new THREE.Vector3(1,1,1))
const intersects = raycaster.intersectObject(mesh)
if( intersects.length %2 === 1) { // Points is in objet
console.log(`Point is in object`)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script>
Just raycast once from the point to any direction, then check the intersects num, if is odd, the point is in the geometry, here is the demo
This is a computational geometry problem. You can look at Finding if point is inside geometry. Since your geometry is irregular the problem is much harder.
But if precision is not too important you can check if the point is inside the bounding box of the geometry.
Its better to check it using the dot product of ray direction and face normal
tested on three.js (r103)
const point = new THREE.Vector3(2, 2, 2) // Your point
const direction = new THREE.Vector3(1, 1, 1);
const geometry = new THREE.BoxGeometry(5, 5, 5)
const material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material)
const raycaster = new THREE.Raycaster()
raycaster.set(point, direction)
const intersects = raycaster.intersectObject(mesh);
if (intersects.length && direction.dot(intersects[0].face.normal) > 0) {
console.log(`Point is in object`);
} else {
console.log(`Point is out of object`);
}
In rare cases you can get even number of interections with point located inside the mesh
(try point = new THREE.Vector3(0, 0, 0), that should give 4 intersections)

Resources