I'm using this very simple code to rotate objects around their own origin
void Entity::rotate(unsigned short axis, float speed, float delta)
{
m_Orientation[axis] += delta * speed;
glm::quat quaternion = glm::quat(glm::vec3(m_Orientation[0], m_Orientation[1], m_Orientation[2]));
m_RotationMatrix = glm::mat4_cast(quaternion);
}
The issue I'm facing is that the rotation is only relative to object's direction on the X axis. Meaning that no matter which way the object is facing (what it's orientation is), if I rotate it around X it will always rotate around it's own X axis. That is what I would like to do, but on the other 2 axis as well.
But Y and Z always rotate around world X and Y axis, disregarding which way my object is facing.
My code is so small and simple I don't really see the problem? Is the X rotation being always correct the accident, or is it that the other two are wrong?
I suggest that you try this:
#include <glm/gtx/euler_angles.hpp>
/**
If you change speed to a vec3,
it do all the calculations at once
(you won't have to do it for each angle)
**/
void Entity::rotate(glm::vec3 speed, float delta)
{
rotation = speed * data
m_modelMatrix *= glm::eulerAngleXYZ(rotation.x, rotation.y, rotation.z);
}
The glm::eulerAngleXYZ function will take the angles and create a rotation matrix from it.
But be aware of gimbal lock.
If you do your multiplication of the matrix from right to left, it will rotate around the global axis. If you do it the other way, it will rotate around the local axis.
Related
Currently I'm working on a orbit system for a game. I've got it so an object will move along a circle based on a progress value that'll be between 0.0 and 1.0 (0.5 being half way around the circle). I calculate this like this:
float angle = Mathf.Deg2Rad * 360 * t;
float xPos = Mathf.Sin(angle) * xAxis;
float yPos = Mathf.Cos(angle) * yAxis;
return new Vector3(xPos, yPos, 0.0f);
With t simply being deltatime and the xAxis/yAxis variables being the radius of the circle.
What I'm a little stuck on currently though is how I could possibly get the progress around the circle based on a poisition. So if I have an object that hits the bottom of the circle, how do I calculate that to be a progress of 0.5?
First step: Find out the angle of your given position with the y-axis.
Second step: Calculate the fraction of a full circle (360 degs) that your angle has.
First step involves a bit of trigonometry, and there you have to make sure to get the right type of angle based on what quadrant you're in. Second step should be trivial then.
You can check out the atan2 function that's available in many programming languages: https://en.wikipedia.org/wiki/Atan2
It gives the angle between a point (x, y) and the positive x-axis. So then in your case, depending on where your circle starts, you'd then shift that by 90 degrees to get the angle with the positive y-axis. Other than that it should work fine though.
I am trying to build a rotation controller for my threejs objects. My rotation method is the following:
function rotate(axis, angle) {
rotMat = new THREE.Matrix4().makeRotationAxis(axis, angle);
rotMat.multiply(mesh.matrix);
rotQuat = new THREE.Quaternion().setFromRotationMatrix(rotMat);
mesh.quaternion.copy(rotQuat);
mesh.updateMatrix();
}
I need to do it this way in order to have a rotation around the world axes and not the local axes (related to this post -> I also cannot use the Euler rotation member here because of a problem i describe here)
Getting to my problem:
I made this JSFiddle which shows the issue pretty good.
How to recreate:
1) Open the fiddle link.
2) Press X, Y or Z on your keyboard to enter the rotation mode for the desired axis.
3) Hold 'Arrow Up' key and rotate as long as the 'strange' scaling occurs. Should happen at an angle of 90-100 degrees. Note that the scaling continues if you keep rotating
Also note that i decrease the rotation step size (rotation speed) when getting to the specific angle area. The scaling only occurs when the rotation step size is quite small.
My question is:
Does somebody know why a rotation is causing a scale?
The reason why this is happening is because you need to feed a 'pure' rotation matrix to the Quaternion.setFromRotationMatrix method. So changing the rotate function to the following will work:
function rotate (axis, angle) {
rotMat = new THREE.Matrix4().makeRotationAxis(axis, angle);
rotMat.multiply(mesh.matrix);
var rotMat2 = new THREE.Matrix4().extractRotation(rotMat);
rotQuat = new THREE.Quaternion().setFromRotationMatrix(rotMat2);
mesh.quaternion.copy(rotQuat);
mesh.updateMatrix();
}
Even after hours of googling, I can't really get my head around this. Maybe somebody here can help me a bit with this.
I basically want to determine the Y-rotation of an object (that is always in the viewport's center), relative to my camera. Imagine the object standing on the center of a record player/turntable, that slowly rotates around its Y axis, and my camera always facing the center of that object while using OrbitControls to change the cam's position around the object. Imagine the camera not moving, but the turntable turning, one revolution equals this Y rotation to be between 0° and 360°.
For example, this Y rotation would be:
0° when cam's position is [x=0, y=0, z=100], or [x=0, y=100, z=200] (the cam's y position doesn't matter, it always looks down/up to the group's center),
45° when cam's position is [x=100, y=0, z=100] or [x=100, y=200, z=100],
90° when cam's position is [x=100, y=0, z=0] or [x=200, y=100, z=0], etc.
Thing is, both of these can have some pretty random positions & rotations in the world coordinate system, so it's not given that the object's position is [x=0, y=0, z=0].
Any ideas? Thanks a lot!
I'm not sure if I'm being helpful, but perhaps Object3D.getWorldQuaternion and Quaternion.angleTo() might help?
something like :
const cameraQuaternion = new THREE.Quaternion();
camera.getWorldQuaternion(cameraQuaternion);
const targetQuaternion = new THREE.Quaternion();
target.getWorldQuaternion(targetQuaternion);
const delta = cameraQuaternion.angleTo(targetQuaternion);
const euler = new THREE.Euler().setFromQuaternion(delta);
console.log(euler.y / Math.PI * 180);
Im trying to crate a shader, that converts fft-data (passed as a texture) to a bar graphic and then to on a circle in the center of the screen. Here is a image of what im trying to achieve: link to image
i experimentet a bit with shader toy and came along wit this shader: link to shadertoy
with all the complex shaders i saw on shadertoy, it thought this should be doable with maths somehow.
can anybody here give me a hint how to do it?
It’s very doable — you just have to think about the ranges you’re sampling in. In your Shadertoy example, you have the following:
float r = length(uv);
float t = atan(uv.y, uv.x);
fragColor = vec4(texture2D(iChannel0, vec2(r, 0.1)));
So r is going to vary roughly from 0…1 (extending past 1 in the corners), and t—the angle of the uv vector—is going to vary from 0…2π.
Currently, you’re sampling your texture at (r, 0.1)—in other words, every pixel of your output will come from the V position 10% down your source texture and varying across it. The angle you’re calculating for t isn’t being used at all. What you want is for changes in the angle (t) to move across your texture in the U direction, and for changes in the distance-from-center (r) to move across the texture in the V direction. In other words, this:
float r = length(uv);
float t = atan(uv.y, uv.x) / 6.283; // normalize it to a [0,1] range - 6.283 = 2*pi
fragColor = vec4(texture2D(iChannel0, vec2(t, r)));
For the source texture you provided above, you may find your image appearing “inside out”, in which case you can subtract r from 1.0 to flip it.
I want to create a graphic calculator and Im stuck with the graph bit. I want to know how to plot a graph for sin(x) cos(x) tan(x). I have made the grid already. I dont want to use core plot framework.
Any help would be appreciated.
Thanks.
To actually plot the function, do like you would with paper and pencil: evaluate the function for a number of inputs. Then draw lines to connect the resulting points.
Not that I would actually do this (I would look at Core Plot), but you could plot such a graph using a Core Image generator filter, like this:
//wavelength and magnitude are distances in destination pixels. Think of them as the width and height of each wave.
kernel vec4 sineWave(float wavelength, float magnitude, __color color)
{
vec2 coord = destCoord();
coord.y -= magnitude;
coord /= vec2(wavelength, magnitude / 2.0);
float pi = radians(180.0);
float value = sin(coord.x * pi);
//Smaller threshold = finer wave line. For a gradient, replace the comparison with 1.0 - abs(…).
float threshold = 0.1;
float alpha = abs(coord.y - value) <= threshold;
return color * alpha;
}
Here is some pseudo-code that could answer your question:
for i = xmin to xmax do
{
draw XY point at X=(i*x_scale_factor+x_offset) and Y=(sin(i)*y_scale_factor+Y_offset);
}
And beware: don't use floats in for loops
EDIT in response to comments
The easiest way to proceed, IMHO, would be to get the bounds of your view, to get the min and max values of your data on both X and Y axis.
You then can use a NSAffineTransform instance to transform the coordinates of your drawings. So everything can be done in your graphic coordinates, which is easier. You can write a label at coordinates (4.6, 3.2*10-7) if you wish to. This is a key point to get you started. The road is long. But using NSAffineTransform will make it easier.