Hide objects on Click with raycaster - javascript

I wanna hide scene objects with clicking on them,
I read many "raycaster" tutorials but I don't know where is my fault
with these codes when I open my HTML file all the objects are hidden.
I have deleted most of irreverent codes to raycaster.
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var FLOOR = -250;
var container, stats;
var group1 , group2 , group3 ;
var camera, scene, controls;
var renderer;
var mesh;
var textureCube;
var cameraCube, sceneCube;
var loader;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
// CAMERA and controls
....
// SCENE
scene = new THREE.Scene();
// SKYBOX
.....
//models
group1=...
group2=...
group3=...
cubes = new THREE.Object3D() ;
cubes.add( group1 ) ;
cubes.add( group2 ) ;
cubes.add( group3 ) ;
mouseVector = new THREE.Vector3();
projector = new THREE.Projector();
// LIGHTS
lights...
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
renderer.domElement.style.position = "relative";
renderer.autoClear = false;
container.appendChild( renderer.domElement );
//
renderer.gammaInput = true;
renderer.gammaOutput = true;
// STATS
stats = new Stats();
container.appendChild( stats.domElement );
// EVENTS
window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener( 'mousemove', onDocumentMouseMove, false );
}
//
function onWindowResize( event ) {
....
}
function onDocumentMouseMove(event) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
mouseVector.x = 2 * (e.clientX / containerWidth) - 1;
mouseVector.y = 1 - 2 * ( e.clientY / containerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
controls.update();
cameraCube.rotation.copy( camera.rotation );
renderer.clear();
renderer.render( sceneCube, cameraCube );
//raycast
var raycaster = projector.pickingRay( mouseVector.clone(), camera );
window.addEventListener( 'mousedown', onMouseDown, false );
var onMouseDown = function ( event ) {
var intersects = raycaster.intersectObjects( cubes.children );
var intersection = intersects[0] , obj = intersection.object ;
obj.visible = false ;
};
renderer.render( scene, camera );
}
</script>

You are doing the raycast on every frame while rendering. When you want to raycast on mouse clicks, you need an Event Listener:
window.addEventListener( 'mousedown', onMouseDown, false );
var onMouseDown = function ( event ) {
var intersects = raycaster.intersectObjects( cubes.children );
var intersection = intersects[0], obj = intersection.object;
obj.visible = false ;
};

Related

Issue with mouse events on three.js iframe

Click events work as they should, however when mouse drag events are fired (on this example happens when dragging video timestamp), mouse coordinates dont' seem to translate to 2d space of iframe correctly. It seems that x coordinate is doubled from what it should be.
On other embedded websites, due to displacement of y coordinate, during selecting symbols to copy, website scrolls to the bottom of the page.
How can I fix this issue?
Minimal example https://codepen.io/asjas/pen/pWawPm
var camera, scene, renderer;
var controls;
var Element = function ( id, x, y, z, ry ) {
var div = document.createElement( 'div' );
div.style.width = '480px';
div.style.height = '360px';
div.style.backgroundColor = '#000';
var iframe = document.createElement( 'iframe' );
iframe.style.width = '480px';
iframe.style.height = '360px';
iframe.style.border = '0px';
iframe.src = [ 'https://www.youtube.com/embed/', id, '?rel=0' ].join( '' );
div.appendChild( iframe );
var object = new THREE.CSS3DObject( div );
object.position.set( x, y, z );
object.rotation.y = ry;
return object;
};
init();
animate();
function init() {
var container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.set( 500, 350, 750 );
scene = new THREE.Scene();
renderer = new THREE.CSS3DRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = 0;
container.appendChild( renderer.domElement );
var group = new THREE.Group();
group.add( new Element( 'xBOqwRRj82A', 0, 0, 240, 0 ) );
group.add( new Element( 'x4q86IjJFag', 240, 0, 0, Math.PI / 2 ) );
group.add( new Element( 'JhngfOK_2-0', 0, 0, - 240, Math.PI ) );
group.add( new Element( 'Grg3461lAPg', - 240, 0, 0, - Math.PI / 2 ) );
scene.add( group );
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 4;
window.addEventListener( 'resize', onWindowResize, false );
// Block iframe events when dragging camera
var blocker = document.getElementById( 'blocker' );
blocker.style.display = 'none';
document.addEventListener( 'mousedown', function () { blocker.style.display = ''; } );
document.addEventListener( 'mouseup', function () { blocker.style.display = 'none'; } );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}

In Three js how do I play the animation of object clicked

I am new to three js and js in general as I mainly use c++, but I am trying to learn. One of the things I am trying to do is play an animation on the balloon i click on. Currently no matter which balloon is clicked only the last plays the animation. I have tried various things but nothing seems to work. Any help would be appreciated.
import './style.css';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// Setup
var balloon1, balloon2, balloon3, mouse, raycaster, selected = null;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#bg'),
});
var raycaster = new THREE.Raycaster(), INTERSECTED;
var mouse = new THREE.Vector2();
var action = null;
var action1 = null;
window.addEventListener( 'mousemove', onMouseMove, false );
window.addEventListener( 'click', onClick );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
camera.position.set(-10, 6, 10 );
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize( e )
{
containerWidth = window.clientWidth;
containerHeight = window.clientHeight;
renderer.setSize( containerWidth, containerHeight );
camera.aspect = containerWidth / containerHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
// Torus
const loader = new GLTFLoader();
// Lights
const pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0x404040 );
scene.add(pointLight, ambientLight);
// Helpers
// const lightHelper = new THREE.PointLightHelper(pointLight)
// const gridHelper = new THREE.GridHelper(200, 50);
// scene.add(lightHelper, gridHelper)
// const controls = new OrbitControls(camera, renderer.domElement);
// Background
let mixer;
loader.load( 'stall.glb', function ( gltf ) {
const model = gltf.scene;
model.position.set( -10, -195, -20 );
model.scale.set( 2.51, 3.01, 2.01 );
scene.add( model );
model.rotation.y += -5.3;
}, undefined, function ( e ) {
console.error( e );
} );
loader.load( 'balloon.glb', function ( gltf ) {
const balloon1 = gltf.scene;
balloon1.position.set( -10, -187, -20 );
balloon1.scale.set( 2.01, 2.01, 2.51 );
scene.add( balloon1 );
balloon1.rotation.y += -5.3;
mixer = new THREE.AnimationMixer(balloon1);
action = mixer.clipAction(gltf.animations[0]);
action.setLoop( THREE.LoopOnce );
action1 = mixer.clipAction(gltf.animations[1]);
action1.setLoop( THREE.LoopOnce );
}, undefined, function ( e ) {
console.error( e );
} );
loader.load( 'balloon.glb', function ( gltf ) {
const balloon2 = gltf.scene;
balloon2.position.set( -14, -187, -16 );
balloon2.scale.set( 2.01, 2.01, 2.51 );
scene.add( balloon2 );
balloon2.rotation.y += -5.3;
mixer = new THREE.AnimationMixer(balloon2);
action = mixer.clipAction(gltf.animations[0]);
action.setLoop( THREE.LoopOnce );
action1 = mixer.clipAction(gltf.animations[1]);
action1.setLoop( THREE.LoopOnce );
}, undefined, function ( e ) {
console.error( e );
} );
loader.load( 'balloon.glb', function ( gltf ) {
const balloon3 = gltf.scene;
balloon3.position.set( -14, -180, -19 );
balloon3.scale.set( 2.01, 2.01, 2.51 );
scene.add( balloon3 );
balloon3.rotation.y += -5.3;
mixer = new THREE.AnimationMixer(balloon3);
action = mixer.clipAction(gltf.animations[0]);
action.setLoop( THREE.LoopOnce );
action1 = mixer.clipAction(gltf.animations[1]);
action1.setLoop( THREE.LoopOnce );
}, undefined, function ( e ) {
console.error( e );
} );
const spaceTexture = new THREE.TextureLoader().load('black.jpg');
scene.background = spaceTexture;
function onMouseMove( event ) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
function onClick(event){
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects( scene.children );
if (intersects.length > 0 && intersects[ 0 ].object.userData.name == 'Sphere' ) {
console.log( intersects[ 0 ].object.userData.name );
console.log(scene.children);
for ( let i = 0; i < intersects.length; i ++ ) {
action.stop(intersects[i].object);
action1.stop(intersects[i].object);
action.play(intersects[i].object);
action1.play(intersects[i].object);
}
}
}
// Scroll Animation
function moveCamera() {
const t = document.body.getBoundingClientRect().top;
camera.position.z = t * 0.000;
camera.position.x = t * 0.000;
camera.position.y = t * 0.0432;
}
document.body.onscroll = moveCamera;
moveCamera();
// Animation Loop
const clock = new THREE.Clock();
function animate() {
reset();
hover();
if(mixer)
mixer.update(clock.getDelta());
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();

Three.js OBJ loader not working on codepen?

I'm a trying to load an OBJ file on Three.js, its working on my local, and when I deploy the files on my server it's working fine :
http://hafsadanguir.com/THREEJS/
but it's not working on codepen : http://codepen.io/hafsadanguir/pen/RaJaPZ
var container;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth/ 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 20, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 900;
camera.position.x = -1000;
// scene
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0x404040 ); //This creates an Ambientlight with a color.
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
// texture
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var texture = new THREE.Texture();
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {
};
var loader = new THREE.ImageLoader( manager );
loader.load('http://hafsadanguir.com/THREEJS/textures/red.jpg', function ( image ) {
texture.image = image;
texture.needsUpdate = true;
} );
// model
var loader = new THREE.OBJLoader( manager );
loader.load('http://hafsadanguir.com/THREEJS/obj/Heart.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = -150;
scene.add( object );
}, onProgress, onError );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//
window.addEventListener( 'resize', onWindowResize, 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 ) / 2;
mouseY = ( event.clientY - windowHalfY ) / 2;
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//camera.position.x += ( mouseX - camera.position.x ) * .005;
//camera.position.y += ( - mouseY - camera.position.y ) * .005;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
Someone can help please, it's my first time using three.js :)
I have the loader working using the latest version of ThreeJS. You are using version 73, you should be using v75:
http://codepen.io/aaronfranco/pen/LNrZQg
https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.min.js
Your server does not allow you to access those object files. I'm getting CORS error from your server. If load them from the same domain, then it should work.
But without proper CORS, allow origin headers, you won't be able to use them in CodePen.
> XMLHttpRequest cannot load
> http://hafsadanguir.com/THREEJS/obj/Heart.obj. No
> 'Access-Control-Allow-Origin' header is present on the requested
> resource. Origin 'http://s.codepen.io' is therefore not allowed
> access.

Adding clickable image to a mesh

This may be a really stupid question, but I am new to three.js and while I've gotten the obj file to load on the web and be controllable via mouse, I'm not quite sure how to handle the next step.
What I'd really like to do is overlay a clickable .jpg or .png file over a section of the existing mesh linking out to some web pages I already have completed. How would I go about doing this? I'd appreciate it if someone could point me to an example or let me know if it's not doable so I can look for possible alternatives.
The code I currently have is below -- it's mostly cobbled together from online example so forgive me if it seems redundant or inelegant.
var container, stats;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 10;
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( render );
// scene
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0xFFFFFF );
scene.add( ambient );
/*var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 1, 1, 0 ).normalize();
scene.add( directionalLight );*/
var hemisphereLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, .70);
scene.add( hemisphereLight );
// model
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {
};
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var loader = new THREE.OBJMTLLoader();
loader.load( 'obj/test/test_model.obj', 'obj/test/test_model.mtl', function ( object ) {
object.scale = new THREE.Vector3( 25, 25, 25 );
//object.position.y = - 80;
scene.add( object );
}, onProgress, onError );
//
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//
window.addEventListener( 'resize', onWindowResize, 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 );
controls.handleResize();
}
function onDocumentMouseMove( event ) {
// mouseX = ( event.clientX - windowHalfX ) / 2;
// mouseY = ( event.clientY - windowHalfY ) / 2;
}
//
function animate() {
requestAnimationFrame( animate );
controls.update();
render();
}
function render() {
//camera.position.x += ( mouseX - camera.position.x ) * .05;
//camera.position.y += ( - mouseY - camera.position.y ) * .05;
//camera.lookAt( scene.position );
renderer.render( scene, camera );
}
In your onDocumentMouseMove - or in a click event - you must compute a ray-picking intersection with http://threejs.org/docs/#Reference/Core/Raycaster and handle the reaction from there.
There are multiples examples of this, in the Three.js examples (like http://threejs.org/examples/#webgl_geometry_terrain_raycast) and on StackOverflow.
A very naive solution could be:
// note that you may have to use other properties if the renderer is not fullscreen"
// like here http://stackoverflow.com/questions/13542175/three-js-ray-intersect-fails-by-adding-div
var mouseX = ( event.clientX / window.innerWidth ) * 2 - 1;
var mouseY = -( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3( mouseX, mouseY, camera.near );
// Convert the [-1, 1] screen coordinate into a world coordinate on the near plane
vector.unproject( camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// See if the ray from the camera into the world hits one of our meshes
var intersects = raycaster.intersectObjects( scene, true ); // true for recursive
// Toggle rotation bool for meshes that we clicked
if ( intersects.length > 0 ) {
var clickedObject = intersects[ 0 ].object;
// here, handle the clickedObject properties to react accordingly
// show an overlay, jump to a page, etc..
}

Animating obj files with OBJLoader in Three.js

I currently have to do an animation with obj files. I want to rotate horizontally the loaded ribs. Is it just POSSIBLE to animate obj files ? If so, how do you do that ? I search all over the web, the only animation examples I found were made using JSONLoader, wich I don't use. Here is my code :
window.onload = function() {
var container, stats;
var camera, scene, renderer, object;
var windowHalfX;
var windowHalfY;
init();
animate();
function init() {
width = 500;
height = 500;
windowHalfX=width/2;
windowHalfY=height/2;
camera = new THREE.PerspectiveCamera( 45, width / height, 1, 2000 );
camera.position.z = 300;
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 1, 1 );
scene.add( directionalLight );
var loader = new THREE.OBJMTLLoader();
for ( var i = 1; i < 13; i ++ ) {
var chem = './three/obj/Cotes/left/CG';
if (i<10) {
var nomcote = chem+'0'+i+'.obj';
var matcote = chem+'0'+i+'.mtl';
}
else{
var nomcote = chem+i+'.obj';
var matcote = chem+i+'.mtl';
}
loader.load( nomcote, matcote, function ( object ) {
object.position.y = - 70;
object.name = "cotesG"+i;
scene.add( object );
} );
}
for ( var i = 1; i < 13; i ++ ) {
var chem = './three/obj/Cotes/right/CD';
if (i<10) {
var nomcote = chem+'0'+i+'.obj';
var matcote = chem+'0'+i+'.mtl';
}
else{
var nomcote = chem+i+'.obj';
var matcote = chem+i+'.mtl';
}
loader.load( nomcote, matcote, function ( object ) {
object.position.y = - 70;
object.name = "cotesD"+i;
scene.add( object );
} );
}
renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
controls = new THREE.OrbitControls(camera,renderer.domElement);
controls.addEventListener( 'change', render );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = width / 2;
windowHalfY = height / 2;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
render();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
// camera.lookAt( scene.position );
renderer.render( scene, camera );
}
}

Categories

Resources