javascript THREE OrbitControls: doubleclick Object - javascript

I am using THREE.js and OrbitControls.js. I want to doubleclick an Object and then do stuff.
This is the code I am using. cube1 is the Object I want to doubleclick.
var projector = new THREE.Projector();
document.addEventListener('dblclick', ondblclick, false);
function ondblclick(event)
{
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5);
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position,
vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( cube1 );
if ( intersects.length > 0 )
{
alert("hit");
}
}
Unfortunately the code does not work.
I appreciate any help.
This is the camera I am using:
var camera = new THREE.PerspectiveCamera( 45, WIDTH/HEIGHT, 0.1, 10000 );
camera.position.z = 1500;
camera.position.y = -1800;
scene.add(camera);
And this is OrbitControls:
var controls = new THREE.OrbitControls(camera, renderer.domElement);

I just corrected the ondblclick function
function ondblclick(event) {
x = (event.clientX / window.innerWidth) * 2 - 1;
y = -(event.clientY / window.innerHeight) * 2 + 1;
dir = new THREE.Vector3(x, y, -1)
dir.unproject(camera)
ray = new THREE.Raycaster(camera.position, dir.sub(camera.position).normalize())
var intersects = ray.intersectObject(sphere);
if ( intersects.length > 0 )
{
alert("hit");
}
}
Here is the working sample: http://jsfiddle.net/ddbTy/241/

Related

Runaway raycasting when it should only respond on click

I've created a script to add a new plane to a scene every time I click on an existing plane - the detection uses a raycaster. However, instead of waiting for a click, the script uncontrollably adds more and more planes to the scene with no clicks at all. What have I missed?
Thanks!
var container, renderer, scene, camera;
var container = document.body;
var frustumSize = 1000;
var width, height;
var numRows = 4;
var numCols = 7;
var spacingSize = 300;
var raycaster;
var mouse;
var savedColor;
function init() {
width = window.innerWidth;
height = window.innerHeight;
container = document.createElement( 'div' );
document.body.appendChild( container );
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor(0x000000);
scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
camera = new THREE.OrthographicCamera( frustumSize * aspect / - 2, frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, 0, 2000 );
// camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 0, 2000 );
camera.updateProjectionMatrix();
// set up grid of colored planes
var startXPos = -((spacingSize*(numCols-1))/2);
var startYPos = -((spacingSize*(numRows-1))/2);
for ( var i = 0; i < numCols; i++ ) {
var x = startXPos + (i*spacingSize);
for ( var j = 0; j < numRows; j++ ) {
var y = startYPos + (j*spacingSize);
var z = -10 + (j * -1.0001);
var geometry = new THREE.PlaneGeometry( 50, 50 );
var material = new THREE.MeshBasicMaterial( {color: new THREE.Color( Math.random(), Math.random(), Math.random() ), side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.position.set( x, y, z );
scene.add(plane);
}
}
savedColor = null;
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
document.addEventListener( 'click', onDocumentClick, false );
var axesHelper = new THREE.AxesHelper( 100 );
scene.add( axesHelper );
container.appendChild( renderer.domElement );
scene.updateMatrixWorld();
render();
}
function render() {
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
// calculate objects intersecting the picking ray
if ( intersects.length > 0 ) {
// console.log("yo!");
for ( var i = 0; i < intersects.length; i++ ) {
var geometry = new THREE.PlaneGeometry( 60, 60 );
var material = new THREE.MeshBasicMaterial( {color: new THREE.Color( 0xffff00 ), side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.position.set( getRandomBetween(-300,300), getRandomBetween(-300,300), -20 );
scene.add(plane);
// console.log("hey!");
scene.updateMatrixWorld();
}
}
renderer.render( scene, camera );
requestAnimationFrame( render );
}
function getRandomBetween( min, max ) {
return Math.random() * (max - min) + min;
}
function onDocumentClick( event ) {
event.preventDefault();
// calculate mouse position in normalized device coordinates
// (-1 to +1) for both components
// console.log("Oi!");
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.js"></script>
It's because the initial position of mouse is (0, 0), which intersects with the AxesHelper.
change the inital position of mouse or remove AxesHelper or change the intersecting target to a specific group should resolve this.

Three js clickable Img in Scene

i have a 360 degree scene where i place some imgs (sprits) on. I'd like to make this imgs clickable, so that I receive a function if i click on it.
My Code:
var map = new THREE.TextureLoader().load( "arrow-poi.png" );
var material = new THREE.SpriteMaterial( { map: map, color: 0xffffff, fog: true } );
var sprite = new THREE.Sprite( material );
var geometry = new THREE.PlaneGeometry(6,6);
sprite.material.side = THREE.DoubleSide,
sprite.position.x= 40,
sprite.position.y= -6,
sprite.position.z= 10,
sprite.scale.set(6,6,1),
sprite.name="arrow",
sprite.directto=r,
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector3( 0, 1, 0 );
projector = new THREE.Projector();
clickableObjects = [];
clickableObjects.push(sprite, sprite1);
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( clickableObjects );
if ( intersects.length > 0) {
intersects[0].object.onClick();
}
}
sprite1.onClick = function(){console.log('Clicked');}
I've been looking for something like that, and after some research, I found that the last THREE.js version has new features in the Raycasting. So i'm using this function for detecting the clicks on sprites, and it's working.
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function clickOnSprite(event){
console.log("CLICK! " + event.clientX + ", " + event.clientY);
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( iconsSprites );
intersects.forEach(function(element){
console.log("Intersection: " + element.object.id);
});
}

How to position sprites in Three.js?

I'm currently using PointCloud to generate a particle system but within that I would like one single sprite that floats in the position of my indication. When I tried using this three.js example: http://threejs.org/examples/#webgl_sprites I found that the Orthographic Camera limited my ability to still zoom about.
var container, stats;
var camera, scene, renderer, particles, geometry, materials =[], i, h, color, sprite, size;
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( 55, window.innerWidth / window.innerHeight, 2, 2000 );
camera.position.z = 1000;
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.001 );
geometry = new THREE.Geometry();
sprite = THREE.ImageUtils.loadTexture( "disc.png" );
for ( i = 0; i < 5000; i ++ ) {
var vertex = new THREE.Vector3();
vertex.x = 2000 * Math.random() - 1000;
vertex.y = 2000 * Math.random() - 1000;
vertex.z = 2000 * Math.random() - 1000;
geometry.vertices.push( vertex );
}
// size = Math.random() * 10;
material = new THREE.PointCloudMaterial( { size: 5, sizeAttenuation: false, map: sprite, alphaTest: 0.5, transparent: true } );
particles = new THREE.PointCloud( geometry, material );
scene.add( particles );
var map2 = THREE.ImageUtils.loadTexture( "astronaut.png" );
var material2 = new THREE.SpriteMaterial( { map: map2, color: 0xffffff, fog: true } );
var sprite2 = new THREE.Sprite( material2 );
sprite2.position.x = 0;
sprite2.position.y = 0;
sprite2.position.z = 498;
scene.add( sprite2 );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, 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;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var time = Date.now() * 0.00005;
camera.position.x += ( mouseX - camera.position.x ) * 0.05;
camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
camera.lookAt( scene.position );
h = ( 360 * ( 1.0 + time ) % 360 ) / 360;
renderer.render( scene, camera );
}
My attempt at solving it was:
var map2 = THREE.ImageUtils.loadTexture( "astronaut.png" );
var material2 = new THREE.SpriteMaterial( { map: map2, color: 0xffffff, fog: true } );
var sprite2 = new THREE.Sprite( material2 );
sprite2.position.x = 0;
sprite2.position.y = 0;
sprite2.position.z = 498;
scene.add( sprite2 );
Right now the sprite is in the center of the screen when I first load but instantly disappears when I begin to move the camera. Ideally, I would like the astronaut.png sprite to move with the other particles but if this is difficult, having him always fixed to the center of the screen would work fine as well.
Resolved this on my own. I created a second THREE.Geometry and THREE.Vector3 an positioned it with vertices.
geometry2 = new THREE.Geometry();
var vertex2 = new THREE.Vector3(0, 0, -50);
geometry2.vertices.push( vertex2 );
var material2 = new THREE.PointCloudMaterial( { size: 100, sizeAttenuation: false, map: map2, alphaTest: 0.5, transparent: true } );
particles2 = new THREE.PointCloud( geometry2, material2 );
scene.add( particles2 );
It seems to me that your values for mouse position would be way too high for camera positions. OpenGL works on the (-1,1) (1,1) (1,-1) (-1,-1) bounding rectangle as a unit. Pixels for your cursor position are in screen pixels like 350,720 etc.
When you increment by the half distance, your numbers are still too large. So here you have to divide by your width/height:
camera.position.x += ( mouseX / window.innerWidth- camera.position.x ) * 0.05;
camera.position.y += ( - mouseY /window.innerHeight- camera.position.y ) * 0.05;
assuming your GL portal is the same size as the window.

Vertex and Vector3 are not interchangeable in three.js

Starting on three.js revision 48 I made vertices connected by lines. It works fine but when updating to revision 65 from 48 I get an error message saying that Vertix is deprecated and should be replaced by Vector3. However, when I replace it with Vector3, Vector2 or Vector4 it behaves differently – the lines won't connect to the vertices anymore. I also get some strange rendering problems on the edges when the canvas is the width of the viewport.
var container = document.getElementById('container');
var camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,1,10000);
var distance = 1000;
camera.position.z = distance;
var scene = new THREE.Scene();
scene.add(camera);
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
camera.lookAt(new THREE.Vector3(0,0,0));
var geometry = new THREE.Geometry();
for ( var i = 0; i < 50; i ++ ) {
particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( {
color: Math.random() * 0x808080 + 0x808080, //0x0000000,
opacity: 1,//0.1,
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 1, 0, Math.PI * 2, true );
context.closePath();
context.fill();
}
} ) );
particle.position.x = Math.random() * 2000 - 1000;
particle.position.y = Math.random() * 2000 - 1000;
particle.position.z = Math.random() * 2000 - 1000;
particle.scale.x = particle.scale.y = Math.random() * 12 + 5;
scene.add( particle );
geometry.vertices.push( new THREE.Vertex( particle.position ) );
}
var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.05 } ) );
scene.add( line );
renderer.render( scene, camera );
document.addEventListener( 'mousemove', onMouseMove, false );
function onMouseMove(event){
mouseX = (event.clientX - window.innerWidth/2) / window.innerWidth/2;
mouseY = (event.clientY - window.innerHeight/2) / window.innerHeight/2;
camera.position.x = Math.sin(mouseX * Math.PI) * distance;
camera.position.y = - Math.sin(mouseY * Math.PI) * distance;
camera.lookAt(new THREE.Vector3(0,0,0));
renderer.render( scene, camera );
}
Try replacing the Vertex at line 42 with Vector3: http://jsfiddle.net/kz94z/
Try changing this line:
geometry.vertices.push( new THREE.Vertex( particle.position ) );
to this:
geometry.vertices.push( particle.position );

Raycasting and container in Three.js

I have been struggling with issues concerning raycasting on small circlegeometries on a sphere.
I know raycasting can't be done with sprites and this is why I use circlegeometries, but it doesn't work all the time, and moreover the raycasting doesn't always work on circles but sometimes around them as well.
Does anybody have an idea ? Here is a JSBin to show you basically
Edit :
I updated my previous version of JSBin, you can click any circleGeometries it will work here, run it with output tab only open for better results
This is related to the renderer width and height properties, my sphere isn't in fullscreen and this is why it fails.
Does anybody have an idea on how to set up it right in order to get this to work perfectly ?
The formula used to compute intersections wasn't the good one, here is the one that works :
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 x and y have slightly changed from the examples you can get, and are now fine.
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
projector.unprojectVector(vector, camera);
var ray = new THREE.Raycaster(camera.position, vector.sub(
camera.position).normalize());
var intersects = ray.intersectObjects(objects);
if ( intersects.length > 0 ) {
//do something
}
if you looking for some thing like this....Your code might need little changes... check this link http://jsfiddle.net/ebeit303/rjJ6q/
// standard global variables
var container, scene, camera, renderer, controls, stats;
var clock = new THREE.Clock();
// custom global variables
var targetList = [];
var projector, mouse = { x: 0, y: 0 };
init();
animate();
// FUNCTIONS
function init()
{
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 100000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(600,0,-1200);
camera.lookAt(scene.position);
// RENDERER
renderer = new THREE.CanvasRenderer();
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// EVENTS
// CONTROLS
// this material causes a mesh to use colors assigned to faces
var faceColorMaterial = new THREE.MeshBasicMaterial(
{ color: 0xffffff, vertexColors: THREE.FaceColors } );
var sphereGeometry = new THREE.SphereGeometry( 500, 64, 64 );
for ( var i = 0; i < sphereGeometry.faces.length; i++ )
{
face = sphereGeometry.faces[ i ];
face.color.setRGB( 0, 0, 0.8 * Math.random() + 0.2 );
}
var sphere = new THREE.Mesh( sphereGeometry, faceColorMaterial );
sphere.rotation.set(0, 14.5, 0);
scene.add(sphere);
//targetList.push(sphere);
var j=0;
for (var i =0; i<100;i+=5){
//var circle = new THREE.CubeGeometry(5,5,5);
var circle = new THREE.CircleGeometry(5, 8, 0, Math.PI * 2);
//THREE.GeometryUtils.triangulateQuads(circle);
var circleMaterial = new THREE.MeshBasicMaterial({color: 0xDEF2EF});
circleMaterial.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(circle, circleMaterial);
var Alon = i - 90;
var Alat = j;
var Aphi = Math.PI/2 - Alat * Math.PI / 180;
var Atheta = 2 * Math.PI - Alon * Math.PI / 180;
mesh.position.x = Math.sin(Aphi) * Math.cos(Atheta) * (501);
mesh.position.y = Math.cos(Aphi) * (501);
mesh.position.z = Math.sin(Aphi) * Math.sin(Atheta) * (501);
mesh.verticesNeedUpdate = true;
mesh.lookAt( sphere.position );
sphere.add(mesh);
targetList.push(mesh);
j++;
}
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}
function onDocumentMouseDown( 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, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = ray.intersectObjects( targetList );
if ( intersects.length > 0 )
{
intersects[ 0 ].object.material.color.setRGB( 0.8 * Math.random() + 0.2,
0.8 * Math.random() + 0.2,
0.8 * Math.random() + 0.2 );
}
}
function animate()
{
requestAnimationFrame( animate );
render();
}
function render()
{
renderer.render( scene, camera );
}

Categories

Resources