Hi, my game is played on the surface of a planet (which is basically a sphere). I need to be able to translate between scene coordinates (cartesian x, y and z axes) and polar coordinates (alpha, beta and distance as used by the arc rotate camera).
Using my basic knowledge of trigonometry, I figured out this routine:
const polarToCartesian = function(position) {
const alpha = position.x;
const beta = position.y;
const distance = position.z
const x = -Math.sin(alpha) * Math.cos(beta) * distance;
const y = Math.cos(alpha) * Math.cos(beta) * distance;
const z = Math.cos(alpha) * Math.sin(beta) * distance;
return new BABYLON.Vector3(x, y, z);
}
This works perfectly and allowed me to create a ground mesh that covers part of a sphere, but my math knowledge is not enough to figure out the reverse
const cartesianToPolar = function(position) {
const x = position.x;
const y = position.y;
const z = position.z;
const alpha = ???;
const beta = ???;
const distance = Math.sqrt(x * x + y * y + z * z);
return new BABYLON.Vector3(alpha, beta, distance);
}
Is there anyone here with the math skill to figure this out, or alternatively are there helper classes in Babylon that can help with this kind of conversion?
Note that this page and this page are not the answer because they define the angles differently from the way that the arc rotate camera does it.
If you want to see how I am using the arc rotate camera, refer to this PG
Your PG test of my function is very interesting. It appears not to work over the range where you tested it.
My ground is also not completely spherical, but much closer to what I expect. Here is an example
Note that the map is defined as hexagons on the back-end but I am drawing rectangles for now to keep is simple and will convert it to hexagons and smooth the edges later.
I can’t do a PG because it relies on the back-end server to generate the map.
I linked the English version of this page in my original question. The reason that I can’t use these formulas is that these are not the angles that the ArcRotateCamera uses for its alpha and beta, and it’s not a simple question of switching the axes around. The reason why I want this conversion is to position the ArcRotateCamera above a specific point on the globe without changing its height above the surface.
My camera code looks like this:
const OrbitalCamera = function (canvas, scene, planet) {
// See https://www.babylonjs-playground.com/#1A3M5C#169
const zeroAlpha = -Math.PI / 2;
const zeroBeta = Math.PI / 2;
const camera = new BABYLON.ArcRotateCamera(
"orbitalCamera",
zeroAlpha, zeroBeta, planet.radius + planet.maxElevation,
BABYLON.Vector3.Zero(),
scene,
true);
camera.upVector = new BABYLON.Vector3(0, 0, 1);
camera.panningSensibility = 0; // Disabling panning makes the right mouse button rotate the camera
camera.angularSensibilityX = 20000;
camera.angularSensibilityY = 20000;
camera.fov = Math.PI / 8;
camera.lowerAlphaLimit = -Math.PI;
camera.upperAlphaLimit = 0;
camera.lowerBetaLimit = 0;
camera.upperBetaLimit = Math.PI;
camera.lowerRadiusLimit = sceneParams.planetRadius + 10;
camera.upperRadiusLimit = sceneParams.skyboxHeight / 2;
camera.inputs.attached.pointers.buttons = [2];
delete camera.inputs.attached.keyboard;
camera.attachControl(canvas, true, false);
const positionCamera = function(position){
if (position) {
const polar = planet.cartesianToPolar(focus.position);
camera.alpha = zeroAlpha + polar.x;
camera.beta = zeroBeta + polar.y;
}
}
var focusedMesh;
const focusOn = function (mesh, sticky) {
if (sticky) focusedMesh = mesh;
else {
focusedMesh = null;
if (mesh) positionCamera(mesh.position);
}
}
scene.registerBeforeRender(function () {
if (focusedMesh) {
positionCamera(focusedMesh.position);
}
});
return {
camera,
focusOn
};
}
I updated your Babylon Playground to reflect the way that I set up the scene in my game, and my formula seems to work reasonably well over the range that I am using it - although I agree that your test shows that it is not useful for the more general case.
The camera always points to (targets) the center of the globe. I need to move it to a position where it is looking down on a particular spot on the globe, but at the height that the user chose via camera inputs (mouse scroll wheel or pinch zoom).
This PG shows what my scene looks like
Okay, to clarify,
you want the camera to rotate (change alpha & beta) so it looks directly at a specific box,
but continue to target center of sphere,
so targeted box will be between camera position and center of sphere
Yes, exactly.
To move the camera using only alpha and beta, such that if I was to draw a line from the camera to the center of the globe, the line would hit the ground at a specific x, y, z position within the scene.
Ok,
i’m not sure about your function,
but we can create a direction vector from sphere.position to picked box position,
then scale it by camera’s radius (distance) and apply that to the camera.position
If this won’t fit your needs, arcRotateCamera must have some conversions in it’s code… somewhere
Thank you, this is really close to a solution. In the PG if I click the same box over again it gets closer and closer to the camera, but other that this issue, your solution works.
Ah, it only happens after panning the scene (with right mouse).
In my case I am not always picking the mesh with the pointer, the player can also pick things from a list. Does your solution rely on mesh picking with the pointer to work?
pull a set of static data from your backend that you are happy to use for testing, and just dump that in a the pg. if you want to if you dont then no problem