|
|
|
|
Gamemaker 6.1 Direct3D extensionsThe 3D examples given here will run in Gamemaker 7.0 without requiring any modification. Furthermore it looks as if there is every reason to move to Gamemaker 7 as the system requirements are similar.I've chosen to bypass the normal 2D mode of GM6.1 and go straight to 3D mode. This is basically because 3D is a lot more exciting. I've tried to make simple games with sprites for a long time. I used to believe that I could never learn the programming techniques for 3D. Since then I've learned a lot about rotation and started to understand the Direct3D lighting functions as implemented in Gamemaker. Please note that only a subset of Direct3D is available to Gamemaker 6.1 programs and some of the omissions are irritating. The care and feeding of QuaternionsThis is one of those weird techniques where you probably won't see the need for it unless you actually try it. In 2D games featuring rotation the direction variable is usually perfectly adequate but when you are programming in 3D in Gamemaker you will probably hit a point when you need to store the orientation of an object and you will find that it is not so easy to work with 3D orientations stored as angles.As a simple example a racing game set on a racetrack could be implemented using angles with the main angle being the direction the car is facing and the steering changing that angle but in an off-road game with slopes the vehicle may be tipped up far enough that the steering is determining the roll angle and the terrain is setting the direction. In a flight sim the player may "loop-the-loop" in which case the plane will be flying inverted. Quaternions are an extension of complex numbers and as such they obey some rules of algebra. They can be added, subtracted, multiplied, divided and even logs, exponents and square roots are possible. For our purposes the add and subtract operations are trivial and can be ignored. A Unit Quaternion is a quaternion with a total magnitude of one. Quaternions can be used to represent an axis of rotation and the degree of rotation about the axis. Multiple rotations can be combined by multiplying the quaternions and this is where it gets interesting, if an object's orientation is represented by a quaternion then the object can execute any sequence of turns, no matter how complicated, and simply multiplying the object's orientation by each rotation in turn will always yield the correct final orientation. Orientations can also be represented as matrices, but I find Quaternions better suited to Gamemaker for the following reasons:
When programming in C those reasons probably will not apply, you will have more access to Direct3D, and should be able to pass the matrix to it directly, and you may have access to optimised matrix ("vectorised") math libraries that will be far faster than the same number of calculations written as equations. A Quaternion can be used to rotate a vector, this is how I implement a flying camera, I start with a vector pointing in the minus x direction and rotate it and put the result into the "set_perspective" command, I also take a z vector, rotate that and use the result as the "up" direction. Script librarySince the same operations turn up again and again I've written scripts to carry out some of these operations. The script is documented in the page "Quaternions" and can be downloaded here. The script is a work-in-progress but I am confident that the parts I've written so far work consistently. I will try not to change the function of the parts I've already written, though I do intend to add functions and replace some of the longer calculations with shortened multiplied-out forms. I will put comments in the code to document it and I will try to update the description page. Other Scripts:A model maker for a smooth ring donut/torus: make_donut_model(radius,radius2,steps,steps2) radius is the radius of the torus radius2 is the radius of the cross-section so that the total outside radius=radius+radius2 and the radius of the hole=radius-radius2 steps=the number of segments round the torus (try 20) steps2=the number of steps through the hole (try 10) returns a model ID The model is generated as a series of triangle_strips so the vertex count is almost half that of the same model expressed as a triangle_list form. Model has been tweaked so the texture wraps onto the torus in a similar way to the basic sphere. When the texture is applied to the torus the top and bottom edges join up. Tile-able textures work well. More complex than complex numbersIf we start with the idea that i is the square root of minus one, and then define j as another root of -1 where i times j is equal to minus j times i (don't question this it just works) then we can take two complex numbers (A+iB) and (C+iD) and combine them as (A+iB)+j(C+iD) or multiplied out (A+iB+jC+ijD). For convenience of notation we define k=ij giving us (A+iB+jC+kD) which is the way quaternions are often written, though in my own notes I usually abbreviate it to (A,B,C,D), and frequently refer to the four parts as q0,q1,q2,q3. Given the rules that i.i=-1 and j.j=-1 and i.j=-j.i=k we can derive a set of rules for multiplication. We start with determining how the complex parts i, j, k multiply: i.j=k (given) j.i=-i.j=-k j.k=j.i.j=(-i.j).j=-i.j.j=-i.(-1)=i k.j=i.j.j=i.(-1)=-i k.i=i.j.j=-i.i.j=-(-1).j=j i.k=i.i.j=-j This now allows us to multiply (q0+iq1+jq2+kq3) by (r0+ir1+jr2+kr3) =(q0(r0+ir1+jr2+kr3)+iq1(r0+ir1+jr2+kr3)+jq2(r0+ir1+jr2+kr3)+kq3(r0+ir1+jr2+kr3)) =(q0(r0+ir1+jr2+kr3)+iq1r0+iiq1r1+ijq1r2+ikq1r3+jq2r0+jiq2r1+jjq2r2+jkq2r3+kq3r0+kiq3r1+kjq3r2+kkq3r3) =(q0(r0+ir1+jr2+kr3)+r0(iq1+jq2+kq3)-q1r1-q2r2-q3r3+i(q2r3-q3r2)+j(q3r1-q1r3)+k(q1r2-q2r1)) You do not need to understand this to use the scripts. Much of the above algebra was derived using Mathcad. Further to the above: a Quaternion has a magnitude and a conjugate. A conjugate is a quaternion where the signs of the i,j,k parts are flipped, so (A+iB+jC+kD) becomes (A-iB-jC-kD). Multiplying a quaternion by it's conjugate gives the square of it's magnitude. The magnitude of a unit quaternion is always one, though in reality after your computer has processed it enough times it may start to drift due to rounding errors. Quaternions can be inverted, the inverse of a quaternion is the conjugate over the square of the magnitude. For unit quaternions the inverse is simply the conjugate, so we can undo a rotation by multiplying by the conjugate of the rotation.
|