|
quaternions.gml File Reference25/10/11 Important note: init_quaternion_random contained an error that caused it to output non-normalised results, and also probably skewed the distribution. 18/8/19 Added guard code to prevent a divide-by-zero in GM Studio. Passing exactly 0,0,0 as an axis causes GMS to silently abort the draw event, making the object vanish for this one condition.
Detailed DescriptionA collection of Gamemaker scripts for rotation using simplified quaternion algebra.Quaternions are derived from complex numbers, and whereas a unit complex number can describe an orientation in a 2D space a quaternion can describe any orientation in a 3D space and provides a code-efficient means to transform orientations particularly in Gamemaker where the more usual matrix algebra would require a larger number of operations for the same result Quaternions have many of the characteristics of rotation matrices and indeed the same results could be obtained from matrices. In my opinion quaternions are preferable in Gamemaker as the gamemaker language does not have vectorised math functions (matrix functions) or an effective way to feed a rotation matrix into Direct3D. Quaternions are used routinely in 3D modelling as they provide an efficient way to store an orientation. Define Documentation
d3d_add_rotation_quaternion(q0,q1,q2,q3) Function to apply quaternion q0,q1,q2,q3 to the current drawing state using a rotation about an axis. The function uses d3d_transform_add_rotation_axis and old versions have a weakness that meant that the d3d function could be called with arguments of 0,0,0,0 in one specific circumstance. Under GM studio this causes the current event (usually the draw event) to be aborted making the object disappear. Note that although I do not have mathematical proof it appears as though any orientation may be expressed as a single rotation about an axis, and therefore that any combination of rotations about multiple axes may be combined into one rotation about new axis
d3d_quaternion_light_direction(ind,q0,q1,q2,q3,color) Arguments are ind,q0,q1,q2,q3,color Applies a directional light according to a quaternion Script treats plus x as the base direction.
d3d_quaternion_light_direction_neg(ind,q0,q1,q2,q3,color) Arguments are ind,q0,q1,q2,q3,color Applies a directional light according to a quaternion Script treats minus x as the base direction. Use whichever one makes most sense to you.
d3d_quaternion_set_projection(x,y,z,q0,q1,q2,q3) Set a camera orientation from a quaternion This script treats plus x as the base direction, e.g. looking RIGHT on the map, to be consistent with the rest of Gamemaker
d3d_quaternion_set_projection_ext(x,y,z,q0,q1,q2,q3,angle,aspect,znear,zfar) Set a camera orientation from a quaternion using the extended form This script treats plus x as the base direction, e.g. looking RIGHT on the map, to be consistent with the rest of Gamemaker Derived from d3d_quaternion_set_projection_neg();
d3d_quaternion_set_projection_neg(x,y,z,q0,q1,q2,q3) Set a camera orientation from a quaternion This script treats minus x as the base direction, e.g. looking LEFT on the map, which is inconsistent with the rest of Gamemaker but was convenient in d3d as on a textured sphere the middle of the texture faces left. This function will be replaced, for consistency with 2D games where zero degrees means looking right.
d3d_quaternion_set_projection_neg_ext(x,y,z,q0,q1,q2,q3,angle,aspect,znear,zfar) Set a camera orientation from a quaternion using the extended form This script treats minus x as the base direction, e.g. looking LEFT on the map, which is inconsistent with the rest of Gamemaker but was convenient in d3d as on a textured sphere the middle of the texture faces left. This function will be replaced, for consistency with 2D games where zero degrees means looking right. Derived from d3d_quaternion_set_projection_neg();
d3d_set_rotation_quaternion(q0,q1,q2,q3) Function to apply quaternion q0,q1,q2,q3 to the current drawing state using a rotation about an axis. The function uses d3d_transform_set_rotation_axis Derived from d3d_add_rotation_quaternion() script
Sets the variables q0,q1,q2,q3 to the basic unit quaternion (1,0,0,0);
Sets the variables q0,q1,q2,q3 to a random orientation quaternion. This is done by generating random angles and converting the result to a quaternion note the special distribution of "theta" needed to prevent bias towards certain orientations Picture a globe, phi is longitude, theta is latitude and psi is which way you are facing. Phi and Psi can be simply random but if theta is a simple random number then if you are near the poles the lines of longitude are closer together. This skews things Starting from the equator on a radius 1 globe the area of the northern hemisphere is 2*pi and the length of a line of latitude is 2*pi*cos(theta). The area between the equator is 2*pi*sin(theta) (basic integral, this only works in radians otherwise the scaling gets ugly) and from this I infer that sin(theta) should have a flat distribution and so if theta=arcsin(random) then sin(theta)=sin(arcsin(random)) so sin(theta)=random (provided random lies in the range -1 to +1) 25/10/11 Important note: The version of this function previously available has a typo: multiply_quaternion_right(cos(psi/2),0,0,sin(psi/2)); //<==typo, psi NOT phi Please correct or substitute a newer version
multiply_quaternion(r0,r1,r2,r3,s0,s1,s2,s3) multiply two quaternions r and s arguments are real,i,j,k,real2,i2,j2,k2 result is returned in variables q0,q1,q2,q3 note that the order of the two quaternions is very important. multiply_quaternion(s,r) is not the same as multiply_quaternion(r,s)
multiply_quaternion_left(l0,l1,l2,l3) multiply two quaternions l (from arguments) and q (from object) arguments are real,i,j,k parts of quaternion note that the order of the two quaternions is very important. multiply_quaternion_left will apply a rotation in the room's reference frame not the object's frame.
multiply_quaternion_right(r0,r1,r2,r3) multiply two quaternions q (from object) and r (from arguments) arguments are real,i,j,k parts of quaternion result is returned in variables q0,q1,q2,q3 note that the order of the two quaternions is very important. multiply_quaternion_right will apply a rotation in the object's reference frame
Normalises (q0,q1,q2,q3) Ensures that math errors have not shifted the absolute value away from 1. Note that this function uses slow math functions but the optimised math form uses more code and so would run slower in Gamemaker.
quaternion_ball_roll_simple(radius) This function implements a simple rolling motion by converting the object's hspeed,vspeed into a rotation and applying that to the object's orientation (q0,q1,q2,q3).
pitch manouver script for aircraft-like movement causes an object to pitch by an amount angle see quaternion_fly_roll() for details
roll manouver script for aircraft-like movement causes an object to roll by an amount angle using multiply_quaternion_right() causes the rotation to be carried out in the object's reference frame instead of the room's frame
yaw manouver script for aircraft-like movement causes an object to yaw by an amount angle see quaternion_fly_roll() for details
quaternion_rotate_vector(x,y,z) script to rotate a vector by an object's quaternion arguments are the x,y,z components of the vector the result is put into variables vx,vy,vz this can be called with (1,0,0) to obtain a vector pointing the way the object is facing. Use (-1,0,0) if you are using the _neg functions
This function is defined as sin(x)/x It is used by the quaternion_ball_roll_simple() function as part of the formula for converting a vector into a rotation axis because it is valid for x=0 and so it won't cause divide by zero errors note that for very small x sinc(x) is close to 1-sqr(x)/6 and when x is effectively zero sinc(x) is defined as being 1
|