I want to ask for help regarding rotation using the Babylon.js framework.
I need the sphere to rotate 45 degrees, exactly aligned with the diagonal circle, which has a 45 degree orientation, but I'm not getting it.
The code I made is in the link below:
https://codepen.io/polalas/pen/VwvaKwL
The method responsible for the rotation is the loop () method, which is triggered every time the scene is rendered.
function loop () {
var y1 = scene.getMeshByName("I1");
y1.rotation.y - = 0.01 * Math.sin (Math.PI / 4);
y1.rotation.x - = 0.01 * Math.sin (Math.PI / 4);
}
I imagine that I mishandled the rotation. Could someone help, please?
Using your code, the best way to achieve that is to first rotate the parent of the sphere (what you called newMesh (or I1)) 45 degrees around the Z axis right before adding the sphere as a child:
newMesh.rotate(BABYLON.Axis.Z, Math.PI / 4);
Afterwards you can rotate it around its Local (!) X axis in your render loop:
function loop(){
var y1 = scene.getMeshByName("I1");
}
This way you get a perfect rotation around your (mocked) pivot.
Related
In Three.js I have 2 3d vectors and I want to find the x-axis and y-axis angle between them.
For the x-axis I found this
toDegrees(atan2(A.z, A.y) - atan2(B.z, B.y))
from
The X angle between two 3D vectors?
which works, but for y-axis, I am trying
toDegrees(atan2(A.z, A.x) - atan2(B.z, B.x))
but it gives me the wrong value. How can I fix this?
Thanks
You can use Vector3.angleTo directly, it will give you the angle in radians, as usual to math functions, here I printing it in degrees (multiplying by 180 degrees/pi rad= 1)
// notice that v1 is pointing to the x-axis direction.
const v1 = new THREE.Vector3(10,0,0);
const v2 = new THREE.Vector3(3,3,0);
const v3 = new THREE.Vector3(0, 50, 23);
// Alngle between v1 and v2
console.log(v1.angleTo(v2)*180/Math.PI)
// The operation is comutative
console.log(v2.angleTo(v1)*180/Math.PI)
// An example at 90 degree
console.log(v1.angleTo(v3)*180/Math.PI)
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
This makes it possible to find angles to any direction, if you want angle to a plane for instance, it is given by ans(a - 90) where a is the angle in degrees to the normal vector of the plane.
Let's say I have a circle with a line sticking out of it.
I want that line to point at the center of the window, no matter where the circle moves to.
But, I want that line to slowly move to that angle. I don't want the rotation to be calculated and set every single frame, but rather calculated and tweened to that direction.
The issue I'm having with this is that if you move to make the line rotate around where the radians meet 0, it will do a full 360 (or 3.14 in rads ;) to get to that point.
I have spent a while trying to think of how to explain this best, here is a codepen that can hopefully help clarify what I'm asking
// CenterX/Y is the center of the screen.
// dotX/Y is the center of the circle.
var angleToCenter=Math.atan2(centerY-dotY,centerX-dotX);
if (angleToCenter<currentAngle) {
currentAngle-=0.05;
} else {
currentAngle+=0.05;
}
if you move to the right of the screen, then go above or below the center, you will see the line move in a full circle to try to get to the calculated direction. How do I avoid this? I want the line to seamlessly rotate to point at the center, via the shortest possible way, not by doing a full circle.
Great question. Very different.
I would have an inverse (-1) relationship defined for any location below the black circle. Such that, if the red circle crosses a horizontal axis - whose boundry is defined by the black circle - the mathematical result to your equation is inversed.
This would make 0 degrees as we typically think of it, now positioned at 180 degrees.
Reasoning: Looking at your CodePen it's obvious that the stem is going "the long way around", but you want it to go the "short way around". The most intuitive way to make that happen would seem to be to inverse the red-circles calculated rotation. The simplest method I can think of would be to inverse the polarity of the circle.
The problem lies in the point where angleToCenter switches from Math.PI to -Math.PI (and vice versa).
Therefore I'd suggest you create an "epsilon angle distance", in which the angles will be hard-coded:
var angleToCenter = Math.atan2(centerY - dotY, centerX - dotX);
var epsilon = 0.05;
if (Math.abs(angleToCenter - Math.PI) <= epsilon / 2 || Math.abs(angleToCenter + Math.PI) <= epsilon / 2) {
if (dotY > centerY) {
currentAngle = -Math.PI;
} else if (dotY < centerY) {
currentAngle = Math.PI;
}
} else if (angleToCenter < currentAngle - epsilon) {
currentAngle -= epsilon;
} else {
currentAngle += epsilon;
}
For the full edit, you can check my fork to your CodePan
I want to move a shape around the circumference of a circle on HTML canvas. I am using the following JavaScript logic:
speed = 0.005;
angle = Math.PI/2;
angle += speed * direction;
var x = cx + (radius * Math.cos(angle));
var y = cy + (radius * Math.sin(angle));
direction is set by a key press (left arrow = -1, right arrow = +1). cx and cy are fixed - they are the x and y co-ordinates of the center of the circle around which the shape is moving.
I want to move the shape around the circle in fixed steps, like the seconds hand of a clock. However, there should be 187 steps. I know that dividing 360/187 = 1.9251 degrees = 0.03359 radians. However, my drawing function is inside a loop, so writing angle += 0.03359 makes the shape spin around the circle forever.
How can I make each key press move the shape either clockwise or anti-clockwise around the circle, but in steps of 0.3359 radians?
I am using the logic I found in the answer written by rafaelcastrocouto for this question: how to move object in circle forward and backward in html5 canvas?
You need to save the starting angle in avariable that you access each time you begin to draw:
This line:
angle = Math.PI/2;
should then look like this:
angle = window.starting_angle;
On each keypress, you either increment or decrement this variable and redraw the shape.
I have an orbital camera that orbits are a globe. There are several markers on the globe that the user can click on, and the camera will move to that point.
Using TweenMax for the animation like this -
TweenMax.to(currentPos, 3, {
theta:targetPos.theta,
phi:targetPos.phi,
radius:targetPos.radius,
ease:Circ.easeIn,
onComplete:btnZoomComplete,
onUpdateParams:["{self}"],
onComplete:SataliteTweenComplete,
onUpdate: function(tween) {
controls.setThetaPhi(tween.target.theta, tween.target.phi, tween.target.radius);
}
});
This works great, however is doesn't take into consideration the shortest route to get there. So it can quite often go 'round the back' of the globe.
ThreeJS seems to measure the angle in a really strange unit system:
0, 1.57 (equivalent to 90 degrees), 3.14 (eq 180dg), then after 3.14 is jumps to -3.14, -1.57 (eq to 270dg), then back to 0... So this blowing my mind on how to work it out.
For example, say the camera is at 2.6 and it needs to go over to -2.61, at the moment the camera will animate CCW (2.6 to -2.16), where as visual it needs to animate CW, which would move from 2.6 to 3.14, -3.14 then to -2.61.
Any help on this would be really appreciated.
I guess there are two problems, how to work out which way to go round, but then how to actually animate across from 2.6 -> 3.14, jump to -3.14 seamlessly -> -2.61
So that "strange unit-system" is just radians and it's quite common to measure theta/phi values in a range from -180° to 180° and -90° to 90° (think latitude/longitude, same thing). The conversion is simple:
angleDegrees = radians / Math.PI * 180;
radians = angleDegrees / 180 * Math.PI;
Now the tweening-library will just interpolate from one value to the other and doesn't know what these values represent. So it simply can't know how to handle the shortest path when it comes to rotations. However, you can do this before starting the tween.
Say we animate from 2.6 to -2.6 (or 149° to -149°).
var from = 2.6, to = -2.6;
The direction and angular distance for the animation can be calculated as
var distance = to - from;
// === -5.2
A negative value here means counterclockwise, and 5.2 (~298°) is the "distance" the camera will travel. Now keep in mind that any angle plus or minus 360° (2 * Math.PI) will essentially land you at the same position. So lets try:
var distance = (to + 2 * Math.PI) - from;
// === 1.083185307179586 (~62°)
So, if you rotate from your position at 2.6 to -2.6 + 2 * Math.PI (or, from 149° to -149° + 360° = 211°), you will get a clockwise animation with a shorter path.
To make sure that all values stay in their allowed range, we change the onUpdate-function a little bit to wrap around properly:
controls.setThetaPhi(
tween.target.theta % Math.PI,
tween.target.phi % Math.PI,
tween.target.radius);
You will probably also want to update the currentPos value with the actual values before the animation starts and below computation happens.
What's left to do is solving this for the general case, so to find out when to do the clockwise and counterclockwise rotation. To see if the other way around would be shorter, we just need to see if the distance would be greater than 180°:
if (Math.abs(to - from) > Math.PI) {
if (to > 0) { // if to is positive we remove a full-circle, add it otherwise
to = to - 2 * Math.PI;
} else {
to = to + 2 * Math.PI;
}
}
So here's the full code in jsFiddle:
http://jsfiddle.net/73v15kb6/1/
Rotating about Y and Z is as I would expect it to be, same thing with all the transitions.
When I try to rotate about X axis, it looks like THREE.js is doing something special to make it look "more cool" - but that's not what I want to achieve.
Reading similar topics I'm sure it's something to do with my rotateX function:
camera.position.y = y * cos - z * sin;
camera.position.z = y * sin + z * cos;
camera.lookAt(scene.position);
When I initiate the 3d world I set the camera's coordinates with the following values, just to keep the desired view:
camera.position.x = -60;
camera.position.y = 30;
camera.position.z = 0;
Has anyone got a clue what I'm doing wrong? Thanks a lot!
I'm new to THREE.js, (In fact, this is my first time working with it), so I might not explain it properly :(
The part THREE.js did to make it look "more cool" was the camera.lookAt method.
camera.lookAt(sphere.position);
Here is the sample (modified) http://jsfiddle.net/73v15kb6/3/
Try to play around with the animate function for each axis and try with the lookAt option enabled. Playing with it for some time will give you the concept. :)
function animate() {
requestAnimationFrame(animate);
rotateX(5); // Try with Y & Z; (also with toggling lookAt())
}
The lookAt function may make the transformation functions seem weird since even if the camera transform as expected, the rendering area will still be the same.
Thanks Sen Jacob for fixing my fiddle!
I found a solution, so to have this working as I wanted - that camera always looks at the center point (0,0,0) and all the rotations of the word happens around the axis, I had to do the following for each rotation:
for rotZ and rotY
camera.up = new THREE.Vector3(0,1,0);
camera.lookAt(new THREE.Vector3(0,0,0));
for rotX:
camera.up = new THREE.Vector3(1,0,0);
camera.lookAt(new THREE.Vector3(0,0,0));
Notice the difference in up vector between X and Y&Z.