I propose a way to change the 3D coordinate basis.
The bases are expressed as a triad of perpendicular vectors.
Since in my case these vectors are all of length 1 and are perpendicular, this topic it's not about a "true" basis change but only the one useful for a 3D rotation.
The World basis (which is implicit) is composed of 3 vectors X,Y,Z of which only one direction has value 1 and all the others 0
WorldBase X = 1, 0, 0
WorldBase Y = 0, 1, 0
WorldBase Z = 0, 0, 1
This class allows you to provide a transformation basis formed by 3 perpendicular vectors.
It can be provided by directly entering these three vectors (Already normalized)
SetBasisNormalized
or by providing only two Vectors (preferably but not necessarily perpendicular)
SetBasisXY and SetBasisXZ
Once the transformation basis is provided, it is possible to transform a vector from one basis to another with the subs:
ToBasis and ToWorld.
ToBasis (WorldPosition , [out] BasePosition)
ToWorld (BasePosition , [out] WorldPosition)
For example, if you had to perform a rotation along the Z axis, it will be sufficient to give as baseX a vector that has X=cos(ang), Y=sin(ang) and as baseZ a vector that only has the value Z = 1
NOTE:
To specify the center of rotation, proceed as follows:
- The Center of Rotation must first be subtracted from the vector to be transformed.
- The transformation is applied.
- The Center of Rotation is added to the result of the transformation.
Another example:
You want your object to point to the Camera vector.
(Shortening)
VectorUP = Vector ( 0 , 1, 0 )
BASIS.SetBasisXY CameraPos - CameraLookAt , VectorUP
BASIS.ToBasis VectorIn - ObjCenter, TransformedV
TransformedV = TransformedV + ObjCenter
I hope it can be useful to someone.
(PS: in case you have a better idea you can express it here but to develop the discussion on it, in case, you are required to start a new thread, Thanks)
MODULE:
CLASS:
The bases are expressed as a triad of perpendicular vectors.
Since in my case these vectors are all of length 1 and are perpendicular, this topic it's not about a "true" basis change but only the one useful for a 3D rotation.
The World basis (which is implicit) is composed of 3 vectors X,Y,Z of which only one direction has value 1 and all the others 0
WorldBase X = 1, 0, 0
WorldBase Y = 0, 1, 0
WorldBase Z = 0, 0, 1
This class allows you to provide a transformation basis formed by 3 perpendicular vectors.
It can be provided by directly entering these three vectors (Already normalized)
SetBasisNormalized
or by providing only two Vectors (preferably but not necessarily perpendicular)
SetBasisXY and SetBasisXZ
Once the transformation basis is provided, it is possible to transform a vector from one basis to another with the subs:
ToBasis and ToWorld.
ToBasis (WorldPosition , [out] BasePosition)
ToWorld (BasePosition , [out] WorldPosition)
For example, if you had to perform a rotation along the Z axis, it will be sufficient to give as baseX a vector that has X=cos(ang), Y=sin(ang) and as baseZ a vector that only has the value Z = 1
Code:
BX.X = Cos( A )
BX.Y = Sin( A )
BX.Z = 0
BZ.X = 0
BZ.Y = 0
BZ.Z = 1
SetBasisXZ BX,BZ
NOTE:
To specify the center of rotation, proceed as follows:
- The Center of Rotation must first be subtracted from the vector to be transformed.
- The transformation is applied.
- The Center of Rotation is added to the result of the transformation.
Another example:
You want your object to point to the Camera vector.
(Shortening)
VectorUP = Vector ( 0 , 1, 0 )
BASIS.SetBasisXY CameraPos - CameraLookAt , VectorUP
BASIS.ToBasis VectorIn - ObjCenter, TransformedV
TransformedV = TransformedV + ObjCenter
I hope it can be useful to someone.
(PS: in case you have a better idea you can express it here but to develop the discussion on it, in case, you are required to start a new thread, Thanks)
MODULE:
Code:
Option Explicit
Public Type tVec3
X As Double
Y As Double
Z As Double
EndType
Public Function DOT3(A As tVec3, B As tVec3) As Double
DOT3 = A.X * B.X + A.Y * B.Y + A.Z * B.Z
End Function
Public Function CROSS3(A As tVec3, B As tVec3) As tVec3
With CROSS3
.X = A.Y * B.Z - A.Z * B.Y
.Y = A.Z * B.X - A.X * B.Z
.Z = A.X * B.Y - A.Y * B.X
End With
End Function
Public Function LEN32(V As tVec3) As Double
With V
LEN32 = (.X * .X + .Y * .Y + .Z * .Z)
End With
End Function
Public Function Normalize3(V As tVec3) As tVec3
Dim D As Double
With V
D = (.X * .X + .Y * .Y + .Z * .Z)
If D Then
D = 1# / Sqr(D)
Normalize3.X = .X * D
Normalize3.Y = .Y * D
Normalize3.Z = .Z * D
End If
End With
End Function
Code:
Option Explicit
Private BaseX As tVec3
Private BaseY As tVec3
Private BaseZ As tVec3
Friend Sub GetBasis(bX As tVec3, bY As tVec3, bZ As tVec3)
bX = BaseX
bY = BaseY
bZ = BaseZ
End Sub
Friend Function GetBaseZ() As tVec3
GetBaseZ = BaseZ
End Function
Friend Sub SetBasisNormalized(baX As tVec3, baY As tVec3, baZ As tVec3)
BaseX = baX
BaseY = baY
BaseZ = baZ
End Sub
Friend Sub SetBasisXY(bX As tVec3, bY As tVec3)
BaseX = bX
BaseY = bY
If LEN32(BaseX) <> 1# Then BaseX = Normalize3(BaseX)
If LEN32(BaseY) <> 1# Then BaseY = Normalize3(BaseY)
BaseZ = Normalize3(CROSS3(BaseX, BaseY))
If DOT3(BaseX, BaseY) <> 0 Then
BaseY = Normalize3(CROSS3(BaseZ, BaseX))
End If
End Sub
Friend Sub SetBasisXZ(bX As tVec3, bZ As tVec3)
BaseX = bX
BaseZ = bZ
If LEN32(BaseX) <> 1# Then BaseX = Normalize3(BaseX)
If LEN32(BaseZ) <> 1# Then BaseZ = Normalize3(BaseZ)
BaseY = Normalize3(CROSS3(BaseZ, BaseX))
If DOT3(BaseX, BaseZ) <> 0 Then
BaseZ = Normalize3(CROSS3(BaseX, BaseY))
End If
End Sub
Friend Sub ToBasis(V As tVec3, vOUT As tVec3)
'Equivalent to MAT3x3 MUL
' vOUT.X = DOT3(V, BaseX)
' vOUT.Y = DOT3(V, BaseY)
' vOUT.Z = DOT3(V, BaseZ)
' SAME:
vOUT.X = V.X * BaseX.X + V.Y * BaseX.Y + V.Z * BaseX.Z
vOUT.Y = V.X * BaseY.X + V.Y * BaseY.Y + V.Z * BaseY.Z
vOUT.Z = V.X * BaseZ.X + V.Y * BaseZ.Y + V.Z * BaseZ.Z
End Sub
Friend Sub ToWorld(V As tVec3, vOUT As tVec3)
' Vout = MUL3(BaseX, V.X)
' Vout = SUM3(Vout, MUL3(BaseY, V.Y))
' Vout = SUM3(Vout, MUL3(BaseZ, V.Z))
'SAME:
vOUT.X = BaseX.X * V.X + BaseY.X * V.Y + BaseZ.X * V.Z
vOUT.Y = BaseX.Y * V.X + BaseY.Y * V.Y + BaseZ.Y * V.Z
vOUT.Z = BaseX.Z * V.X + BaseY.Z * V.Y + BaseZ.Z * V.Z
End Sub