Creating bones in code

Blitz3D Forums/Blitz3D Programming/Creating bones in code

Yasha(Posted 2009) [#1]
*** EDIT: Success! See below ***


Before anyone says it, YES, I am fully aware that there is no command for this in Blitz3D.

However, I've been having some fun recently poking around (heh) with the structures of various objects in Blitz3D. Thanks to Billp and MixailV (this and this) I've been able to find a few useful (for my purposes, anyway) speed enhancements, by combining this information with the ability to peek and poke directly to memory pointers with a DLL (both of their DLLs allow this).

One idea that amuses me is to pack all my media into archives. Very original. Now the standard way to do this with B3D files is to extract a temporary file and then load it with LoadAnimMesh. This is all very good and practical, but because I am incredibly stubborn I am still wondering if I can use the aforementioned peeking and poking commands to create an animated B3D in code, out of a bank (having read that from an archive, or being me, read it from a B3D file and doing this bit for kicks). The diagrams supplied by MixailV make it pretty clear where the bone weights are stored, but I haven't worked out how to actually make this work. So far, I have tried this:

box=CreateCube()
PositionEntity box,0,15,0
ScaleMesh box,7,7,7

bone1=CreatePivot(box):PositionEntity bone1,0,7,0

s=GetSurface(box,1)

vertexptr=MemoryFastPeekInt(s+28)  
For ver=0 To 3
	v=vertexptr+64*ver
	
	MemoryFastPokeByte(v+44,1)  ;Bone number?
	MemoryFastPokeFloat(v+48,1)  ;Weight?
	
	MemoryFastPokeInt(box+$2C,1)  ;On the offchance this might do anything
Next


Moving the pivot has no effect. Does anyone know if bones are some kind of special entity class that can't easily be created from code? I always thought they were just pivots. And does anyone know what the one-byte number for bone ID actually represents and how to get it? I thought it would be the child index but this didn't seem to work. I thought the value at entity+$2C might be some kind of update flag like surface+64 apparently is, but this also didn't help.

I didn't see anything in MixailV's table of the mesh/entity structure that indicated Blitz3D stores a distinction between entities created with CreateMesh and LoadAnimMesh, although there's still a lot of white space on that table. On the Vertex structure table he does point out that vertex+48 is either the first bone weight or, "for normal vertices", the parent surface - again, does this mean vertices and surfaces loaded as part of an animated mesh are somehow different from those created using Blitz3D commands, and that there is possibly no way to convert one to the other?

Sorry to ramble, or if I've missed something obvious. It's getting late here.... heh. Thanks for your attention!


Ross C(Posted 2009) [#2]
They aren't just pivots, as they transform the location of vertices, and depending on the weight of the vertices attached, the bone could affect the movement of some vertices more than others.

I believe there is code actually built into blitz to handle bones, as these are calculated, transformed on the CPU, rather than the GPU. To create a bone, you would need to attach vertices to it, before you would see any movement.


Warner(Posted 2009) [#3]
Maybe it is an idea to look at the b3d file code in the archives, as the structure of b3d might be pretty close to the structure of entities in memory.


Beaker(Posted 2009) [#4]
You might have more luck examining the open source version of the blitz3d sdk.


Yasha(Posted 2009) [#5]
....wait, what?

I thought B3D SDK was payable. Do you mean miniB3D? Because that's different internally, having been written in BlitzMax for OpenGL (already looked there!). I know the SDK was opened to users, but I haven't bought it - is there some limited version available to the rest of us? If so, thanks for the brilliant idea.


Ross C(Posted 2009) [#6]
Pacemaker creates bones, as it a blitz boned animation system. It does however either use software to transform the bones (I doubt this), or quickly writes out a blitz3d file and reloads it. It all seems very fast to me...


Yasha(Posted 2009) [#7]
I'm 99% sure Pacemaker just does the transformations in code, based on the fact that it's possible to animate a character out of its own cullbox, and that a careful search of the system turned up no deleted temporary files - it's not fast, but consider that Pacemaker doesn't have to render a scene or more than one character.

Anyway I gave up in desperation and emailed BRL, who have kindly supplied the necessary information, so... watch this space.


Yasha(Posted 2009) [#8]
Update: after some more fiddling around and wishing I understood more than I actually do, I have determined that this is definitely possible. Haven't got it working properly yet though - more updates when (if) I get it right (I have managed to add bones to static meshes, but the positions are all wrong for some reason).


_PJ_(Posted 2009) [#9]
This is really interesting to me.

I am intending to use a similar approach for the purposes of a 'creature creator', in which prefab body parts can be stuck onto others to create more diverse creatures.

As I suck completely with any 3D modellig apps, these will all be built from B3D primitives and for animating them, each body part type will have identical animations, which I hope to make work using pivots between the joints and rotating them individually.

A heavy task, but I do think it's possible as Yasha says.





I'l try and let you know how I get on with it if it helps. As for the positions being wrong, could it be a local / global issue?


Yasha(Posted 2009) [#10]
It's something like a local/global issue, but I haven't figured out why. Basically the deformed vertex positions are offset a second time - say in the simplest case, you have a cube and the only bone is the cube's root itself. If you position the cube at 10,10,10, normally you would expect the verts to be surrounding that point (9,9,9; 11,11,11 etc.). However, at the moment, the root pivot's offset seems to be being applied to the vertices a second time, so the cube ends up being rendered at 20,20,20. Other than this it works - taking this into account, the offsets for child bones are generally correct - so if the top half of the cube is attached to "bone1" and this is hovering gently at local position 0,1,0 the cube will still be cube-shaped, not brutally skewed - but it will be twice as far away as you want it to be!

There are of course a couple of obvious solutions - position the objects at 50% of where you want them, don't make the bones children, etc - but this isn't how it's done by the LoadAnimMesh models so I really don't want to make things messier than they already are (not to mention, on point of principle you shouldn't patch a problem you don't understand until you do).

Even if this is resolvable, there's another point to consider, which is that while bones as it happens are just pivots (they can even be meshes if you want), the bone transforms list and animator objects list are created by the LoadAnimMesh command - they don't exist for static meshes. This is easy enough to get around by creating a bank and redirecting the mesh to look for the information in the bank data (having Poked it into the bank) but it does mean that memory leaks will occur if things aren't freed carefully - and it may be unstable as this isn't how the system was meant to work (resizing a bank after adding it as a list would completely break it).

I'll tidy up my experiments and post them shortly, but they won't make much sense unless you have either access to the B3D source or a very good instinct for guessing memory structures (hint: MikhailV's tables are only about 90% correct).

I strongly recommend that if you need this functionality for anything other than purely academic interest or fun (my motivation) you should use miniB3D, which being written in the same language as the program using it, is easy to mod this way.

(EDIT2: removed this codebox so nobody gets the wrong code by mistake)


Yasha(Posted 2009) [#11]
.....boy do I feel stupid. Two days wondering why the cube was rendering in the wrong place due to a one character typo.

OK, problem solved! Cast your eyes to the codebox one post up and you will see that I was saying "MemoryFastPokeInt(box+240,1)" - which should have been "MemoryFastPokeInt(box+$240,1)", as I have been using hex values for most of that section. This sets the object's render space to Global or Local and, due to the typo giving a decimal instead of hex value, was not being set correctly. The mesh now renders in the right place, as follows (As I said before, YOU WILL NEED a userlib to let you peek and poke directly to memory addresses. You can get MikhailV's FastPointer, which I used, here) :



And there you have it: how to create bones in code. I will attempt to wrap this up into something a little tidier later - also, I haven't actually tested whether this will work with animations yet. I can't see any reason why it wouldn't as long as everything is set up correctly, though (the order of doing things will be important) - really the only difference between this and a LoadAnimMesh entity is that this method requires two banks to be created alongside the main entity.


Yasha(Posted 2009) [#12]
OK, a tidier example that you can use relatively easily (assuming you have the userlib specified above, or an alternative).



Remember to free boned entities with FreeBoneEnt and not FreeEntity, as the latter will cause a memory leak. If you want to load meshes out of a bank, there are more efficient ways of doing this (start by sizing the bank correctly from the outset!) although how precisely will depend on the format of the data in the bank.

I hope this all works, and if it does - have fun!


puki(Posted 2009) [#13]
Good stuff; however, it is old news.

:)


In fairness, "halo" cracked this 5-6 years ago when "Vertex" made some breakthroughs with some probing via kernel32.dll


EDIT:
In fact, "halo" was manipulating (poking) the vertices in code. It was "Vertex" who found the bone index (28th November 2003); thereafter, him and "halo" explored further.


Ross C(Posted 2009) [#14]
I've never heard of this being done in code ever. Well done Yasha. This is incredibly useful!


MikhailV(Posted 2009) [#15]
@Yasha: It's cool! Thanks!


puki(Posted 2009) [#16]
I don't think "halo" or "Vertex" actually animated them via code - it was more the fact that it had become possible if you wanted to do so. It was more of a journey into the inner workings of Blitz3D than a journey into bones as such.

I think that "Grumpy" made a lot of progress into this sort of thing, but never released his animation system.


_PJ_(Posted 2009) [#17]
I'm glad you solved it, Yasha... Unfortunately where you were using the peek/poke which I'm sure is nicer, faster and tidier, it was hard for me to follow so I got a little lost with what was happening when I looked it over.

As for the animations, again, something I will be hopefully looking at and done again in code as per this old thread:

http://www.blitzbasic.com/Community/posts.php?topic=83096

I will still let you know how I get on, but I think I shall certainly make use of your bones :)


Warner(Posted 2009) [#18]
Nice work, Yasha. Maybe you can submit it to the code archive?


GrumpyOldMan(Posted 2009) [#19]
Hi

Puki

I don't think "halo" or "Vertex" actually animated them via code - it was more the fact that it had become possible if you wanted to do so. It was more of a journey into the inner workings of Blitz3D than a journey into bones as such.

I think that "Grumpy" made a lot of progress into this sort of thing, but never released his animation system.



I did release the code, I think the download links are broken but at Here and Here are code examples. I'll have a look and see if I can find anything remaining of that work

Cheers

GrumpyOldMan


Yasha(Posted 2009) [#20]
@GrumpyOldMan,

Would you be able to provide a simple prose explanation of what's actually going on in your animation system? Is it really faster than native B3D bone animation (I spy a VertexCoords, that's a slow command...)? I think I get what you're doing but am not sure... also, not having a .b3x file to test it with makes it a little difficult.

I saw it a couple of months ago but couldn't make head or tail of it then either... which is actually why I first made a vertex animation system and then this little adventure into "real" bones.

@Warner - done.


GrumpyOldMan(Posted 2009) [#21]
Hi Yasha

I've reuploaded the demo at Demo in case any body wants to have a look.

The figures, within the single surface mesh, are stored as local vertex positions ie relative to their bone (haven't modified it yet for multiple bones) and there is one reference skeleton loaded that will provide matrix information, and one animation loaded to move the skeleton (for the purposes of the demo I left it at one but you could load any number of animations for the reference skeleton). For each instance of the figure the skeleton is set at the appropriate point of that animation and the matrix information is extracted for the bones of the skeleton and applied to the vertices. Move on to the next figure, set, extract, apply, etc. So the basis of the system is that there is one reference skeleton only, that provides matrix information to move the vertices for many 'figures' that seem to be controlled by their own individual bones. I'm not sure how it rates in a straight shoot out between a single native b3d animation and this system for a single 'figure' but I'm predicting this system's slower :0), but in a shoot out between 100 b3d animations and this system.....

Drawbacks are that you need a lot of control and direction ie you need transition anims like stand_to_walk, walk _to_stand, etc.

Cheers

GrumpyOldMan


Yasha(Posted 2009) [#22]
...so that's how people use single surfaces for multiple characters. A single reference bone... brilliant idea. The high surface count was the last obstacle to creating a usable vertex-animation system (got past the slowness of VertexCoords by doing that part in a DLL, more direct accessing nonsense).

Now.... combining this with "pure" vertex animation, and the ability to add and drop characters (and their reference bones) at will thanks to developments higher up in the thread... and it may actually be possible to equal the speed of MD2s with mesh quality that doesn't suck...

Thank you very much for sharing that!