Another way of thinking about this stuff is that the concatenated matrix (from now on we call it the object matrix, k?) is a way for us to "move from world space to object space"...
Once we've applied our objectmatrix as the current world xform, we have effectively entered object space - everything we do now is totally relative to the position/orientation/scale of the object, instead of the world origin. For example if we have entered object space, and we then tried to draw another object, its position and rotation would be relative to the first one.
To get back to world space, we could either restore the matrices we stored prior to rending each object, or just apply an Identity matrix as the current world xform, which has the effect of resetting it.
We could consider that the first object is Parent to the second object, because if we now move the first object around in the world, the second one will move with it (since its relative).
Likewise, we could consider the the second object is a Child of the first object.
We could say that the Child has a different Frame Of Reference to the Parent, that the Child's Origin depends on the Parent's Origin, etc.
I may be getting a little ahead, but it makes good brainfood.
When you start to read about Frames later, this is what they are talking about, not animation cell frames, but rather frames of reference, and relative objects (relative position, relative rotation etc - it's all just a matter of nesting the call to render the object, nothing hard to code)
Posted on 2004-09-21 01:56:15 by Homer
Afternoon, gallo.

Check out the following thread:
http://www.asmcommunity.net/board/viewtopic.php?t=16454

Every object in the world has its own "World" matrix. The "World" matrix is the matrix telling DX where the centre of the <about-to-be-rendered> object is *in* the world. It *isn't* the world's matrix. :shock: :-D

This means you *don't* have to save/restore it every time you want to render something.
You just have to remember that each object *must* have it's own World matrix which is set just before rendering that object.

When it comes to the Camera matrix (the View matrix), you can pretty much treat it like any other object, except there's an extra step when setting up the matrices.

I don't bother with quarternions, as there ends up being about the same number of calculations/ code involved as with using the vector/matrix calculations.

Cheers,
Scronty
Posted on 2004-09-22 21:50:23 by Scronty
I don't bother with quarternions, as there ends up being about the same number of calculations/ code involved as with using the vector/matrix calculations.


in fact is all math nothing more than just some very basic operations. but, quaternions are an explanation of what you are actually doing. and they are the solution to rotate around an arbitrary axis, which is a must if you write something more than an average first person shooter.
Posted on 2004-09-23 12:24:06 by lifewire
It's possible to define matrices to rotate about arb axes also - and rather hard to use quats to do anything EXCEPT rotate - however, quats can be faster (as I've said before), and they are inherently better at coping with something called Gimbal Lock - they don't suffer from it.
Posted on 2004-09-24 02:28:07 by Homer
hello and sorry for being absent but in school we had a sort of tests :-D ,

thanks to EvilHomer2k and to Scronty for your help :alright: ,
but something wierd happened, i did a little drawing to make my problem a little clearer, imagine that this object is been seen from the right side:
(i think the image should appear below)
well as you can see in the image, what is happening is that after the object has been rotated, it just moves forward and not to the object's direction how i thought it'd be if i use matrices....so what is happening is correct or it should be how i wanted and i'm doing something wrong....

and something more, Scronty i downloaded your "fly" proggy and it's very very impressive, if you saw the picture i post, i'll notice that what i need it's basically what the red-buggy does...so may be you can please help me :oops:

thanks
Posted on 2004-09-24 19:01:13 by gallo
Afternoon, gallo.

It all depends upon which method you're using for the movement and rotation of the object.

Is it possible to upload the proggy plus sourcecode of what you've got so far so I can take a look at it?

Cheers,
Scronty
Posted on 2004-09-25 08:12:08 by Scronty
hello Scronty,
here is my little program and its code; as i said before, the problem is that after rotating the object if i move it, the DX puts the object in its new position in the world and not in the object's position relative to its direction

so i hope you can help me :alright:

thanks
Posted on 2004-09-25 19:10:56 by gallo
Good afternoon.

Here's some stuff that may help you - or not :tongue:

First, a structure to define an instance of a mesh object.
We load the mesh once, then we create some kind of array
of instances of the object, with their unique data kept inside (stuff like position, orientation kept per instance of the object).

NB: CAVEATS concerning the following code, the pMesh member of object instances is a copy of the pMesh we got when we loaded the mesh - all Instances of a mesh use the same pMesh value, so we should not unload the mesh until the reference count (#instances) reaches zero :)
This "object" structure is merely a way of keeping instance-specific data together, and is just something I made up - invent your own :)



LPOBJECT typedef ptr Object
Object STRUCT
ObjectType DWORD ? ;We just might wanna know this if we have more than 1 kind
pMesh DWORD ? ;Pointer to this object's Mesh
vLocation D3DVECTOR <> ;where in 3D space this object is currently located
fYaw FLOAT ? ;Three angles = the 3D rotation (orientation) of the object
fPitch FLOAT ?
fRoll FLOAT ?
matLocal D3DMATRIX <> ;will be used to manipulate the object according to the above info
Object ENDS


Now a couple of helper procs that operate on object instances:



;--------------------------------------------------------------------------------------------------------------------------------------------------
;This procedure calculates a per-object "world transformation matrix"
;useful for Orientation and Positioning of a 3d object in "world space",
;from data stored in a per-object data structure, where it also stores the resulting matrix.
;Rotation of objects is around their own origin (around origin of model space).
;Position of objects is in world space.
;--------------------------------------------------------------------------------------------------------------------------------------------------
CalculateObjectMatrix PROC pObject:DWORD
local matTemp, matRotateX, matRotateY, matRotateZ :D3DMATRIX
push edi
mov edi,pObject
assume edi:LPOBJECT
;The following function shifts the world by MINUS the object origin
;You could also say we are moving our imaginary 3d pen to the object location
invoke D3DUtil_SetTranslateMatrix, addr matWorld, addr [edi].vLocation

invoke D3DUtil_SetRotateYMatrix, addr matRotateY, addr [edi].fYaw
invoke D3DUtil_SetRotateXMatrix, addr matRotateX, addr [edi].fPitch
invoke D3DUtil_SetRotateZMatrix, addr matRotateZ, addr [edi].fRoll
invoke D3DXMatrixMultiply, addr matTemp, addr matRotateX, addr matRotateY ;(X x Y --> T)
invoke D3DXMatrixMultiply, addr matTemp, addr matRotateZ, addr matTemp ;(Z x T --> T)
invoke D3DXMatrixMultiply, addr matWorld, addr matTemp, addr matWorld ;(T x W --> W)
invoke RtlMoveMemory,addr [edi].matLocal , addr matWorld,sizeof D3DMATRIX
pop edi
ret
CalculateObjectMatrix ENDP





;This procedure is used to perform the following steps:
;1- Stash the current World Transform Matrix
;2- Switch to the OBJECT Local Transform Matrix
;3- Draw the Object
;4- Return the World Transform Matrix to its previous state

DrawObjectInPosition PROC pObject:LPOBJECT
local matStash:D3DXMATRIX
mov edi,pObject
mcall [lpd3dDevice],IDirect3DDevice8_GetTransform, 256, addr matStash
mcall [lpd3dDevice],IDirect3DDevice8_SetTransform, 256, addr [edi].matLocal
_saferender [edi].pMesh
mcall [lpd3dDevice],IDirect3DDevice8_SetTransform, 256, addr matStash
ret
DrawObjectInPosition ENDP


I have not given code to load or render the actual mesh - I'll leave it to you since I assume you can already do that :)

What we can do now is call the function to calculate object instance matrices once when an object instance is initialized, and once whenever the objectinstance's values (pos, rot etc) are changed.

We can call render on the instances at any time after they have been initialized - and can do so in a loop, looking for a flag that states the instance "IsReadyToRender" ..
Posted on 2004-09-25 23:32:48 by Homer
The above posting may seem redundant to some people at first, especially the getting and setting of the world transform in the render-in-frame-of-reference procedure.
I agree, there should be a parameter in that procedure that points to a "parent matrix", which normally is an identity matrix, but could also be an object's matrix in which case subsequent rending would be relative to that object.
With that in mind, it's pretty potent stuff :)
Posted on 2004-09-25 23:55:24 by Homer
You can also translate the object in world space, and then rotate it around the world origin to achieve the result you seek, but the solution I have offered will work for every case.
Posted on 2004-09-26 06:39:27 by Homer
hello EvilHomer2k,
first thank you for those class instance methods, i think they are gonna be very useful.
Now if you downloaded my little test program you'll notice that what i do to rotate and to move the object is more or less the same as you, even though, it still doesn't work how i showed in the picture (rember?): the object doesn't move the its direction, so i still don't know how to do it.....would some one please help me??

thanks
Posted on 2004-09-26 18:39:53 by gallo
Afternoon, gallo.

You've still got a wee bit of code missing:

1) There's no timing code. You need to be able to know how much time has passed between renders for doing any animation (movement/rotation).

2) There's no control code. You need to be able to control the object (move forward/backward/rotate) with keyboard and/or mouse.

Cheers,
Scronty
Posted on 2004-09-27 20:57:28 by Scronty
hello Scronty,
i took in count your advices (thanks!) and this is my new test program:
(to control the object use the numpad (with num-lock) numbers: 8=down and 2=up (rotate x axis); 4=left and 6=right (rotate z axis); 0=left and <return>=right (rotate y axis))
.....so what do you think? :oops:

thanks
Posted on 2004-09-30 17:19:41 by gallo

We could consider that the first object is Parent to the second object, because if we now move the first object around in the world, the second one will move with it (since its relative).
Likewise, we could consider the the second object is a Child of the first object.
We could say that the Child has a different Frame Of Reference to the Parent, that the Child's Origin depends on the Parent's Origin, etc.
I may be getting a little ahead, but it makes good brainfood.
When you start to read about Frames later, this is what they are talking about, not animation cell frames, but rather frames of reference, and relative objects (relative position, relative rotation etc - it's all just a matter of nesting the call to render the object, nothing hard to code)

had been interesting to see a example of frames of reference, etc in ATC

just interesting as I am doing all stuff right now by myself but yet has only object transform/rotate, not World rotate
Posted on 2004-10-05 14:46:21 by daydreamer
Yep, all this stuff I coded under ATC some time ago (see the TerrainDemo), was very educational, learning about dealing with polygonal objects, a segmented World and its data structure(s), etc.

One of the major support classes that myself and Ultrano wrote and which deserves to be reviewed is the one used to create node hierarchies - a small base class from which we derive various classes for the various kinds of nodes we want to handle.

We are talking about Frame Nodes.
NOT FRAME OF REFERENCE, NOT ANIMATIONFRAME
Microsoft like talking about 'Frames', so I'll refer to them as Frames from now on. Damn you to hell m$ for confusing everyone. Note there's several kinds of Frames for holding different kinds of content - each is similar, and all have a handful of fields in common, so we can certainly afford to wrap all the common stuff in a light base class as stated earlier.

What are these common fields so we can define our base class?
We'd need at least the following:

-pParent = pointer to Parent frame ("up" the tree)
-pChild = pointer to Child frame ("down" the tree)
-pNextSibling = pointer to Younger Brother frame ("right" in tree)
-pPrevSibling = pointer to Older Brother frame ("left" in tree)

It's normal to NAME frames with a string, so we should also have
-pName = pointer to NameString
Finally, since we'll probably keep mixed node types in a single tree, all nodes should have a NodeType identifying field
-dwNodeType = What kind of Node this is (we'll use this later)

So, armed with these 6 fields, we can go ahead and define a BaseClass from which all Frame Nodes will be derived.

It's common to use the value NULL (zero) to mean illegal pointer,
so an object with no Parent will have pParent=NULL.

Under ATC, we're not meant to need to zero out fields in new object instances (in constructor), but my experience tells me that we do - I assume sometimes the HeapAlloc call doesn't correctly zero newly-allocated memory, possibly this is an artifact of my modified xp os.

Now let's talk about what kind of Methods we'll want in our baseclass.
We want to be able to link and unlink objects from their parents and siblings. We'll need to handle insertions (patching links) and the opposite (unpatching links to remove an object without deleting it) ie linking and unlinking objects in a tree-wise fashion.
That's about all we need.

You may have noticed that we are defining a bidirectional 2-dimensional linked list here, a useful support class in your arsenal, good for all kinds of things besides FrameNode hierarchy.

Go ahead and try to write the Node Hierarchy Base Class.
I'd like to see what you come up with :)

Once this is written, we simply inherit it in our Node classes.
Posted on 2004-10-06 01:38:47 by Homer
The type of hierarchy formed using this baseclass is called a Directed Acyclic Graph (aka DAG).

It has one root node.
Each node can have N children.
Note that only the FIRST CHILD of a Parent Node is recorded as a Child of that Parent, since any others are Younger Siblings of the First Child.
That means a group of Siblings all know who their Parent is, but a Parent only knows the FIRST of its children. That's important. Now we know that Siblings are just a way of keeping a group of "subitems" together.

We can use this hierarchy to define a SCENE GRAPH !!!
It's more than just a system of storing the scene data - we can define Nodes which DO STUFF instead of just containing something.
Furthermore, any changes made by nodes that do stuff (called Action Nodes) are propagated down the tree, and thus affect any subsequent Nodes.

Imagine we have a "rotation node", with a child "geometry node".
The rotation will be applied to the geometry, and anything "below" it in the tree hierarchy.

We can define Skeletons for animating Skinned Mesh creatures using this kind of hierarchy - and more !!

We can write MOST OF THE LOGIC OF A GAME into a SceneGraph, including triggered and timed events and their response actions.

I hope you see some of the possibilities of this stuff, and appreciate that SceneGraph (in all its forms) is already in common use to the point where it's becoming a defacto standard.

The "game engine" then boils down to a scenegraph loader, and some code to "walk" the scenegraph (applying action nodes, collecting the "renderables" into a by-texture array of "stuff to draw", marking Nodes for deletion where applicable).
Posted on 2004-10-06 03:10:56 by Homer
Hey EvilHomer2k, why don't you write a tutorial? :) if you copy all your posts in this thread together you'll have one :)

What is the next step? BSP-trees or Quad/Oct-trees for frustum culling?
Posted on 2004-10-06 10:56:06 by lifewire
If you have specific requests for one or more tutorials, I'd be happy to take them into consideration. I'm not about to write tutorials which won't be read and appreciated.

Where to from here? Octree :) Why?

We have been discussing the merits of hierarchical databases.
One method of wholesale culling which is gaining popularity right now is to create a hierarchy of Bounding Volumes (generally Boxes, but not always). The reason? If a Bounding Volume is totally outside the Viewing Frustum, then it is not at all visible - and neither are its children ... we can disregard the bounding volume AND ANYTHING WITHIN IT.

The name given to this kind of system is Octree Space Partitioning 2.
Don't ask me why, I have no idea why it wasn't given a name which distinguishes it more easily from regular OSP.

Regardless, it's a great culling method because it is cheap to implement, and the savings in cpu cycles compared to non hierarchical BB testing is obviously very large.

Unfortunately, it is not efficient to implement unless you already have a hierarchical DB, so we have yet another reason to want one.

Last night, I revised my TreeNode class.
I went on to write a SwitchNode class that is derived from it.
I'll post it a little later, I'm currently not on my workhorse.

Have a nice day :)
Posted on 2004-10-07 00:20:44 by Homer
Just wanted to qualify my last post a little more .. BSP is redundant due to its simplicity.. its a system used to divide the world into ever-smaller "half-spaces", where a half-space contains geometric data, either in the leaves of the tree ("leafy bsp") or spread throughout its nodes ("nodey bsp").
One problem with that is that we end up with a lot of EMPTY HALFSPACES being mapped into the tree - nodes that don't contain anything.

Hierarchical BoundingVolumes are a better choice, because the geometry nodes will ALWAYS contain some geometry, and will NEVER be empty - we will never map an empty volume of space.

It's inherently more suitable for a world that is mostly empty space, with objects and terrain occupying anything under 50% of the universe.

Furthermore, it's pretty easy to move stuff around in an OSP2 world, blow holes in geometry, etc, all the stuff that basically can't be done in a BSP.

A BSP IS ONLY USEFUL FOR MAPPING STATIC WORLDS.
Posted on 2004-10-07 00:32:30 by Homer
I should also add that BSP requires preprocessing of the map.
Depending on the quality of the algo used, it can be very slow.
Processing times of 10 to 12 hours for a single map are not unusual.
Want to modify the world? Now you have to reprocess it (grrr).

OSP on the other hand: much faster, in fact, no need to preprocess, can generate at runtime in a couple of seconds.

If I remember correctly, BSP was first written up in 1968, and I feel that it is beginning to show signs of old age.
Posted on 2004-10-07 00:41:05 by Homer