Unable to intersect Points - three.js

I unable to intersect Three.Points but i am able to intersect THREE.Mesh, below is my code: Can someone please help me to understand what mistake i am making. When i intersect the Points all i get is 0.
function init()
{
geometry = new THREE.Geometry();
vertex = new THREE.Vector3();
vertex.x=( [i + 3 ] * 140 ) - 1330;
vertex.y = - ( [i + 3 ] * 180 ) + 990;
vertex.z = 100;
geometry.vertices.push(vertex);
var particleTexture = THREE.ImageUtils.loadTexture(imgstr);
var materials = new THREE.PointsMaterial({
map:particleTexture,
size: 150
});
particles = new THREE.Points(geometry, materials);
scene.add(particles);
targetList.push(particles);
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function onDocumentMouseDown(event){
var projector = new THREE.Projector();
var vector = new THREE.Vector3(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(targetList);
console.log(intersects.length);
}

function onDocumentMouseDown( event ) {
event.preventDefault();
if(event.which == 1) {
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera( mouse, camera );
raycaster.params.Points.threshold = 100000; // bigger number = bigger sensitivity
var intersects = raycaster.intersectObjects( myobjectsarray,false); // myobject array is array of THREE.Points object
if ( intersects.length > 0 ) {console.log('tadaah',intersects);}
}
}

Related

How to add measurement details while line drawing in three.js

I'm trying to add the length of the start point and endpoint of the line geometry. I have a line but I have no idea how to show some unit measurement data in the form of the text while drawing the wall in mouse move itself.
Here's the fiddle
var renderer, scene, camera;
var line;
var count = 0;
var mouse = new THREE.Vector3();
init();
animate();
function init() {
// info
var info = document.createElement('div');
info.style.position = 'absolute';
info.style.top = '30px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.style.color = '#fff';
info.style.fontWeight = 'bold';
info.style.backgroundColor = 'transparent';
info.style.zIndex = '1';
info.style.fontFamily = 'Monospace';
info.innerHTML = "three.js - animated line using BufferGeometry";
document.body.appendChild(info);
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 0, 1000);
// geometry
var geometry = new THREE.BufferGeometry();
var MAX_POINTS = 500;
positions = new Float32Array(MAX_POINTS * 3);
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
// material
var material = new THREE.LineBasicMaterial({
color: 0xff0000,
linewidth: 2
});
// line
line = new THREE.Line(geometry, material);
scene.add(line);
document.addEventListener("mousemove", onMouseMove, false);
document.addEventListener('mousedown', onMouseDown, false);
}
// update line
function updateLine() {
positions[count * 3 - 3] = mouse.x;
positions[count * 3 - 2] = mouse.y;
positions[count * 3 - 1] = mouse.z;
line.geometry.attributes.position.needsUpdate = true;
}
// mouse move handler
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
mouse.z = 0;
mouse.unproject(camera);
if( count !== 0 ){
updateLine();
}
}
// add point
function addPoint(event){
console.log("point nr " + count + ": " + mouse.x + " " + mouse.y + " " + mouse.z);
positions[count * 3 + 0] = mouse.x;
positions[count * 3 + 1] = mouse.y;
positions[count * 3 + 2] = mouse.z;
count++;
line.geometry.setDrawRange(0, count);
updateLine();
}
// mouse down handler
function onMouseDown(evt) {
// on first click add an extra point
if( count === 0 ){
addPoint();
}
addPoint();
}
// render
function render() {
renderer.render(scene, camera);
}
// animate
function animate() {
requestAnimationFrame(animate);
render();
}
I'm trying to achieve the measurement like the above.
The simplest way is to use CSS2D labels. You can assign a regular HTML <div> to act as a label. It displays flat on top of your <canvas> renderer without rotations so it's always facing the camera. See here for a demo on how to set up your CSS2DRenderer:
https://threejs.org/examples/#css2d_label
All you'd have to do is take the average of 2 Vector3s, and assign that as your label's position.
// Get distance and midpoint
var distance = vectorA.distanceTo(vectorB);
var midpoint = new Vector3();
midpoint.copy(vectorA);
midpoint.add(vectorB).multiplyScalar(0.5);
// Create label, set distance and position
const labelDiv = document.createElement( 'div' );
labelDiv.className = 'label';
labelDiv.textContent = "Distance: " + distance;
labelDiv.style.marginTop = '-1em';
const distLabel = new CSS2DObject( labelDiv );
distLabel.position.copy( midpoint );
cssScene.add( distLabel );

Three.js: not accurate to detect faceIndex when clicking the 2*2*2 geometry cube

I have created a 2*2*2 geometry cube via Three.js. Now I want to detect the click event when clicking the faces (24 faces in total).
Please check my current implementation at https://jsfiddle.net/agongdai/pdwg3myr/17/. When clicking on the faces, I want to console.log the current face index. But the index is not always accurate. For example, clicking on the top-left gray cell should show 0, but actually clicking the bottom part of it shows 2.
Please help me to check the mouse click event handler:
var raycaster = new THREE.Raycaster();
function onDocumentMouseDown( event ) {
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
vector.unproject( camera );
raycaster.setFromCamera( vector, camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObject( cube );
if ( intersects.length > 0 ) {
var index = Math.floor( intersects[0].faceIndex / 2 );
console.log(index);
}
}
Could anybody please help?
Em, after googling a lot, I found this page and applied the approach. It's working properly https://jsfiddle.net/agongdai/pdwg3myr/19/:
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onDocumentMouseDown(event) {
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(cube);
if (intersects.length > 0) {
var index = Math.floor(intersects[0].faceIndex / 2);
console.log(index);
}
}
Update
To adjust to the left/top shift and scrolling, update it to https://jsfiddle.net/agongdai/pdwg3myr/24/:
function onDocumentMouseDown(event) {
const holder = renderer.domElement;
const rect = holder.getBoundingClientRect();
mouse.x = ((event.pageX - rect.left - window.scrollX) / holder.clientWidth) * 2 - 1;
mouse.y = -((event.pageY - rect.top - window.scrollY) / holder.clientHeight) * 2 + 1;
...
}

Uncaught TypeError: Cannot read property 'length' of null - Three.js

I've trying to draw the square wall by getting mouse clicks coordinates and extrude it.
I've picking up the mouse coordinates by clicking at the scene.
var onDocumentMouseDown = function ( event )
{
//update the mouse variable
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
vector.unproject( camera );
var dir = vector.sub( camera.position ).normalize();
var distance = - camera.position.z / dir.z;
var pos = camera.position.clone().add( dir.multiplyScalar( distance));
console.log('mouse_x ' + pos.x + ' mouse_y ' + pos.y);
if (clickCount <= 3){
coord[clickCount] = {'x' : pos.x, 'y' : pos.y};
clickCount ++;
} else {
//make new wall and stop function
newshape = new THREE.Shape();
shape.moveTo(coord['0'].x ,coord['0'].y);
shape.lineTo(coord['0'].x, coord['1'].y);
shape.lineTo(coord['2'].x, +coord['2'].y);
shape.lineTo(coord['3'].x, coord['3'].y);
shape.lineTo(coord['0'].x, coord['0'].y);
var newextrudeSettings = {
//*******/
};
}
And when I've recived four coordinates, three.js throw the error:
Uncaught TypeError: Cannot read property 'length' of null
at Object.triangulateShape (three.js:26140)
at ExtrudeGeometry.addShape (three.js:26330)
at ExtrudeGeometry.addShapeList (three.js:26235)
at new ExtrudeGeometry (three.js:26211)
at HTMLDocument.onDocumentMouseDown (script.js:116)
To find points of intersection I prefer to use THREE.Raycaster() (though I've never used THREE.Projector() for this purpose).
This is the result of my code:
I hope I got your conception. Thus, all the stuff you need is here:
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects;
var controlPoints = [];
var clickCount = 0;
function onMouseDown(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(objects); // objects is an array which contains just the mesh of the plane
if (intersects.length > 0) {
if (clickCount <= 3) { // I took your idea of 4 clicks
controlPoints[clickCount] = intersects[0].point.clone(); // add a control point to the array
// visualization of a control point
var cp = new THREE.Mesh(new THREE.SphereGeometry(0.125, 16, 12), new THREE.MeshBasicMaterial({color: "red"}));
cp.position.copy(intersects[0].point);
scene.add(cp);
clickCount++;
} else { // on the fifth click we'll create our wall
shape = new THREE.Shape();
shape.moveTo(controlPoints[0].x, -controlPoints[0].z);
shape.lineTo(controlPoints[1].x, -controlPoints[1].z);
shape.lineTo(controlPoints[2].x, -controlPoints[2].z);
shape.lineTo(controlPoints[3].x, -controlPoints[3].z);
shape.lineTo(controlPoints[0].x, -controlPoints[0].z);
var extrudeSettings = {
steps: 1,
amount: 2,
bevelEnabled: false
};
var extrudeGeom = new THREE.ExtrudeGeometry(shape, extrudeSettings);
extrudeGeom.rotateX(-Math.PI / 2);
var wall = new THREE.Mesh(extrudeGeom, new THREE.MeshStandardMaterial({
color: "gray"
}));
scene.add(wall);
controlPoints = []; // we clear the array of control points
clickCount = 0; // and reset the counter of clicks
};
};
};
jsfiddle example. 4 clicks for setting control points, the fifth click creates a wall, and so on.

raycaster.intersectObjects returns 0 always

Below is the code that i am currently experimenting with, raycaster.intersectObjects returns 0 always what am i missing here? I have also tried raycaster.intersectObjects( objects );
geometry.vertices.push(vertex);
objects.push(geometry);
var particleTexture = THREE.ImageUtils.loadTexture('images/test.jpg');
var materials = new THREE.PointsMaterial({
map:particleTexture,
size: 150
});
document.addEventListener('click', onDocumentMouseClick, false);
function onDocumentMouseClick(event) {
event.preventDefault();
var vector = new THREE.Vector3();
var raycaster = new THREE.Raycaster();
vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); // z = 0.5 important!
vector.unproject( camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( scene.children, true );
}
particles = new THREE.Points(geometry, materials);
scene.add(particles);
You can intersect from Array, scene.childern is Object.
Try to make another array reference to inersected object.
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function onDocumentMouseUp( event ) {
event.preventDefault();
if(event.which == 1) { /// LMB
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera( mouse, camera );
raycaster.params.Points.threshold = 100000;
var intersects = raycaster.intersectObjects( intersects_obj, false );
console.log(intersects_m);
}
}
var mouse = new THREE.Vector2();
var intersects_obj = [];
canvas.addEventListener( 'mousemove', onDocumentMouseMove, false );
canvas.addEventListener( 'mouseup', onDocumentMouseUp, false );
//var paticles = .... your code;
intersects_obj.push(paticles);

Threejs raycaster only works super close

I was following mrdoobs examples of how to use raycasting to handle clickable objects. I have also looked at all of the many many similar questions and have tried countless things.
The raycasting works... If I am at a distance of less than 1.
The Raycaster is set to near 0 and far infinity though (defaults).
I haven't seen any code examples where distance was set.
I am hoping for another pair of eyes.
// snippet
glow.clickables = [];
var cubeGeo = new THREE.CubeGeometry(2, 2, 2);
cubeGeo.computeFaceNormals();
var cube = new THREE.Mesh(cubeGeo, redmat);
cube.position.y = 10;
cube.position.x = 0;
cube.position.z = -12;
cube.overdraw = true;
glow.Vis.scene.add(cube);
glow.clickables.push(cube);
onclick_();
var onclick_ = function() {
$('#world').on('mousedown', function(e){
var mouseX = (event.offsetX / $('#world').width()) * 2 - 1;
var mouseY = - ( event.offsetY / $('#world').height()) * 2 + 1;
var vector = new THREE.Vector3(mouseX, mouseY, 0.1); //what should z be set to?
//console.info(vector); // A vector between -1,1 for both x and y. Z is whatever is set on the line above
projector.unprojectVector(vector, glow.Vis.camera);
var conts = glow.Vis.controls.getObject().position; // control 3dObject which the camera is added to.
var clickRay = new THREE.Raycaster(conts, vector.sub(conts).normalize());
var intersects = clickRay.intersectObjects(glow.clickables);
console.info(intersects.length);
if(intersects.length > 0) {
alert("Click detected!");
}
});
}
Setting the mouse position this way is more accurate.
var rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
For mouse detecting (far or near! no matter!), do this:
put this in your global:
var pointerDetectRay, projector, mouse2D;
put this in your init() function:
pointerDetectRay = new THREE.Raycaster();
pointerDetectRay.ray.direction.set(0, -1, 0);
projector = new THREE.Projector();
mouse2D = new THREE.Vector3(0, 0, 0);
put this in your render() loop function:
pointerDetectRay = projector.pickingRay(mouse2D.clone(), camera);
and it's your mouse event:
function onDocumentMouseMove(event) {
event.preventDefault();
mouse2D.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse2D.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
Now, every where that you want to detect the objects under your mouse pointer, use this:
var intersects = pointerDetectRay.intersectObjects(scene.children);
if (intersects.length > 0) {
var intersect = intersects[0];
// intersect is the object under your mouse!
// do what ever you want!
}
I use the following which, for me, works for larger distances:
var projector = new THREE.Projector();
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector(vector,camera);
var raycaster = new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize() );
var intersects = raycaster.intersectObjects( [sphere,cylinder,cube] );
if ( intersects.length > 0 ) {
intersects[ 0 ].object.material.transparent=true;
intersects[ 0 ].object.material.opacity=0.1;
console.log(intersects[0]);
}
}
This just sets the first selected object to semitransparent. Complete example at: https://github.com/josdirksen/learning-threejs/blob/master/chapter-09/02-selecting-objects.html

Resources