Get distance and angle from OrbitControl's target - three.js

I'm making a 3D earth explorer using three js and orbit control in which I want to be able to zoom in and open a external map at that location.
I therefore need the distance from the target as well as the current camera angle (to convert to long lat later). However, the orbit control library doesn't provide methods for getting this information.
I suppose that this is a simple 3D trigonometry problem but I can't wrap my head around it. How would you do that ?
Thanks !

Try this:
const polarAngle = controls.getPolarAngle();
const azimuthalAngle = controls.getAzimuthalAngle();
const distance = controls.object.position.distanceTo( controls.target );
Demo: https://jsfiddle.net/f2Lommf5/6109/
three.js R92

Related

Three.js keep object static relative to outside container div - EDIT now with jsfiddle

So I have the basic setup of a three.js-canvas rendered inside of a html-div. Inside the 3d-world I want to position an object in such a way that it appears to be glued on to this outside div (should never move in any way). Currently I have this solution:
render {
object.position.x = camera.position.x;
object.position.y = camera.position.y;
object.position.z = camera.position.z - 200;
}
This works for panning the camera (i have rotation disabled since i don't need it). However, once I zoom in or out it obviously doesn't work any more, since zooming doesn't change the camera's position values. My approach was to incorporate the camera.zoom factor into the above function, but i couldn't get it to work properly. Is there an easy transformation function or something i can use?
Edit: I created a jsfiddle, hopefully this helps figuring out the solution. As long as you pan the camera with right mouse the yellow plane doesn't move at all (wanted behaviour). When you zoom in or out it starts to move (unwanted behaviour): https://jsfiddle.net/rdyLp7uc/2/

How to return the frustum of the THREE.Perspective camera and store it as a variable?

I was looking on Three.js API and I found that the Frustum is used for the camera visible area. I was wondering if I can access the view frustum of my PerspectiveCamera and declare the frustum as an object. Basically, my goal is to color the frustum of the camera.
If you want to visualize the frustum of your camera, you can use a THREE.CameraHelper. It essentially does what you're describing in the question: it lets you color the frustum so you can visualize it.
To implement it, you simply need to initiate it with your camera as a parameter, then add it to the scene:
var camera = new THREE.PerspectiveCamera( 75, camRatio, 0.1, 1000 );
var helper = new THREE.CameraHelper( camera );
scene.add( helper );
You can read more about it in the docs and you can see it in action on the right side of this example
Update:
If you want to read the data used to build the helper, you can access its .pointmap property. It's got lots of points that determine the position of the near plane (n1, n2, n3...), far plane (f1, f2, f3...), target, etc. To get better acquainted with what each key means, you can look at its constructor from line 38 to 83. The code is very well-documented in there.

Threejs orbitalcontrols set target breaking camera rotation using mouse/touch

I am developing a standard panorama viewer, where a 360 picture is placed inside of a sphere and the user can look around using mouse and touch. I am using OrbtialControls for this and it is working fine.
The user can also load a new 360 picture, after loading the picture, I am trying to set the camera direction so that the user is looking in a certain direction. As I am using orbitalControls, I am using control.target.set(x,y,z) to do so. However that causes the camera to lock at that point and if I use the mouse or touch to look around, the camera position changes and it revolves around that point, rather than looking around inside the sphere.
Has anyone else seen this kind of behavior? Do I need to do something
The code is pretty simple.
controls.reset();
controls.target.set(window.newLookAt.x,window.newLookAt.y,window.newLookAt.z);
The purpose of controls.target.set(x,y,z) is to set the pivot point, so what you are facing is the expected behavior
Instead of setting the target (that has to be (0, 0, 0) in your case), why not putting the camera inside a THREE.Object3D and rotate this object
var camera = new THREE.PerspectiveCamera()
var container = new THREE.Object3D()
container.add( camera )
camera.position.set( 0, 0, 0.1 )
var controls = new THREE.OrbitControls( camera, renderer )
controls.target.set( 0, 0, 0 ) // Optional
container.rotate.y = Math.PI / 2 // Or whatever you want
So I ended up solving this myself. The issue was that my understanding of orbitControls was slightly off. All I needed to do was to set the target point in the same direction but way closer to the camera and presto, issue solved and things are working fine now.

How to move and object but keep the child object in the same (world) location

I am trying to find the solution to the question I asked here. I think I achieved the solution by creating and orbit object and inserting the camera as a child object to this one.
I want to be able to move the orbit object but keep the camera in the same world location. I tried this;
this.orbit.position.add(travel);
this.camera.position.sub(travel);
This works perfectly until I do rotation. The fact that my orbit object will have rotation about Z (only Z) axis is making things (world to local conversions) hard for me. and the code above obviously moves my camera to wrong locations.
How can I fix this problem?
Glad to see that you solved it, but I thought this might also be interesting for you in the event that things get more crazy -
I saw something in the SceneUtils that might be relevant - the attach/detach function. So you could do something like detach them, do whatever parent independent things you plan to do, then reattach them. This is nice because you can still do parent-y stuff between them, but you can also create blocks where they move in world space, and then reattach without the child moving to worldCoordinates in between.
So I tried to transform the travel vector by using quartenion of the orbit object:
this.orbit.position.add(travel);
this.camera.position.sub(travel.applyQuaternion(this.orbit.quaternion));
it did not work...
Since I wasn't sure what quarternions are exactly doing and rotation of orbit is only around Z axis it was quite easy to transform the travel vector to local coordinates as follows:
this.orbit.position.add(t);
var angle = -this.orbit.rotation.z;
var x = t.x * Math.cos(angle) - t.y * Math.sin(angle);
var y = t.x * Math.sin(angle) + t.y * Math.cos(angle);
var t2 = new THREE.Vector3(x, y, t.z);
this.target.position.sub(t2);
And it works like a charm...

Changing scale of Three.js object after it is loaded

I am developing an augmented reality project using Three.js and aruco-js. I made my code so that all my 3D Objects are added to the scene (empty) at the beginning but the data gets initially loaded on marker detection.
Now I want to create an interface for changing the objects appearance, starting with the possibility of scaling an object.
So I created an updateObject() function to set the new values like this:
function updateObject(object, rotation, translation)
{
...
...
...
// first method
object.scale.x = 200;
object.scale.y = 200;
object.scale.z = 200;
// second attempt
object.scale.set(300, 300, 300);
};
I tried both of the methods shown above to set the scale of my object but it has no effect to the rendered images I get. The interesting thing is that the values of the objects in my scene3d DOM object are the values I set in my function. But why doesn't it have any impact on the output?
I'm not very familiar with 3d programming in WebGL or Three.js, so if you could give me any hint where the problem might has it's origin I would really appreciate an answer.
FIX:
I took a closer look to the 3D objects I was loading and discovered that they have a children called "mesh" inside another children. By trying to change the scale of only the mesh I found out that it works this way. But I think it looks very ugly:
scene3d.children[visibleModels[0][0]+3].children[0].children[0].scale.set(2, 2, 2);
//visibleModels is a list of the markers/models that should be loaded
This is only a test for one single object to change but at least I found a way to solve this. Is this an ordinary way to change the scale of objects? If you have a better solution or anything to add feel free to contribute.
You could also try to scale the object by changing its matrix using the THREE.Matrix4.makeScale method instead:
object.matrix.makeScale( xScale, yScale, zScale );
Or the even simpler THREE.Matrix4.scale method:
object.matrix.scale( scale );

Resources