Issue
I'm working on a Python program where I define my own vector 3D type. At least the way I imagined it, vectors can store both a position and rotation... if implementing quaternion rotations with 4 values is better I can attempt a vec4
but I strongly prefer avoiding those since I understand them even less and they're much more cumbersome. Note that this is a general description of my vec3
class, it can store either a position or rotation and objects can use an instance for each one (eg: self.pos = vec3(4, 16, 0)
and self.rot = vec3(0, 90, 180)
). What I have so far seems to work as intended and should need no further changes:
class vec3:
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
def rot(self, other)
self.x = (self.x + other.x) % 360
self.y = (self.y + other.y) % 360
self.z = (self.z + other.z) % 360
def dir(self):
# This is where the magic I'm missing must happen
return vec3(self.x / 360, self.y / 360, self.z / 360)
v = vec3(0, 90, 180)
# Result: 0 90 180
v.rot(vec3(-90, 45, 270))
# Result: 270 135 90
v.dir()
# Result: 0.75 0.375 0.25
# Correct range but doesn't represent direction
The issue I'm struggling with is how to get the real direction the vector is pointing toward, meaning the virtual arrow jutting out from the origin and pointing toward where this vector is looking: X is right, Y is forward, Z is up. Its rotation alone doesn't represent it: A rotation of 0 0 0
should be a direction of 0 1 0
, one of 0 0 45
(45* to the right) should probably translate as 0.5 0.5 0
(half of the forward direction is ceded to the right direction), if we add another 45* to look all the way to the right we have 0 0 90
which would point toward 1 0 0
. I don't mind if the directions are mixed up from how I'm imagining them, as long as this is done correctly and all possible combinations are predictable. What is the simplest conversion algorithm possible I can use in my dir
function?
Solution
It looks like you're using a rotation vector where each value says how much to rotate around that axis, which really means "how much to rotate the plane spanned by the other two dimensions by", so that a rotation vector (0,0,45)
represents a 45 degree rotation about the Z axis, i.e. a rotating of the XY plane by an eighth of a turn.
We can do this with a quick conversion from degrees to radians (so (0,0,45)
becomes (0,0,pi/4)
) so that we can trivially compute what the rotations for X and Y should be using basic trigonometry:
degreeVec3 = (0,0,45)
rotation = new Vec3()
angle = radians(degreeVec3.z)
rotation.x = cos(angle)
rotation.y = sin(angle)
So the original (0,0,45)
becomes (0.7071, 0.7071, 0)
, a quarter turn (0,0,90)
becomes (0,1,0)
, (0,0,135)
becomes (-0.7071, 0.7071, 0)
, etc.
The benefit of this approach is that by doing things this way, we are assured that our resulting rotation vector is always a unit vector, which makes doing any sort of additional work much easier than if we just tried to come up with some random set of values that effect the same rotation. For example, while any (s, s, 0)
vector represents a 45 degree rotation in the XY plane, only s=0.7071 will give us a unit vector, and trig functions help ensure we do.
Answered By - Mike 'Pomax' Kamermans
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.