I have created a sphere in three.js which has around 140 circles on its surface.
Have a look here if you like!
By clicking or touching a circle the user can change its colour.
Its a bit laggy on mobile devices though - is there any way of optimizing the following code?
function onMouseDown( e ) {
mouseVector.x = 2 * (e.clientX / (window.innerWidth*0.8)) - 1;
mouseVector.y = 1 - 2 * ( e.clientY / window.innerHeight );
raycaster.setFromCamera( mouseVector, camera );
var intersects = raycaster.intersectObjects( circles );
if ( intersects.length > 0 ) {
var intersect = intersects[ 0 ];
pickedColor=parseInt(document.getElementById("color").value.replace('#', '0x'));
intersect.object.material.color = new THREE.Color( pickedColor );
render();
}
}
Related
I am loading SVG images on to the mesh basic material of BoxBufferGeometry(cube) using SVGLoader. I want to trigger mouse events when user hovers/clicks on specific element of SVG which is loaded on the specific side of the cube.
I tried adding events into the .svg file before loading it but once it get loaded on the material it doesn\'t show any changes caused by the events.
Is there any other possible way to select the elements of loaded svg image and apply events on it?
For better understanding please refer http://plnkr.co/edit/YYN8aechHGTKXvPv6tOo?p=preview apart from this also tried to access the particular side using following code:
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
var index = Math.floor( intersects[0].faceIndex / 2 );
if ( INTERSECTED != intersects[ 0 ].object && (index == 4 || index == 5)) {
if ( INTERSECTED ) {
INTERSECTED.material[intersects[0].faceIndex].color.setHex( INTERSECTED.currentHex );
}
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material[4].color.getHex();
INTERSECTED.material[index].color.setHex( 0xCACACA );
f = index;
}
I have used threex.domevent.js to capture the mouseover event and created a plunker. I am finding the cube face which has the svg image.
Links:
detect mouse click / hover event on sides of cube in three js and
https://github.com/jeromeetienne/threex.domevents.
Attach the dom event using *threex.domevent.js**
domEvents = new THREEx.DomEvents(camera, renderer.domElement)
Listen to mouse over event and find the face you require.
domEvents.addEventListener(mesh, 'mouseover', function(event) {
var vector = new THREE.Vector3(
(event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, );
vector.unproject(camera);
raycaster.set(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObject(mesh);
if (intersects.length > 0) {
var index = Math.floor(intersects[0].faceIndex / 2);
if (index === 4) {
//index 4 is cude face having the svg image,
//you can load a new svg or do required things here
console.log('##############');
mesh.material[4].map = new THREE.TextureLoader().load('sample2.svg');
}
}
}, false)
Plunker: http://plnkr.co/edit/QXwqN3X70ex3EZmlKhRf?p=preview
Hope it helps.
I have a 3D scatter plot with spheres to represent the points and I'm trying to display information from the points when clicked. Based on answers to a couple different questions here on SO, I think I'm on the right track. Here is my onCanvasMouseDown:
event.preventDefault();
mouse.x = ( (event.clientX - renderer.domElement.offsetLeft) / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( (event.clientY - renderer.domElement.offsetTop) / renderer.domElement.height ) * 2 + 1;
mouse.z = 0.5;
projector.unprojectVector( mouse, camera);
raycaster.setFromCamera( mouse, camera);
var intersects = raycaster.intersectObjects( scene.children );
if( intersects.length > 0 ) {
intersects.map(function(d) {
if(d.object.name === "sphere") {
//etc...
}
})
}
But intersects keeps coming back empty. I have a feeling the problem has something to do with the way I'm setting up the mouse coordinates, but I'm not sure how to resolve the issue.
EDIT: I seem to be able to find a sphere if I rotate the plot so that I am looking at it from above (but I need to be able to detect it regardless of the rotation). Does this indicate anything specific?
If your objects (points) belong to, for example, THREE.Group(), which is a child of the scene, then
var intersects = raycaster.intersectObjects( scene.children );
will give you negative result of intersection.
To reach group's children it's better to use
var intersects = raycaster.intersectObjects( scene.children, true );
Or you can try a different option: put the objects you want to check for intersection into an array and then pass the array to intersectObjects method.
var objects = [];
for(i=0; i<10; i++){
...
var meshobj = new THREE.Mesh(...);
scene.add(meshobj); // or group.add(meshobj);
objects.push(meshobj);
}
...
var intersects = raycaster.intersectObjects( objects ); // here you don't need recursive parameter, as you have the array with objects you indeed want to check for intersection
if you have offset, use the the boundingRect.
var rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
see the demo of my answer.
I'm working on someone else's project to finish it, and it's pretty cool. It is supposed to be a diagram that will dynamically generate nodes(spheres) and be able to click on them and then a new diagram with related nodes will appear.
I am working on the clic kable part now, it seems harder than i thought. I have read into raycasting and vectors. I have even found examples that get pretty close to what i want: http://mrdoob.github.io/three.js/examples/canvas_interactive_cubes.html
BUT, for some reason when i hover next to the nodes (the hover spots seem very arbitrary, as highlighted in the image) they change color. For some most of them i cant even find the "hotspots".
I think i lack some understanding of the unprojecting/converting/transformation from 3d to 2d part. And maybe that's why my mouse doesn't intersect properly with the nodes on screen i guess.
My onmousemove event:
function onDocumentMouseMove2(event){
event.preventDefault();
var canvasSvg= d3.select("#canvas-svg")[0][0];
mouse.x = ( event.clientX / canvasSvg.clientWidth) * 2 - 1;
mouse.y = - ( event.clientY / canvasSvg.clientHeight ) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 1).unproject(camera);
//raycaster.setFromCamera( mouse, camera );
raycaster.set(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects( scene.children );
//console logs
console.log("current 'canvas' div");
console.log(canvasSvg)
console.log("mouse");
console.log(mouse);
console.log("vector");
console.log(vector);
if ( intersects.length > 0 ) {
intersects[0].object.material.color.setHex( Math.random() * 0xffffff ); //gives another color to the node i hover over
intersects[0].object.callback(); //this calls the funcion "callback" i attached to the nodes.
}
for ( var i in intersects ) {
intersects[ i ].object.material.color.setHex( Math.random() * 0xffffff | 0x80000000 );
}
}
My camera
// Set camera attributes and create camera
var VIEW_ANGLE = 7, //field of view
ASPECT = WIDTH / HEIGHT,
//ASPECT = $container[0].clientWidth / $container[0].clientHeight,
NEAR = 0.1,
FAR = 10000;
var camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
http://i.imgur.com/wWlEYQT.png?1
Good day! I managed to fix it with this example:
http://jsfiddle.net/fek9ddg5/62/
mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
The ray was indeed confused on where it had to be projected. I had to take note of the offSet from the top of thescreen to my canvas.
I've been working with three.js examples of boids/flocks for some time, but both the canvas one and the webgl/shaders one have a flaw: the mouseOver event (which "disturbs" birds and triggers a repulsion) only works when camera.position = {x: 0, y: 0,: whatever}.
I've tried to improve that in the canvas example (easier to my eyes) by editing this part:
function onDocumentMouseMove( event ) {
var vector = new THREE.Vector3( event.clientX - SCREEN_WIDTH_HALF, - event.clientY + SCREEN_HEIGHT_HALF, 0 );
for ( var i = 0, il = boids.length; i < il; i++ ) {
boid = boids[ i ];
vector.z = boid.position.z;
boid.repulse( vector );
}
}
And trying something like:
function onDocumentMouseMove( event ) {
var vector = new THREE.Vector3();
vector.x = event.clientX;
vector.y = - event.clientY;
vector.unproject(camera);
for ( var i = 0, il = boids.length; i < il; i++ ) {
boid = boids[ i ];
vector.z = boid.position.z;
boid.repulse( vector );
}
}
But this can't work, the unprojected vector could only be used with a raycaster to find objects intersecting its path. In our case, the repulsion effect must work at 150 distance, according to boid.repulse:
this.repulse = function ( target ) {
var distance = this.position.distanceTo( target );
if ( distance < 150 ) {
var steer = new THREE.Vector3();
steer.subVectors( this.position, target );
steer.multiplyScalar( 0.5 / distance );
_acceleration.add( steer );
}
}
So I'm stuck. Should I find a way to widen the raycaster so it's like a 150-wide cylinder for mouse picking? Or is there a way to unproject the vector then re-project it on the plane nearest to the bird, so to calculate the distance? (but what about performance with 200+ birds? )
If the solution can only come from shaders, feel free to tell me to create another topic.
Included: jsfiddle of the canvas example with a slightly moved camera.
Honestly, i tried to find solution for question below, please help me. And sorry for my English :)
I have created a map, added a camera + added camera control of all dimensions.
And when I get the position of the cursor relative to the mesh, the position is always different from different angles.
View all code in jsfiddle.net: http://jsfiddle.net/BT3g3/
I use Three.js r49.
This code is just responsible for calculating the position.
function onDocumentMouseMove(event) {
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 1);
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersect = ray.intersectObject( island );
if ( intersect.length > 0) { // !!
document.getElementById('z').value = intersect[0].point.z;
document.getElementById('x').value = intersect[0].point.x;
}
}
I was browsing internet and came across an article where the cursor position is caught on the map, but i fail move this method to my project :(
Please, help!
Have you tried with following ?
mouseX = ( ( event.clientX - canvas.offsetLeft ) / canvas.clientWidth ) * 2 - 1;
mouseY = - ( ( event.clientY - canvas.offsetTop ) / canvas.clientHeight ) * 2 + 1;