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);
Related
I m trying to add 2d hotspots to a 3d model. For this, i have added a WebGLRendere for 3d model and a CSS2DRenderer for te hotspot.
I m using raycaster to detect the hotspot but it is not detecting the hotspot.
This is my code -
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 7;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var platform;
var loader = new THREE.ColladaLoader();
loader.load('model/platform.dae', function(dae){
platform = dae.scene;
platform.position.set(0, -3.5, 0.5);
scene.add(platform);
scene.add(hotSpot);
});
var hotSpotDiv = document.createElement('div');
hotSpotDiv.className = 'hotSpot';
var hotSpot = new THREE.CSS2DObject(hotSpotDiv);
hotSpot.position.set(-1, 4.2, 0);
var renderer2D = new THREE.CSS2DRenderer();
renderer2D.setSize( window.innerWidth, window.innerHeight );
renderer2D.domElement.style.position = 'absolute';
renderer2D.domElement.style.top = 0;
renderer2D.domElement.style.backgroundColor = 0xff0000;
document.body.appendChild( renderer2D.domElement );
var light = new THREE.AmbientLight( 0x555555 ); // soft white light
scene.add( light );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set(-0.5, 0.5, -1);
scene.add( directionalLight );
var mouse = new THREE.Vector2();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
var raycaster = new THREE.Raycaster();
var INTERSECTED;
function renderLoop(){
requestAnimationFrame(renderLoop);
render();
}
renderLoop();
function render(){
camera.lookAt( scene.position );
camera.updateMatrixWorld();
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children, true );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
console.log(intersects.length + " -- " + intersects[0].object);
INTERSECTED = intersects[ 0 ].object;
}
} else {
INTERSECTED = null;
}
renderer.render(scene, camera);
renderer2D.render(scene, camera);
console.log(body);
}
var camControls = new THREE.OrbitControls(camera);
camControls.enableDamping = true;
camControls.dampingFactor = 1;
Please let me know if there is any other better way to add 2d clickable buttons over the 3d model.
Thanks for all the help in advance!
Just a code version of what Andy has already provided as an answer.
This is in context to Amod's code.
hotSpotDiv.addEventListener('click', function(){
// Do your stuff here
});
I am trying to use a THREE.raycaster to trigger the download of a .obj file when it is clicked on. For some reason I keep getting a THREE.Raycaster: Unsupported camera type error. I am using a a THREEPerspectiveCamera. I am using a grid of canvases and rendering a different object to each- could this be why I am getting the error? Help!
var projector = new THREE.Projector();
var directionVector = new THREE.Vector3();
var SCREEN_HEIGHT = window.innerHeight;
var SCREEN_WIDTH = window.innerWidth;
var mouse;
var objects = [];
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
init();
animate();
//camera
function View( canvas, fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight ) {
canvas.width = viewWidth * window.devicePixelRatio;
canvas.height = viewHeight * window.devicePixelRatio;
var context = canvas.getContext( '2d' );
var camera = new THREE.PerspectiveCamera( 20, viewWidth / viewHeight, 1, 10000 );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );
camera.position.z = 75;
this.render = function () {
camera.lookAt( scene.position );
renderer.render( scene, camera );
context.drawImage( renderer.domElement, 0, 0 );
};
}
also
function onDocumentMouseDown( event ) {
event.preventDefault();
var mouseX = (event.clientX / window.innerWidth)*2-1;
var mouseY = -(event.clientY /window.innerHeight)*2+1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
console.log( 'click');
}
}
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);}
}
}
I'm trying my hands on three.js
I am moving the camera using a tween, and it works quite good.
At the end of the animation, however, the camera jumps back to its initial position.
I found out that the mousemove event was causing that behavior.
How can i fix this problem and keep both the tween movement and the mouse move?
I have constructed my three.js based on this example;
Mousemove declared inside render function
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.04;
camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
Tween movement
function setupTween (position, target, duration) {
TWEEN.removeAll();
new TWEEN.Tween (position)
.to (target, duration)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate (
function() {
// copy incoming position into camera position
camera.position.copy (position);
})
.start();
};
tween function source
UPDATE
Complete working code:
<script>
var container,
i,
camera,
scene,
renderer,
particles,
geometry,
materials = [],
color,
sprite,
size,
mouseX = 0,
mouseY = 0,
isTweening,
windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2;
// +++++ three.js +++++
// +++++ +++++ +++++ +++++ +++++
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.5, 2000 );
camera.position.set (0,0,1900);
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.0005 );
geometry = new THREE.Geometry();
var textureLoader = new THREE.TextureLoader();
for ( i = 0; i < 1000; i ++ ) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * 2000 - 1000;
vertex.y = Math.random() * 2000 - 1000;
vertex.z = Math.random() * 2000 - 1000;
geometry.vertices.push( vertex );
}
sprite = textureLoader.load( "circle.png" );
color = [0.90, 0.05, 0.8];
size = 8.5;
materials = new THREE.PointsMaterial( { size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent : false } );
materials.color.setHSL( color[0], color[1], color[2] );
particles = new THREE.Points( geometry, materials );
scene.add( particles );
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function startTween() {
isTweening = false;
var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());
new TWEEN.Tween (camera.position.clone())
.to (target, 1000)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate( function() {
camera.position.copy(this);
})
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
}
function getRandomNumber() {
// get a number between -1000 and -500 and 500 and 1000
return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
}
function render() {
if(!isTweening && (mouseX || mouseY)) {
// more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
var upVector = camera.up.clone().transformDirection(camera.matrix);
var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);
camera.translateOnAxis(rightVector, mouseX);
camera.translateOnAxis(upVector, -mouseY);
mouseX = mouseY = 0;
}
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
init();
animate();
setTimeout(function(){
startTween();
},2500);
</script>
I think, you should only update the position by the mousemove event, when it's not tweening. So you need to check if its currently tweening or not.
var isTweening = false;
new TWEEN.Tween (camera.position)
.to (target, duration)
.easing (TWEEN.Easing.Quadratic.InOut)
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
// in your render loop
function render() {
if (!isTweening) {
camera.position.x += ( mouseX - camera.position.x ) * 0.04;
camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
}
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
You don't need to set an onUpdate function and copy the new position to camera.position. You can just pass over camera.position to the tween and it will work.
EDIT:
I didn't see the link to example. Now, I know which kind of navigation is used (which is actually used in a lot of three.js examples). It's not the mousemove event that is causing your problem, it's this kind of calculating the new camera position (camera.position.x += ( mouseX - camera.position.x ) * 0.04;). So, I changed the code of the example a bit, especially the navigation. Here are the important parts:
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
function onDocumentMouseMove( event ) {
mouseX = (event.movementX * 0.5) || event.mozMovementX || event.webkitMovementX || 0;
mouseY = (event.movementY * 0.5) || event.mozMovementY || event.webkitMovementY || 0;
}
function render() {
if(!isTweening && (mouseX || mouseY)) {
// more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
var upVector = camera.up.clone().transformDirection(camera.matrix);
var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);
camera.translateOnAxis(rightVector, mouseX);
camera.translateOnAxis(upVector, -mouseY);
mouseX = mouseY = 0;
}
camera.lookAt( scene.position );
TWEEN.update();
}
function startTween() {
isTweening = false;
var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());
new TWEEN.Tween (camera.position.clone())
.to (target, 1000)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate( function() {
camera.position.copy(this);
})
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
}
function getRandomNumber() {
// get a number between -1000 and -500 and 500 and 1000
return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
}
And you are right about TWEEN.onUpdate: you need to copy the new values to camera.position. My earlier approach do also work, but then all of the functionality of THREE.Vector3 gets lost. I didn't realize that until now.
I am fairly new to three.js and have a problem I can't readily find an answer for.
Here is a codepen that should sum up the situation: http://codepen.io/anon/pen/PPYPzO
var container, stats;
var camera, controls, scene, renderer, raycaster, mouse;
init();
animate();
add_world();
var indie_render = true;
for(var j = 0; j < 20; j++){
add_objects(20);
indie_render = !indie_render;
console.log("adding more objects...");
if(!indie_render){render();}
}
function add_world(){
var geometry = new THREE.BoxGeometry( 1000, 1000, 1000);
var mesh = new THREE.MeshBasicMaterial( {color: 0xf5f5dc, wireframe: false, opacity: 0.2, transparent:true } );
var world = new THREE.Mesh( geometry, mesh );
scene.add( world );
render();
}
function add_objects(num, indiv){
var geometry = new THREE.SphereGeometry( 5, 32,32 );
var material = new THREE.MeshBasicMaterial( { shading: THREE.FlatShading } );
material.color.setRGB( Math.random(), Math.random(), Math.random() );
for ( var i = 0; i < num; i ++ ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x = ( Math.random() - 0.5 ) * 1000;
mesh.position.y = ( Math.random() - 0.5 ) * 1000;
mesh.position.z = ( Math.random() - 0.5 ) * 1000;
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
scene.add( mesh );
if(indie_render){
console.log("individual render");
render();
}
}
}
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set(500, 500, -1000);
camera.up.set( 0, 1, 0 );
camera.lookAt(500,500,500);
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
//world
scene = new THREE.Scene();
// lights
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0x222222 );
scene.add( light );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setClearColor( 0x000000, 1 );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
mouse = new THREE.Vector2();
raycaster = new THREE.Raycaster();
container.addEventListener( 'mousemove', onMouseMove, false );
container.addEventListener( 'mousedown', onMouseDown, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
renderer.render( scene, camera );
}
function onMouseMove( e ) {
mouse.x = ( e.clientX / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( e.clientY / renderer.domElement.height ) * 2 + 1;
}
function onMouseDown( e ) {
mouse.x = ( e.clientX / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( e.clientY / renderer.domElement.height ) * 2 + 1;
if(e.button == 2){ //right button
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children, true );
if ( intersects.length > 0 ) {
var geometry = new THREE.SphereGeometry( 5, 32,32 );
var material = new THREE.MeshBasicMaterial( { color:0xff0000, shading: THREE.FlatShading } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set(intersects[0].point.x, intersects[0].point.y, intersects[0].point.z);
scene.add(mesh);
render();
}
}
}
In this demo, I init() and animate() a blank scene, and then add a translucent cube, following what seems to be convention. Then I add groups of spheres to the scene in a nested for loop, randomly placing the spheres inside the cube and making a render() call after every scene.add() call.
Currently, the scene adds all the spheres and only then is visible to the user, even though I can add individual objects after the for-loop objects are added (by right-clicking on the cube). I need for the user to be able to watch as spheres are added, rather than waiting for the whole thing to be done.
I realize this may not be the most efficient way to render the scene, but it would be quite helpful if, for example, the info on the objects to be animated is arriving asynchronously from a server. Does anyone have a suggestion?
Thanks
1) First: move call render() to animate:
function animate() {
requestAnimationFrame( animate );
render();
controls.update();
}
2) Call add_objects asynchronously: setTimeout( add_objects, 0, 20 );
http://codepen.io/anon/pen/bVbEEP