I have an equirectangular texture of a panorama that is applied to the inside of a sphere. The camera is placed at the centre of the sphere and the user can rotate the camera to look around by clicking and dragging their mouse. However, when the user clicks and does not drag, I would like to be able to convert the screen co-ordinates to co-ordinates on the texture. I could determine the location on the texture given a the location in the world coordinates the user clicked but looking over the Three.js documentation I am unable to discern how I would go about this.
Ultimately, the question is how would I go about constructing a ray query to get the point of intersection between a ray from a given screen point and the textured sphere?
There are a lot of examples of this in the three.js examples directory. For example, http://mrdoob.github.com/three.js/examples/canvas_interactive_cubes.html.
The pattern your want to google for is this:
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( objects );
if ( intersects.length > 0 ) {
console.log( intersects[ 0 ].point );
}
This will work if the canvas is full browser. Also, objects is an array.
three.js r.53
Related
Three.js 76
I start to use Orthographic camera instead Perspective - has some troubles.
I use stemkoski's shader-glow for point animation in scene: he created some sphere and then use shader for it transparancy, i just add animation to it.
function animatePoints() {
var alphas;
var count;
var time;
let j = 0;
while ( animatedPoints[j] ) {
let threeGlow = animatedPoints[j];
let finishAnimation = threeGlow.meta.state.finishAnimation;
let itFinished = 0;
let pointGlowMat = threeGlow.material;
let pointGlowGeom = threeGlow.geometry;
// ########## make glow look at camera
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( threeGlow.position, camera.position);
alphas = pointGlowGeom.attributes.alpha;
count = alphas.count;
time = 0.001* Date.now();
if ( finishAnimation ) {
....
} else {
....
}
alphas.needsUpdate = true;
j++;
}
}
Main goal - to make glow look at camera. When camera was perspective i use solution with subtracts two vectors - camera position and glow position, so it look like glow looking at camera.
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( camera.position, threeGlow.position );
But now, when i use Orthographic camera this solution doesn't work correctly.
The problem is that now the glow should look not at camera position point, it should look at plane of the camera.
I make some pic scheme for that situation:look it, it very useful
So for each new glow (it's positions of course different) i must get new red vector, to make each glow look at orto cam.
Any ideas?
What you need to do to get the red vector in your image, is project vector sub on the vector representing the direction in which the camera is looking.
I think this is what you need:
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3()
.subVectors( camera.position, threeGlow.position )
.projectOnVector( camera.getWorldDirection() );
One way to make an object "look at" an orthographic camera by using this pattern:
object.quaternion.copy( camera.quaternion );
The object's view direction will be perpendicular to the camera's projection plane.
This approach is appropriate if neither the object nor the camera have a rotated parent.
three.js r.84
I have this three js scene: http://codepen.io/giorgiomartini/pen/ZWLWgX
The scene contains 5 things:
Camera - Not Visible
origen (3D vector) - At 0,0,0.
objOne - Green
objParent - Red
CenterOfscene - Blue
objOne is a child of objParent. And ObjOne looksAt origen, which is a 3d vector at 0,0,0.
But the objOne instead of looking at the 0,0,0. where the origin vector is, It looks at objParent....?
Got any ideas?
What i want is the objOne to look at the 0,0,0. Which is the origen vector.
Any ideas why this is misbehaving? thanks.
THREE.SceneUtils.detach( objOne, objParent, scene );
THREE.SceneUtils.attach( objOne, scene, objParent );
var origen = new THREE.Vector3( 0, 0, 0 );
var render = function () {
objOne.lookAt(origen);
requestAnimationFrame( render );
xOffset += 0.01;
yOffset += 0.011;
zOffset += 0.012;
xOffsetParent += 0.0011;
yOffsetParent += 0.0013;
zOffsetParent += 0.0012;
camXPos = centeredNoise(-1,1,xOffset);
camYPos = centeredNoise(-1,1,yOffset);
camZPos = centeredNoise(-1,1,zOffset);
objOne.position.x = camXPos*4;
objOne.position.y = camYPos*4;
objOne.position.z = camZPos*4;
camParentXPos = centeredNoise(-1,1,xOffsetParent);
camParentYPos = centeredNoise(-1,1,yOffsetParent);
camParentZPos = centeredNoise(-1,1,zOffsetParent);
objParent.position.x = camParentXPos*10;
objParent.position.y = camParentYPos*10;
objParent.position.z = camParentZPos*10;
renderer.render(scene, camera);
};
render();
Object3D.lookAt() does not support objects with rotated and/or translated parent(s).
Your work-around is to (1) add the child as a child of the scene, instead, and (2) replace the child object with a dummy Object3D, which, as a child of the parent object, will move with the parent.
Then, in your render loop,
child.position.setFromMatrixPosition( dummy.matrixWorld );
child.lookAt( origin );
three.js r.75
Here is the corrected codepen:
http://codepen.io/anon/pen/oxGpPQ?editors=0010
Now the green disk rides around its parent (the red sphere) all while looking at the blue disk (or the 'origen' vector).
Uncomment lines 163 and 164 to make the camera be at the green disk's location and have the camera also look at the blue disk ('origen' vector) while it orbits its parent red sphere.
How I accomplished this is:
1. make parent Red Mesh
2. make dummyChild Object3D (this is an invisible math object)
3. make child Green Mesh
4. make origen centerOfScene Blue Mesh
5. attach parent, child, and centerOfScene mesh to Scene (not dummyChild though)
6. attach dummyChild to parent like so: parent.add(dummyChild);
In render function:
1. Move parent around with noise function (which offsets dummyChild)
2. Move dummyChild with another noise function (which revolves around its parent position, the center of dummyChild's world is its red parent's position)
3. Stick the green child mesh wherever the invisible dummyChild is. But since dummyChild is offset by red parent, we need to get it's world coordinates in relation to Scene, not its coordinates in red's world, so we use
child.setFromMatrixPosition(dummyChild.matrixWorld);
Notice its matrixWorld and not matrix - matrix holds its local system and matrixWorld holds its coordinated relative to the Scene or World coordinate system.
4. Use lookAt to make the green child disk 'lookAt' the blue centerOfScene Mesh which is at the origen vector or the center of the Scene.
Hope this helps! :)
I have an sphere with divs using CSS3DRenderer. When I click to one of the divs I'd like to position/rotate the camera so the element displays in the center of the screen.
I've tried several examples and I've read other answers but still I cant get it to work.
At the moment it moves the camera but the sphere gets repositioned in different places
What I'm trying to do is the following:
Gets the HTML element's class. Then loop through an array of THREE.CSS3DObject to get its position, then use that to position the camera.
function moveCamera(element) {
for ( var i = 0; i < objects.length; i ++ ) {
var object = objects[ i ];
if(object.element.className == element.className) {
position = object.position;
rotation = object.rotation;
found = true;
break;
}
}
if (found) {
camera.rotation = rotation;
render();
found = false;
} }
What I'm I doing wrong?
Here's the example http://jsfiddle.net/37R22/1/
Thanks
You were close. You just have to move the camera to the right place.
camera.rotation.copy( rotation );
camera.position.copy( position ).multiplyScalar( 4 );
Updated fiddles: http://jsfiddle.net/37R22/2/ or http://jsfiddle.net/37R22/3/
Be careful about going behind-the-back of TrackballControls and modifying the camera properties yourself. This appears to work, however.
three.js r.65
In OpenLayers 2D maps there's a property called restricted extent that doesn't allow to pan or zoom outside a defined bounding box.
Can I make something similar with Google Earth Plugin in 3D?
Obviously the problem is that one can bend (incline) the view, something that cant be achieved in 2D.
I have already restricted the view if thers no bend or incline in the map but that's far from being what I want..
Thanks!!
Update 1:
By now I have restricted the bbox with a handler on viewchangeend event, if the actual viewport (north, south, east, west) is outside some predefined initial values I move the view to the initial position again.
var viewchangeend = function viewchangeendhandler(){
var actualViewport = {
north: ge.getView().getViewportGlobeBounds().getNorth(),
south: ge.getView().getViewportGlobeBounds().getSouth(),
east: ge.getView().getViewportGlobeBounds().getEast(),
west: ge.getView().getViewportGlobeBounds().getWest()
};
if (actualViewport.north > initialViewport.north || actualViewport.south < initialViewport.south ||
actualViewport.east > initialViewport.east || actualViewport.west < initialViewport.west){
var la = ge.createLookAt('');
la.set(initialX, initialY, 0, ge.ALTITUDE_RELATIVE_TO_GROUND, 0 , 0, 50000);
ge.getView().setAbstractView(la);
}
}
For example in the initial case where I dont incline the view the relation north-south (north minus south) is static, but when I incline the view the relation grows and the initial viewport cannot be used to know if the actual viewport is ok.
Thanks again!
Perhaps you should consider using hitTest() instead of getViewportGlobeBounds()
See this SO Question which links to this Google Example
Have a play with the Google Example by tilting the view and see the resulting difference between the two
I am working on panoramic scene . And I want to move a plane with cursor. When I move mouse, plane must be mouse coordinates. And I want to take plane 3D coordinates (x,y,z) expecially z-coordinate. I try below code. But it doesnt work correctly. Mouse and plane are not be same coordinates on screen. How I can do?
public class RayTracer
{
public static function getIntersection(viewport:Viewport3D, camera:CameraObject3D, normal:Array):Number3D
{
var plane3D:Plane3D=new Plane3D();
plane3D.setNormalAndPoint(new Number3D(0, 1, 0), new Number3D(0, 0, 0));
var cameraPosition:Number3D=new Number3D(camera.x, camera.y, camera.z);
var ray:Number3D=camera.unproject(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY);
ray=Number3D.add(ray, cameraPosition);
var intersect:Number3D=plane3D.getIntersectionLineNumbers(cameraPosition, ray);
return intersect;
}
}
As far as I know there is no Z coordinate of the Mouse even in PV3d.
No i will try. I am trying to Mouse3d object and run below code:
private function onEnterFrame(param1:Event=null):void{
renderer.renderScene(scene, camera, viewport);
var mouse3D:Mouse3D;
viewport.interactive=true;
Mouse3D.enabled=true;
mouse3D=viewport.interactiveSceneManager.mouse3D;
trace(mouse3D.x, mouse3D.y, mouse3D.z)
}
But mouse3D coordinates always (0,0,0). I dont know why.