Tribes 2 RPG - Ironsphere II Mod

2»

Comments

  • As mentioned a few times in this thread, one of the big issues is going to be working out the limitations of the engine's AI for a proper RPG setting (You're essentially locked out of Dungeon style encounters with high enemy counts).

    A few other mentions are also correct, that there is no real "close combat" implements that can feasibly be worked out so you're locked into a style of gameplay similar to TES3 where you'll only have access to slashing weapons only with no type of counter or combat lock. I've only ever gotten close to a form of implementation of this on one of my old construction mods (Nighthawk) where I did something kind of like a Harry Potter style magic duel where players had to mash their jetpack key to win the duel. That's essentially as far as the engine will allow you to go in terms of that.

    Thyth did mention Abrickofham's photon missile example for seeking style behavior. I have a copy of his original on my disk if you want it, and I have an adaptation of the code in use for TWM2 3.8 which you can view here if interested.

    The biggest challenge you're going to face with using the IS codebase is really a mess of code and massive functions that simply need to be re-done entirely. As said before if you're really going to tackle this challenge you should definitely opt into the route of starting fresh at T2 base and working out a brand new mod from there.
  • As mentioned a few times in this thread, one of the big issues is going to be working out the limitations of the engine's AI for a proper RPG setting (You're essentially locked out of Dungeon style encounters with high enemy counts).

    A few other mentions are also correct, that there is no real "close combat" implements that can feasibly be worked out so you're locked into a style of gameplay similar to TES3 where you'll only have access to slashing weapons only with no type of counter or combat lock. I've only ever gotten close to a form of implementation of this on one of my old construction mods (Nighthawk) where I did something kind of like a Harry Potter style magic duel where players had to mash their jetpack key to win the duel. That's essentially as far as the engine will allow you to go in terms of that.

    Thyth did mention Abrickofham's photon missile example for seeking style behavior. I have a copy of his original on my disk if you want it, and I have an adaptation of the code in use for TWM2 3.8 which you can view here if interested.

    The biggest challenge you're going to face with using the IS codebase is really a mess of code and massive functions that simply need to be re-done entirely. As said before if you're really going to tackle this challenge you should definitely opt into the route of starting fresh at T2 base and working out a brand new mod from there.
    Honestly, I'm not too worried about the codebase itself. Much of it was taken (albeit somewhat sloppily) from Tribes 1 RPG. While it is still somewhat of a mess, to me it's a mess I'm familiar and can work with. But it still can use some improvements. I've already cleaned up most of the giant chat function so that commands (eg. #say and #hide) directly map to functions rather than multiple huge switch statements. The functions are then organized into files based on skill categories along with the rest of their skill information, so they are easier to find and everything relevant is in one place. I still need to do the rest of the non-skill related commands, but at this point it's pretty easy. And since I integrated the Skill Info hud with that code, all the description information will get passed to the client for use on the Skill Info hud.

    I still think a lot more can be done with the combat, via script. Again, Skyrim is not the goal. But this does put a heavier emphasis on skills (hence why I redid the codebase for them). So a better approach to "melee" combat would be something similar to the Diablo series. Where skills are used nearly as often (or more) as weapon swings.
  • Huh. Ironsphere. Now that's a name I've not heard in a long time.

    Me reviving Ironsphere into Ironsphere II was initially an AP project my friends and I were doing for high school. After we turned in the project, my friends didn't want to help anymore so I lost motivation to continue (end second team). Some months later after school finished I tried to bring it back again and proper, but it ended up getting dropped again. I decided to move to Garry's mod, and with some friends we ended up making a neat little RPG loosely based off of tribes' rpg.

    To anyone involved in bringing this mod back, please message me on Skype (shinji145) or Steam (http://steamcommunity.com/id/shinjiku144/) I would love to contribute, and see this mod finally finished.
  • Huh. Ironsphere. Now that's a name I've not heard in a long time.

    Me reviving Ironsphere into Ironsphere II was initially an AP project my friends and I were doing for high school. After we turned in the project, my friends didn't want to help anymore so I lost motivation to continue (end second team). Some months later after school finished I tried to bring it back again and proper, but it ended up getting dropped again. I decided to move to Garry's mod, and with some friends we ended up making a neat little RPG loosely based off of tribes' rpg.

    To anyone involved in bringing this mod back, please message me on Skype (shinji145) or Steam (http://steamcommunity.com/id/shinjiku144/) I would love to contribute, and see this mod finally finished.
    So far, it's pretty much just me directly working on it. But I'm having lots of support from others on this forum with getting up to speed on Torque. As I've probably said multiple times at this point, most of my experience comes from extensively modifying Tribes 1 RPG.

    I'll hit you up over steam. This gives me an excuse to to turn my scribbles into an actual plan of attack :P. Currently, I've just been tackling things one task at a time.
  • edited January 2016
    Off the top of your head, do you know if there's a way to create the ELF beam effect between two objects, without using a weapon image objects. I'd love to use that for some kind of life or mana draining spell effect. TRPG doesn't use weapon images for spells, which I'd like to keep it that way if possible. Worse case scenario, I could create invisible or super tiny ELF turrets ;D. I swear, Tribes scripting requires a "thinking with portals" mentality sometimes.

    Well, I did it. I created an ELF turret to create the ELF beam, literally off the top of my head :P

    bixMIGw.jpg?1

    But in all seriousness, this was a pain in the butt. I could use an ELF projectile and spawn it from a turret_muzzlepoint.dts image, but the beam tracking is limited to a 180 degree arc in front of the player. So a turret is the best option i could think of that makes the beam track around the player with less of an insane arc. However, I ran into another issue. Turrets seem to have a limited list of usable .dts files. I tried replacing the Turret Base's default image with the turret_muzzlepoint.dts, and T2 didn't not like that one bit. I then tried using Camera.dts. That worked (in the sense that T2 didn't crash), but it couldn't aim the mounted barrel, let alone fire it.

    Using this big honking thing as a hat doesn't work out too well. When you mount the turret to the player, the player keeps colliding with it every now and then as you walk. I also can't seem to change offset. My only options are the hand (slot 0), the back (slots 1-7) and the feet (any other slot). In the image, the turret is mounted to slot 1. Is there any way to add a mount offset? Or is that set in stone within the .dts?

    I also might try using one of the smaller turrets instead. Also, is there a way to disable collision for an object?
  • If all else fails, using %turret.startFade(1,0,1) would hide the turret and %turret.setScale("0.1 0.1 0.1") would reduce the scale and thusly reduce its bounding box to hopefully acceptable levels.

    I recall that there is a way to trick the engine into not running collision checks, but I don't remember what it is exactly. If I'm not mistaken, Thyth might know about that one -- though I might be mixing him up with Naosyth or someone else.

    However, a turret may not be necessary. As mentioned in the other thread regarding this, have you tried other T2 weapon images?
  • edited January 2016
    If all else fails, using %turret.startFade(1,0,1) would hide the turret and %turret.setScale("0.1 0.1 0.1") would reduce the scale and thusly reduce its bounding box to hopefully acceptable levels.

    I recall that there is a way to trick the engine into not running collision checks, but I don't remember what it is exactly. If I'm not mistaken, Thyth might know about that one -- though I might be mixing him up with Naosyth or someone else.

    However, a turret may not be necessary. As mentioned in the other thread regarding this, have you tried other T2 weapon images?
    Using a weapon image for the ELFProjectile works too. But as I said, I was limited to what looked like a 180 degree arc in front of the player. At first, it was a 30 degree arc, until I found the BeamHitWidth parameter by doing a dump(). Tried setting it to 360, but it looks like it caps it (I'm guessing the cap is at 180, might be something less than).

    What I didn't like, is how the beam behaves. It goes out straight first, then curves towards the target. I could increase the number of controlpoints to make the curve start sooner, but it still won't activate on targets behind the player. Also, target selection is funky. It seems to prefer targets closer to the crosshair rather than distance to the target. Someone could be right next to me, but the beam will lock on to someone 100m away if my aiming direction is more towards them than the closer guy. Makes sense for the ELF Projector, but not this.

    With a turret, I get the full 360 degrees around the player. And the beam doesn't bend like a wet noodle, at least in terms of yaw. Also, I can pick the turret's target. Only problem is that I have very limited control the position of where the beam starts, unless I can give a mounting offset for the turret. But as long as I can make it look like the beam is coming out of the player, I'll take it as long as I can get around the collision issue.

    What is really neat about not using a turret is how the projectile persists. You don't have to hold down a trigger or anything. Once spawned, it just follows the player around and calls the ELFProjectileData::zap() when a target is in range and in the BeamHitWidth arc. And it still works when I can change weapon images. And it will change targets seamlessly. Using an invisible beam, I could quickly find a target that is near the player's line of sight. Effectively, it can act like a cone-shaped raycast (conecast?) for player objects. Saving this hack for later.

    Edit: I realize about 80% of my work on this mod lately has been case studies like this. While I love researching stuff like this, it means my progress on the actual RPG mod itself has slowed. But some of it should pay off later.
  • As mentioned in the other thread, there is a lot of quirky engine behavior. While also very dynamic in many areas, there's still a good handful of places where its rigidly hard coded and modification to the game's executable or runtime memory (via TribesNext-provided memPatch) may be necessary.

    You are also thinking of raycasts. There is no such thing as a conecast, only ray casts and radius checks. Something that might help is this reference I've generated (and regenerated several times already): http://dx.no-ip.org/doku.php?id=documents:t2engine
    It's just a raw scrape of the engine executable for various function and global variable registrations, so it should pick up on stuff that people might not even know existed. The only issue is that the information provided is limited to what the registration calls I scraped gave it, so the engine-set descriptions may not be sufficient. I will also note that its definitely buggy in some subtle and not-so-subtle ways, buts its probably still fairly useful.
  • As mentioned in the other thread, there is a lot of quirky engine behavior. While also very dynamic in many areas, there's still a good handful of places where its rigidly hard coded and modification to the game's executable or runtime memory (via TribesNext-provided memPatch) may be necessary.

    You are also thinking of raycasts. There is no such thing as a conecast, only ray casts and radius checks. Something that might help is this reference I've generated (and regenerated several times already): http://dx.no-ip.org/doku.php?id=documents:t2engine
    It's just a raw scrape of the engine executable for various function and global variable registrations, so it should pick up on stuff that people might not even know existed. The only issue is that the information provided is limited to what the registration calls I scraped gave it, so the engine-set descriptions may not be sufficient. I will also note that its definitely buggy in some subtle and not-so-subtle ways, buts its probably still fairly useful.
    I actually ran across that document a few weeks ago, but had trouble finding it again. Didn't realize you were the one who put it together. As an aside, it's interesting that there's both a MatrixMulVector and a MatrixMulPoint. What's the difference, I wonder.

    As for the conecast, that was a play on words. I was just saying that using an invisible ELFProjectile of a known BeamHitWidth and grabbing the object ID from the 3rd paramater of the resulting ElfProjectileData::zap() could act somewhat like a raycast, but in a cone around your crosshair. Really, I think the engine is probably raycasting behind the scenes or something. But you don't have to do any function calls or math on the script side.

    To do that via script, I'd probably create a trigger box in front of the player, see what all IDs resulted from the onEnter, then get my player's muzzletranform. Then for each player found in the trigger, subtract my player's position from theirs and normalize it to get a direction. Then using the dotproduct and ArcCos I'd find the angle between "1 0 0" for side to side and "0 0 1" for up and down. Then see if their player's angles fall between + or - an amount from the angles I can get out of the muzzletransform. You get the idea.

    That was all off the top of my head, so my math likely off. And there might be an somewhat easier way (like a radius check instead of a trigger). But the point I'm trying to make is that using an invisible ELFProjectile accomplishes the same thing, but with less work.

    You could also think of it as a cone-shaped trigger in that's always in front of the player. Since you can look away and loop back, and the Zap and Unzap functions will be called. It's a little weird that the Zap and Unzap functions fall under ELFProjectileData and not the individual ELFProjectiles, but it's workable with if statements.
  • https://github.com/Ragora/T2-DXAI/blob/master/scripts/DXAI/helpers.cs#L185

    That does what you're describing, though it has a small chance for false-negatives. Worked well enough for my bots to use it, though. There's actually a massive computational complexity issue with it that I can fairly readily solve using mAtan and the player's forward vector, I just never got around to it yet.

    MatrixMulVector and MatrixMulPoint is probably floating point multiplication versus integer multiplication respectively, by the way.
  • If all else fails, using %turret.startFade(1,0,1) would hide the turret and %turret.setScale("0.1 0.1 0.1") would reduce the scale and thusly reduce its bounding box to hopefully acceptable levels.

    I recall that there is a way to trick the engine into not running collision checks, but I don't remember what it is exactly. If I'm not mistaken, Thyth might know about that one -- though I might be mixing him up with Naosyth or someone else.

    However, a turret may not be necessary. As mentioned in the other thread regarding this, have you tried other T2 weapon images?
    You might try setting scale to "0 0 0", but selectively disabling collision on objects that are already mounted is tricky. You might be able to make it work by mounting a muzzlepoint shaped object in the target slot on the player object, and then mounting the turret to the muzzlepoint object. I think collision checks stop happening after 2 levels of mounts.
    MatrixMulVector and MatrixMulPoint is probably floating point multiplication versus integer multiplication respectively, by the way.
    Restricting a matrix/vector multiplication to integers doesn't seem like a particularly useful thing to do. The built-in matrix functions are fairly poorly documented, but I get the sense that they're designed around 4x4 homogeneous coordinate transformations. The Vector versus Point variants of the MV multiply might end up being identical. Reading the Torque source is probably going to be a prerequisite if you actually want to use them.
    Yikes -- you know that you can compute cone intersection much more easily? cos(theta) < dot(norm(forward_vector), norm(position_delta_vector))
    You typically want to pre-compute the cosine that way instead of doing arccos on each of the dot products, because dot product is fast, and transcendental functions are slow.
  • edited January 2016
    You might try setting scale to "0 0 0", but selectively disabling collision on objects that are already mounted is tricky. You might be able to make it work by mounting a muzzlepoint shaped object in the target slot on the player object, and then mounting the turret to the muzzlepoint object. I think collision checks stop happening after 2 levels of mounts.
    I was curious how far mount-ception could go. I'll give this a try.
    Restricting a matrix/vector multiplication to integers doesn't seem like a particularly useful thing to do. The built-in matrix functions are fairly poorly documented, but I get the sense that they're designed around 4x4 homogeneous coordinate transformations. The Vector versus Point variants of the MV multiply might end up being identical. Reading the Torque source is probably going to be a prerequisite if you actually want to use them.
    The reason why I asked was because I came across MatrixMulPoint while reading a google preview on one of the TGE books, but could not find it in the scripts. It sounds like it takes a localized point (ie. w/ respect to the origin) and applies a given transform to it. So if a player transform was applied to "-2 0 5", it would place the point 2m behind the player and 5m up while also accounting for the player's rotation. Or something like that. Not sure if X would be front/behind or side/side. Essentially it looks like it adds the positions and uses the rotation within the transform and to do a matrix rotation on the point. Sounds like it could be pretty useful.

    The passage in the TGE book references T2 in regards to doing collision checks with scaled bounding boxes. Did a quick search in the scripts, but never found a use of MatrixMulPoint (must have been in engine where it's used). But I did find MatrixMulVector, specifically where projectile spread is accounted for in ShapeBaseImage::onFire(). If they do the exact same thing, then maybe MatrixMulVector is an alias for MatrixMulPoint for the sake of consistent terminology.
  • Yikes -- you know that you can compute cone intersection much more easily? cos(theta) < dot(norm(forward_vector), norm(position_delta_vector))
    You typically want to pre-compute the cosine that way instead of doing arccos on each of the dot products, because dot product is fast, and transcendental functions are slow.

    Oh I know, a lot of that doesn't need to occur period if I just use mAtan to acquire the facing. A huge portion of that code was to fake the player's X facing because I didn't immediately have a way offhand to grab it (I tried using a component in their rotation, but I don't remember why that didn't work). At the time, I didn't realize I could just do %facing = mAtan(%forwardVectorY, %forwardVectorX) then cast out the various points really easily. Most if it was just to try and get my trig a little better, really.
    Restricting a matrix/vector multiplication to integers doesn't seem like a particularly useful thing to do. The built-in matrix functions are fairly poorly documented, but I get the sense that they're designed around 4x4 homogeneous coordinate transformations. The Vector versus Point variants of the MV multiply might end up being identical. Reading the Torque source is probably going to be a prerequisite if you actually want to use them.

    The engine is filled with all sorts of other useless bits. I wouldn't be surprised. Here's the definition for both anyway (they're right next to each other): https://github.com/GarageGames/Torque3D/blob/1a009d6dd31b66832de3b67e76465ad1f313a9dc/Engine/source/math/mathTypes.cpp#L938
  • The engine is filled with all sorts of other useless bits. I wouldn't be surprised. Here's the definition for both anyway (they're right next to each other): https://github.com/GarageGames/Torque3D/blob/1a009d6dd31b66832de3b67e76465ad1f313a9dc/Engine/source/math/mathTypes.cpp#L938
    Okay, the differences is slight, but still there. Both functions end up here:
    inline void m_matF_x_point3F(const F32 *m, const F32 *p, F32 *presult)
    {
       AssertFatal(p != presult, "Error, aliasing matrix mul pointers not allowed here!");
       
    #ifdef TORQUE_COMPILER_GCC
       const F32   p0 = p[0], p1 = p[1], p2 = p[2];
       const F32   m0 = m[0], m1 = m[1], m2 = m[2];
       const F32   m3 = m[3], m4 = m[4], m5 = m[5];
       const F32   m6 = m[6], m7 = m[7], m8 = m[8];
       const F32   m9 = m[9], m10 = m[10], m11 = m[11];
       
       presult[0] = m0*p0 + m1*p1 + m2*p2  + m3;
       presult[1] = m4*p0 + m5*p1 + m6*p2  + m7;
       presult[2] = m8*p0 + m9*p1 + m10*p2 + m11;
    #else
       presult[0] = m[0]*p[0] + m[1]*p[1] + m[2]*p[2]  + m[3];
       presult[1] = m[4]*p[0] + m[5]*p[1] + m[6]*p[2]  + m[7];
       presult[2] = m[8]*p[0] + m[9]*p[1] + m[10]*p[2] + m[11];
    #endif
    }
    
    
    //--------------------------------------
    inline void m_matF_x_vectorF(const F32 *m, const F32 *v, F32 *vresult)
    {
       AssertFatal(v != vresult, "Error, aliasing matrix mul pointers not allowed here!");
    
    #ifdef TORQUE_COMPILER_GCC
       const F32   v0 = v[0], v1 = v[1], v2 = v[2];
       const F32   m0 = m[0], m1 = m[1], m2 = m[2];
       const F32   m4 = m[4], m5 = m[5], m6 = m[6];
       const F32   m8 = m[8], m9 = m[9], m10 = m[10];
       
       vresult[0] = m0*v0 + m1*v1 + m2*v2;
       vresult[1] = m4*v0 + m5*v1 + m6*v2;
       vresult[2] = m8*v0 + m9*v1 + m10*v2;
    #else
       vresult[0] = m[0]*v[0] + m[1]*v[1] + m[2]*v[2];
       vresult[1] = m[4]*v[0] + m[5]*v[1] + m[6]*v[2];
       vresult[2] = m[8]*v[0] + m[9]*v[1] + m[10]*v[2];
    #endif
    }
    

    The difference is that MatrixMulPoint is the [X Y Z] of the point and sticks a 1 on the end => [X Y Z 1]. So when the Point and Transform are multiplied, indexes 3, 7, and 11 of the transform matrix are added into the result. MatrixMulVector just uses [X Y Z 0]. I have no idea what this accomplishes, in game.
  • The description on both functions for the engine registration said that, one uses w =1 and the other uses w = 0.
    The engine is filled with all sorts of other useless bits. I wouldn't be surprised. Here's the definition for both anyway (they're right next to each other): https://github.com/GarageGames/Torque3D/blob/1a009d6dd31b66832de3b67e76465ad1f313a9dc/Engine/source/math/mathTypes.cpp#L938
    Okay, the differences is slight, but still there. Both functions end up here:
    inline void m_matF_x_point3F(const F32 *m, const F32 *p, F32 *presult)
    {
       AssertFatal(p != presult, "Error, aliasing matrix mul pointers not allowed here!");
       
    #ifdef TORQUE_COMPILER_GCC
       const F32   p0 = p[0], p1 = p[1], p2 = p[2];
       const F32   m0 = m[0], m1 = m[1], m2 = m[2];
       const F32   m3 = m[3], m4 = m[4], m5 = m[5];
       const F32   m6 = m[6], m7 = m[7], m8 = m[8];
       const F32   m9 = m[9], m10 = m[10], m11 = m[11];
       
       presult[0] = m0*p0 + m1*p1 + m2*p2  + m3;
       presult[1] = m4*p0 + m5*p1 + m6*p2  + m7;
       presult[2] = m8*p0 + m9*p1 + m10*p2 + m11;
    #else
       presult[0] = m[0]*p[0] + m[1]*p[1] + m[2]*p[2]  + m[3];
       presult[1] = m[4]*p[0] + m[5]*p[1] + m[6]*p[2]  + m[7];
       presult[2] = m[8]*p[0] + m[9]*p[1] + m[10]*p[2] + m[11];
    #endif
    }
    
    
    //--------------------------------------
    inline void m_matF_x_vectorF(const F32 *m, const F32 *v, F32 *vresult)
    {
       AssertFatal(v != vresult, "Error, aliasing matrix mul pointers not allowed here!");
    
    #ifdef TORQUE_COMPILER_GCC
       const F32   v0 = v[0], v1 = v[1], v2 = v[2];
       const F32   m0 = m[0], m1 = m[1], m2 = m[2];
       const F32   m4 = m[4], m5 = m[5], m6 = m[6];
       const F32   m8 = m[8], m9 = m[9], m10 = m[10];
       
       vresult[0] = m0*v0 + m1*v1 + m2*v2;
       vresult[1] = m4*v0 + m5*v1 + m6*v2;
       vresult[2] = m8*v0 + m9*v1 + m10*v2;
    #else
       vresult[0] = m[0]*v[0] + m[1]*v[1] + m[2]*v[2];
       vresult[1] = m[4]*v[0] + m[5]*v[1] + m[6]*v[2];
       vresult[2] = m[8]*v[0] + m[9]*v[1] + m[10]*v[2];
    #endif
    }
    

    The difference is that MatrixMulPoint is the [X Y Z] of the point and sticks a 1 on the end => [X Y Z 1]. So when the Point and Transform are multiplied, indexes 3, 7, and 11 of the transform matrix are added into the result. MatrixMulVector just uses [X Y Z 0]. I have no idea what this accomplishes, in game.

    The description on both functions for the engine registration said that, one uses w =1 and the other uses w = 0.
  • The description on both functions for the engine registration said that, one uses w =1 and the other uses w = 0.
    Right, but that brought up the question "what is 'W'?" I still don't quite know qualitatively what it is. Just what it being 1 or 0 implies for these functions, now that I've stepped through them.
  • It's just a 4x4 transformation matrix:
    http://www.euclideanspace.com/maths/geometry/affine/matrix4x4/
    http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

    You'll want to look around for a more complete description of the purpose of such transformation matrices.
  • Interesting. In almost all situations I can think of, you'll want to use the version with w=1 -- I'm not actually sure when you would ever want to use w=0.

    You can use homogeneous coordinate vectors (X, Y, Z, and W) with a 4x4 transformation matrix to concisely express an arbitrary set of rotation, transformation, and scale operations on a set of 3D points. The W value is added to the vector to enable free transformation in 3D space -- if you stick to 3x3 matrices for 3D transformations, you're restricted to the 3D equivalent of affine transforms (e.g. scale, translation, and shearing), and can't freely express rotation. In order to have a meaningful application of one of these transform matrices, you set w=1.

    It's reasonably straightforward to express scale and transformation matrices as 4x4's. Scale matrices take the form:
    a 0 0 0
    0 b 0 0
    0 0 c 0
    0 0 0 1
    To scale a point (relative to origin) by 'a' on the x-axis, 'b' on the y-axis, and 'c' on the z-axis.

    Transform matrices take the form:
    1 0 0 a
    0 1 0 b
    0 0 1 c
    0 0 0 1
    Which will add (relative to the origin), 'a' to the x-axis, 'b' to the y-axis, and 'c' to the z-axis.

    Rotations end up being a little bit more complex, defined in terms of sine/cosine of the 3 rotation angles in the first 3x3 part of the matrix, but are fundamentally about re-defining the X, Y, and Z axis values in the new rotated reference coordinate system. You can kind of see an artifact of that in the first 3x3 of the above matrices where the first 3 elements of the first row are "1 0 0", which is the definition of a vector along the X axis; ditto for the next two rows, specifying "0 1 0" as the Y axis, and "0 0 1" as the Z axis. The rotation matrix redefines them to still be unit vectors that are orthogonal (dot product between them is 0). I don't remember the formula definitions off hand, but you can probably derive them with the intuition about the axis representation within the matrix, and thinking through the behavior of matrix-vector multiplication at the different 90 degree turns (where all of the values in the first 3x3 are 1, 0 or -1) -- or just look up the formula for calculating new basis vectors for a particular set of rotation angles.

    You can use this representation to compose multiple operations by matrix-matrix multiplication. E.g. rotate by 45 degrees on x axis, translate along the y axis by 5 units, scale by 3 units on all axes. You can create the individual matrices for each of those operations and then compose them into a single transform matrix that you can multiply against a set of vectors to apply that change to e.g. a mesh of points represented by those vectors. The order sensitivity to the transformations is mirrored in the order sensitivity of matrix multiplication (because A*B != B*A with matrix multiplication -- i.e. not commutative). For an object relative rotation, as an example, you typically see a translation from worldspace to objectspace coordinates (subtracting the object position in the world out, so it's centered at the origin), a rotation (or scale) relative to the center of the object at the new origin, and a reverse translation to bring the rotated/scaled points back into worldspace coordinates. Rotating prior to the initial recentering transform, as an example, would mean the rotation would be pivoted around the world origin coordinate instead of around the center of the object.

    If you want to know more about how this stuff works, you should learn linear algebra.
  • Interesting. In almost all situations I can think of, you'll want to use the version with w=1 -- I'm not actually sure when you would ever want to use w=0.
    Well, according to T2 scripts, handling projectile spread uses w=0 (ie. MatrixMulVector). However, in that scenario the matrix itself is not a transform, but instead a rotation matrix (created via MatrixCreateFromEuler). And the vector is actually a direction, not a position. Which now makes a ton of sense now that I have typed it. It is rotating direction, and disregarding the location in space (since it's 0 anyway).
    If you want to know more about how this stuff works, you should learn linear algebra.
    I got a "B" in that class. Which was enough to be able to follow along with everything that you said.
Sign In or Register to comment.