Making Geometries clickable Hyperlinks in Three.js (WebGl Renderer) - javascript

So I've been trying to make a spherical 360 panorama using three.js which implements clickable objects, which at the moment I would like to make hyperlinks.I've read many of the previous examples of raycasting and such, but have had no luck in getting the object to actually redirect me to the site. If someone could tell me where I'm going wrong in the code I'd greatly appreciate it.
I have a feeling the orbiting/panning function under "onDocumentMouseDown" is interfering with the raycasting? I'm still new to this and figuring it out.
<div id="container"></div>
<script src="three.min.js"></script>
<script>
var container, stats;
var camera, controls, scene, renderer;
var objects = [], plane;
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(),
offset = new THREE.Vector3();
var fov = 70,
texture_placeholder,
isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
init();
animate();
function init() {
var container, mesh1, sphere1, cube1;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
mesh1 = new THREE.Mesh( new THREE.SphereGeometry( 500, 60, 40 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'spherical_map_small.jpg' ), transparent: true} ) );
mesh1.scale.x = -1;
scene.add( mesh1 );
meshMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff});
var sphere1 = new THREE.Mesh( new THREE.SphereGeometry( 2.5,20,20 ), meshMaterial );
sphere1.position.set( 50, 10, 0 );
scene.add( sphere1 );
sphere1.userData = { URL:"http://www.google.com"};
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
document.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( sphere1 );
if ( intersects.length > 0 ) {
controls.enabled = true;
SELECTED = intersects[ 0 ].sphere1;
var intersects = raycaster.intersectObject( sphere1 );
if ( intersects.length > 0 ) {
window.open(intersects[0].object.userData.URL);
}
}
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
isUserInteracting = false;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
renderer.render( scene, camera );
}
</script>

Looking at your code I notice that you create var mouse = new THREE.Vector2(), then you don't set its values at any point in the supplied code. Then in onDocumentMouseDown() you cast a ray into the scene with undefined mouse coordinates raycaster.setFromCamera( mouse, camera ); As var mouse has not been set it is very likely that that is the reason you are not getting the navigation to start.
What you need to do is get the normalised screen coordiantes of the mouse and pass that into the raycaster.setFromCamera I can not quite remenber if the screen is one or two units but something like
mouse.x = (event.clientX / window.innerWidth); // normalise the mouse screen pos
mouse.y = (event.clientY / window.innerHeight); // same
mouse.x *= 2; // 0 is the center. -1 is left and 1 is right
mouse.y -= 1; // center
mouse.y *= -2; // Think this is upside down If it does not work try positive 2
mouse.y += 1; // center
if it does not work try switching mouse.y the otherway around;
mouse.y *= 2; // remove the -2 and put in 2
mouse.y -= 1; // remove the += and put in -=
What I find very handy when messing about in 3D is to have a spare debug object in the scene. Something simple like a box or sphere. Use it to show a point on the raycaster's ray.
Something like
// creat a box
var box... blah blah box creation code/
boxP = new vector3(); // position of debug object
// position it halfway in the raycasters range
boxP.x = camera.x + rayCaster.ray.x* ((rayCaster.near+rayCaster.far)/2);
boxP.y = camera.y + rayCaster.ray.y* ((rayCaster.near+rayCaster.far)/2);
boxP.z = camera.z + rayCaster.ray.z* ((rayCaster.near+rayCaster.far)/2);
box.position.set(boxP.x,boxP.y,boxP.z);
Now with luck you should see where you clicks are going.
Also, I am not sure but if you are looking at the sphere from the inside you may have to set the material to doubleSided (I can't see it in your code) as the raycaster ignores faces with normals pointing away. Or try reversing the direction of each polygon.
That's about all I can suggest at the moment. Hope you find the problem.

Related

Three js 360 video camera controls api

I am using this demo:
https://threejs.org/examples/?q=video#webgl_video_panorama_equirectangular
with the following code:
let camera, scene, renderer;
let isUserInteracting = false,
lon = 0, lat = 0,
phi = 0, theta = 0,
onPointerDownPointerX = 0,
onPointerDownPointerY = 0,
onPointerDownLon = 0,
onPointerDownLat = 0;
const distance = 50;
init();
animate();
function init() {
const container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
scene = new THREE.Scene();
const geometry = new THREE.SphereGeometry( 500, 60, 40 );
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale( - 1, 1, 1 );
const video = document.getElementById( 'video' );
video.play();
const texture = new THREE.VideoTexture( video );
const material = new THREE.MeshBasicMaterial( { map: texture } );
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'pointerdown', onPointerDown );
document.addEventListener( 'pointermove', onPointerMove );
document.addEventListener( 'pointerup', onPointerUp );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onPointerDown( event ) {
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onPointerMove( event ) {
if ( isUserInteracting === true ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( onPointerDownPointerY - event.clientY ) * 0.1 + onPointerDownLat;
}
}
function onPointerUp() {
isUserInteracting = false;
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.MathUtils.degToRad( 90 - lat );
theta = THREE.MathUtils.degToRad( lon );
camera.position.x = distance * Math.sin( phi ) * Math.cos( theta );
camera.position.y = distance * Math.cos( phi );
camera.position.z = distance * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( 0, 0, 0 );
renderer.render( scene, camera );
}
Is there an api for the THREE.PerspectiveCamera so you can manually call zoom in / out, move left / right inside the scene ..etc?
Is this possible?
There is indeed an API for the Three.PerspectiveCamera, including a method to call to zoom in/out the camera.
https://threejs.org/docs/#api/en/cameras/PerspectiveCamera.zoom
If you wish to move the camera around the scene, you can update the position of the camera through updating its position attribute. This can be done by either updating each of its three coordinates individually, or using the 'set' method to pass in a Vector3 for its position. Below is the documentation to Object3D, which camera inherits from.
https://threejs.org/docs/#api/en/core/Object3D.position
Be wary though that script is already updating its position during its 'update' function, so you will need to possibly change those lines directly, depending on what you want to do.
Hopefully this helps!

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.

Position camera inside three.js cube

I'm starting learning three.js. I studied the Getting started section on the website and had a look to some examples, but I can't figure out many things.
What I'd like to do is to create a cube (a box) and put the camera in the middle of it, so that I would see the inner side of each face. Is this actually possible?
Looking at the documentation, various examples and on stackoverflow, right now I'm at this point:
var camera, scene, renderer;
var isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3(1, 1, 1);
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry(7, 7, 7);
geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
var material = [
new THREE.MeshBasicMaterial( { color: 0x8bf2a7 } ),
new THREE.MeshBasicMaterial( { color: 0x1ad9a5 } ),
new THREE.MeshBasicMaterial( { color: 0xdadcad } ),
new THREE.MeshBasicMaterial( { color: 0xb1b1b1 } ),
new THREE.MeshBasicMaterial( { color: 0x3a3a3a } ), // front
new THREE.MeshBasicMaterial( { color: 0xf5f5f5 } )
];
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(material) );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'dragover', function ( event ) {
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}, false );
document.addEventListener( 'dragenter', function ( event ) {
document.body.style.opacity = 0.5;
}, false );
document.addEventListener( 'dragleave', function ( event ) {
document.body.style.opacity = 1;
}, false );
document.addEventListener( 'drop', function ( event ) {
event.preventDefault();
var reader = new FileReader();
reader.addEventListener( 'load', function ( event ) {
material.map.image.src = event.target.result;
material.map.needsUpdate = true;
}, false );
reader.readAsDataURL( event.dataTransfer.files[ 0 ] );
document.body.style.opacity = 1;
}, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting === true ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
// WebKit
if ( event.wheelDeltaY ) {
camera.fov -= event.wheelDeltaY * 0.05;
// Opera / Explorer 9
} else if ( event.wheelDelta ) {
camera.fov -= event.wheelDelta * 0.05;
// Firefox
} else if ( event.detail ) {
camera.fov += event.detail * 1.0;
}
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
if ( isUserInteracting === false ) {
// lon += 0.1;
}
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
camera.position.z = 3;
/*
// distortion
camera.position.copy( camera.target ).negate();
*/
renderer.render( scene, camera );
}
I can actually see the cube from the inside, but it's not exactly what I want. I'm trying to put the camera in the exact center of the room and I would it to rotate on itself, but I don't exactly how to precisely move it.
If you look at this fiddle the only difference is the material.
Comment and uncomment the following line to see the effect.
THREE.ImageUtils.crossOrigin = '';
Also you can read more at this issue

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..
}

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