some addons for blitz3d

Blitz3D Forums/Blitz3D Programming/some addons for blitz3d

Bobysait(Posted 2015) [#1]
Just for purpose, I rebuild the sources of blitz3d to add support for some missing getters (actually, I don't really know why thoose funcions were not on the "official" release, but whatever ... let's assume it wasn't mandatory)

Download modified sources only (in 7Z format) (compressed with 7zip -> 42 Ko)

Download vB.003 in 7Z format (compressed with 7zip -> 775 Ko)

Download vB.003 in Zip format (if you can't decompress 7z files, here is the zip -> 1.062 Mo)




how to instal :
1/ go to your blitz3d installation
2/ rename blitz3d.exe as blitz3d.back.exe
3/ rename the bin directory to bin.back
4/ rename the cfg directory to cfg.back (I modified the "theme" with my own color theme, which is more contrasted and ... IMO more attractive, but, it's not required to run this version of blitz3d, it's just a theme)
5/ Decompress the archive in your blitz3d folder
6/ run blitz3d as you did before.






GetBrush[]
-> GetBrushBlend%(brush)
-> GetBrushRed#(brush)
-> GetBrushGreen#(brush)
-> GetBrushBlue#(brush)
-> GetBrushAlpha#(brush)
-> GetBrushShininess#(brush)
-> GetBrushFx%(brush)


GetVertex[]
-> CountVertexBones%(surface, index); returns the bone count set on the specified vertex
-> VertexBone%(surface, index, boneIndex); (boneindex in the range 0 to 3) -> returns the bone Identifier from the surface bones list
(this is not really usefull as long as there is no function that require this bone index ATM)
-> VertexWeight#(surface, index, boneIndex); // // -> returns the rate the bone affect this vertex
// Thoose 3 functions below check is the entity has bones. If not, it returns the coordinates of the vertex in world space.
// Else, it returns the vertex coords multiply by the bones transforms.
// As long as the internal function is a bit maths intensive, it's not the fastest function in the world, but it should be faster than anything you might want to code in Blitz3D to get the same result. So, for what it is, it is IMHO the fastest function to get animated vertex coords. (but you can fill it's not ... then leave a comment, I'll be glad to discuss about that)
-> VertexRiggedX#(mesh, surface, vertexIndex); returns the real coordinates of the vertex (support animation) /!\ returned coordinates are "world" coordinates.
-> VertexRiggedY#(mesh, surface, vertexIndex);
-> VertexRiggedZ#(mesh, surface, vertexIndex);


Setting bones:
-> CreateBones(mesh); extract bones from current hierarchy of the specified mesh
you must create the hierarchy before using this function, else it won't do anything.
(see exemple below)
-> setBone(surface, index, vertex_boneindex, hierarchy_boneindex [, weight#, normalize_weights%=0])
set the bone and weight of a vertex.
vertex_boneindex can be in the range [0,3], each vertex can support up to 4 bones, but remember that all bones set on a vertex won't be used until all previous boneindex are used. (it means that if I set a bone for index 2 and nothing for 0 and 1, the vertex won't be affected by this bone)

Rendering:
-> RenderToTexture(texture [,frame=0] [,tween#=1.0])
render the world directly on the specified texture.
/!\ You need to use a texture created with CreateTexture with the flag 1024 to allow graphics to be drawn on the texture canvas !


And that's all for the moment.






a blitz function to show how to use the vertex rigged coordinates :
format_codebox('
; simple function to show a dot for each vertex of the mesh
; don't forget to use "UpdateWorld", else, there won't be "rigged animations".
Function PlotMeshVertices(camera, mesh)
Local is, nbs = CountSurfaces(mesh);
For is = 1 To nbs
Local surf = GetSurface(mesh, is);
Local nbv% = CountVertices(surf), v;
For v = 0 To nbv-1
CameraProject(camera, VertexRiggedX(mesh, surf, v), VertexRiggedY(mesh, surf, v), VertexRiggedZ(mesh, surf, v));
Plot ProjectedX(), ProjectedY(); Plot the projected "world" vertex
Next;
Next
End Function
')

; sample - rigg a mesh
format_codebox('
Graphics3D 1024,768,0,2
SetBuffer BackBuffer()

; camera
Local player = CreatePivot ( );
Local head = CreatePivot ( player );
Local camera = CreateCamera ( head )
MoveEntity ( camera , 0,0,-3.5 );
CameraRange ( camera , .1,100 );


; - light ---------------------------------------------------------
AmbientLight ( 010,015,020 );
AmbientLight ( 000,000,000 );
Local lightpiv1 = CreatePivot ( );
Local light1 = CreateLight ( 2, lightpiv1 );
LightRange ( light1, 10 );
PositionEntity ( light1, +10,+10,-10 );
LightColor ( light1, 255,050,000 );
Local light2 = CreateLight ( 2, lightpiv1 );
LightRange ( light2, 10 );
PositionEntity ( light2, +10,+10,+10 );
LightColor ( light2, 000,100,255 );
Local lightpiv2 = CreatePivot ( );
Local light3 = CreateLight ( 2, lightpiv2 );
LightRange ( light3, 15 );
PositionEntity ( light3, +00,-10,+00 );
LightColor ( light3, 050,200,050 );
Local light4 = CreateLight ( 2, lightpiv2 );
LightRange ( light4, 10 );
PositionEntity ( light4, -10,+00,+00 );
LightColor ( light4, 255,180,050 );


; a sphere to rigg
Local sphere = CreateSphere ( 64 );
ScaleMesh ( sphere , 1,2,1 );
EntityShininess ( sphere , 1 );

; create a bone hierarchy using blitz pivots (it also works with any entity ... light camera ... etc ...)
Const NBBONES% = 6;
Const stp# = Float(2)/NBBONES;
Local Bones%[NBBONES]
Bones[0] = CreatePivot ( sphere ) : PositionEntity Bones[0], 0,-1,0; first bone is at the bottom of the sphere
Local id%=1
For n# = -1+stp To 1 Step stp ; create bones everythin .25 units
Bones[id]= CreatePivot ( Bones[id-1] ) : PositionEntity Bones[id], 0,n,0
id = id + 1;
Next;
DebugLog (id-1)+" bones";

; build bones from the sphere hierarchy
CreateBones ( sphere );

; time to assign the bones to the vertices
Local surf = GetSurface(sphere,1); by default, blitz spheres have only one surface
For v = 0 To CountVertices(surf)-1
Local bonecoef# = 1 + Float(id-2) * (MeshHeight(sphere)/2.0 + VertexY(surf,v))/MeshHeight(sphere)
Local boneid1% = Floor (bonecoef);
Local boneid2% = Ceil (bonecoef);
Local w1# = 1.0-(bonecoef-boneid1);
Local w2# = 1.0-(boneid2-bonecoef);
; comment the next line for a linear interpolation (sharpen edges)
w1 = w1 * w1 : w2 = w2 * w2;
setBone (surf, v, 0, boneid1, w1, False );
setBone (surf, v, 1, boneid2, w2, True );
setBone (surf, v, 2, -1, 0);
Next;

; set frames
For frame# = 0 To 359
For i# = 0 To id-1
RotateEntity( bones[i], 0, 120 * Cos ( i *360/id + Float(frame) ), 0, 0 );
ScaleEntity ( bones[i], 1.0+.2*Cos(frame+360*Cos(i*360/id)), 1, 1.0+.2*Sin(frame+360*Cos(i*360/id)), True );
SetAnimKey ( bones[i], frame, False, True, True );
Next;
Next;

; we covered 360° using 360 frames. -> Register the animation
Local anim = AddAnimSeq ( sphere, 360 );

; play the animation.
Animate ( sphere, 1, .5, anim, 0 );

MouseXSpeed ( );
MouseYSpeed ( );

Local wire = False;

Repeat

If KeyHit(59) Then wire =Not(wire) : WireFrame wire;

For t = 1 To 4
TurnEntity lightpiv1,1,.5,.3
TurnEntity lightpiv2,-1,.5,-.3
Next

Local msx# = MouseXSpeed( );
Local msy# = MouseYSpeed( );

; rotate camera around the model
If MouseDown(2)
TurnEntity ( player , 0,-msx,0 );
TurnEntity ( head , +msy,0,0 );
EndIf;

; mandatory if you want to see animation !
UpdateWorld ( );
RenderWorld ( );


Text 10,10, TrisRendered();

Flip ( True );

Until KeyDown(1);

End;
')


Render To Texture sample
format_codebox('
Graphics3D 800,600,0,2
SetBuffer BackBuffer()


; - camera --------------------------------------------------------
Local player = CreatePivot ( );
Local head = CreatePivot ( player );
Local camera = CreateCamera ( head );
MoveEntity ( camera , 0,0,-4.5 );
CameraRange ( camera , .1,100 );
CameraClsColor ( camera , 20,40,80 );

; - light ---------------------------------------------------------
Local light = CreateLight ( 2 );
LightRange ( light, 15 );
PositionEntity ( light, 10,10,-10 );

; - small scene ---------------------------------------------------
Local scene = CreatePivot ( );
Local cube = CreateCube ( scene );
Local sphere = CreateSphere ( 8, scene );
FitMesh ( sphere, -.5,1.5,-.5,1,1,1 );

; - texture for rendering -----------------------------------------
Local rendertex = CreateTexture ( 800,600, 1+16+32+256+1024 );

; - a quad to render the texture on screen ------------------------
Local renderquad= CreateMesh ( camera );
Local surf = CreateSurface ( renderquad );
; setup the UVs to fit the real texture size on the camera viewport
Local dh# = Float(GraphicsHeight())/GraphicsWidth();
Local du0# = Float(0)/TextureWidth(rendertex);
Local du1# = Float(GraphicsWidth()+1)/TextureWidth(rendertex);
Local dv0# = Float(0)/TextureHeight(rendertex);
Local dv1# = Float(GraphicsHeight()+1)/TextureHeight(rendertex);
AddVertex ( surf, -1.0,+dh, 0, du0, dv0 );
AddVertex ( surf, +1.0,+dh, 0, du1, dv0 );
AddVertex ( surf, +1.0,-dh, 0, du1, dv1 );
AddVertex ( surf, -1.0,-dh, 0, du0, dv1 );
AddTriangle ( surf, 0,1,2 );
AddTriangle ( surf, 0,2,3 );

EntityFX ( renderquad, 1+8 );
PositionEntity ( renderquad, 0,0,1 ); offset the quad at z=1 from camera

EntityTexture renderquad, rendertex


; - small demo loop -----------------------------------------------

MouseXSpeed ( );
MouseYSpeed ( );

Local r2t% = True;
Local wire% = False;

Local rendermode$[2]
rendermode[0] = "RenderWorld"
rendermode[1] = "RenderToTexture"

Repeat

If KeyHit(60) Then wire = Not(wire):WireFrame wire;
If KeyHit(59) Then r2t=Not(r2t);

Local msx# = MouseXSpeed( );
Local msy# = MouseYSpeed( );

; rotate camera around the model (on right mouse down)
If MouseDown(2)
TurnEntity ( player , 0,-msx,0 );
TurnEntity ( head , +msy,0,0 );
EndIf;

; render to texture
If r2t

; show the real scene to render (not the quad !)
ShowEntity ( scene );
HideEntity ( renderquad );

; render to texture ^^
RenderToTexture ( rendertex );

; hide the scene and show the quad
HideEntity ( scene );
ShowEntity ( renderquad );

; finally render the textured quad on the screen
RenderWorld();

Else

; basic rendering using renderworld ...
ShowEntity ( scene );
HideEntity ( renderquad );
RenderWorld();

EndIf;

Color 255,255,000
Text 10,10, "Hit F1 to switch render mode"
Text 10,25, "Current render method : "
Color 000,255,255
Text 10+StringWidth("Current render method : "),25, rendermode[r2t]

Color 255,255,000
Text 10,40, "Wireframe (F2) : "+wire
Flip (True);

Until KeyDown(1);
End;
')


notes : the new commands are highlighted, but not documented.
I won't comment the function, no need to ask me to, I don't need documentation, and the function are self-explained enough.
If anyone feel the needs of a documentation, feel free to propose one, I'll add it to the archive.

If you see bugs, let just post a comment with a code involving the error.
If you need a specific function, idem : post a comment, I'll see if I can/want to add it a publish a new release.

Of course, this is released free and "As is" ( = without any warranty) :)
If your machine burn, then ... post a comment ^_^

I can provide the source of the modification on demand.
If anyone wants to see, I'll post a zip of the modification.






[EDIT - 2015.12.02 23h56]
+ update vB.002
- add function CreateBones(mesh[,animlength=0])
- add function SetBone (surface, vertex_index, vertexboneindex, bone_index [, weight=1.0][, normalize_weight=0] )
- add sample for skinning a sphere and animate it.

+ update vB.003
- add function RenderToTexture(texture [, frame=0, tween#=1] )


RemiD(Posted 2015) [#2]
CountVertexBones%(surface, index)
VertexBone%(surface, index, boneIndex)
VertexWeight#(surface, index, boneIndex)
could be useful to analyze the joints ("bones") of a skeleton and the influences of some joints over some vertices, this may allow us to create a rigged skinned mesh with several parts in code... thanks ! :)

Now what is missing are functions to create joints ("bones") (some joints being childs of others joints), set influences ("weights") of some joints over some vertices... And have these joints compatible with the existing functions to create poses and to create animations with the poses... (SetAnimKey(), AddAnimSeq(), ExtractAnimSeq()) and with the existing functions to animate the joints (Animate())

But i would understand if you don't have time for this. Maybe later.

(i thought that you were not using Blitz3d anymore ?)


Bobysait(Posted 2015) [#3]
I currently have already add the setBone function and I'm adding the addBone function to manually rigg models.
Just need some test before commiting the v1.002

Then, the next stuff could be a b3d export function (that fully support animation and bones) ...
But, I'm not sure to be brave enough this week (this month?) for this one ^_^

ps : I don't use Blitz3D at all, my blitzmax engine is so similar in syntax with blitz3d that there is nothing I can do with blitz3d I can't do with my engine, easier, faster and with shader support... and BTW, my engine already support natively the bone manipulation and have a b3d export function. All I do here, is almost just peek some of my engin code and translate it to the blitz3d sources. It's also the reason why it's easy enough for me to take a bit of time to update the sources.

But you know, I've been working on blitz3d for so many times that it's kind of my contribution, and since many people could really use thoose functions (that are really missing to enable user to manipulate bones) and since it could pass a long time before anyone publish an update, I can do it, so I do it :)

Simple as that.


RemiD(Posted 2015) [#4]

I've been working on blitz3d for so many times that it's kind of my contribution, and since many people could really use thoose functions, and since it could pass a long time before anyone publish an update, I can do it, so I do it


And i am sure the blitz3d users will appreciate it :)

I also try to contribute when i can (at my level...) because i have been helped by others in the past (including by you).

(it seems that you are the last one standing from the ancient blitz3d forum ? Some of the others have moved to unity3d as i have seen...)
https://www.youtube.com/watch?v=LiCFfDToc6Q :P


Stevie G(Posted 2015) [#5]
Excellent Bobsait.

I appreciate that this is probably never going to happen but I'd love to see a fast Render To Texture function in native Blitz3d. Copyrect is dog slow.


Bobysait(Posted 2015) [#6]
Update vB.002
the Links on the first post are updated. (I won't leave previous version, links will be replaced for each update)

@Stevie G:
It's a good thing to add. But (there always is a "but")
I'm not very familiar with dx7, I'm more an OpenGL user.
I'll try to find some doc covering the topic, but, for the moment, I have to say : I can't do that.
For the moment, I can modify the c++ sources related to hierarchy, getters, setters, and some maths, but not the graphics function.


RemiD(Posted 2015) [#7]
Thanks ! I will do some tests in the day.


Bobysait(Posted 2015) [#8]
update vB.003
-> RenterToTexture implemented.
Have fun ;)

For the next update, I'll add some more rendering functions
-> RenderEntity(entity,camera=0,recursive=true)
-> EntityToTexture(entity,texture,camera=0,recursive=true))
Because it makes the coe easier for multi-pass rendering
(else we have to deal with Hide/Show entity ... it's boring and unproductive)


RupeB(Posted 2015) [#9]
Just wanted to pop in to tell what a great effort I think this is ! Blitz3D just grew ^ 10 times. Amazing work!


RemiD(Posted 2015) [#10]
1/ go to your blitz3d installation ->ok
2/ rename blitz3d.exe as blitz3d.back.exe ->ok
3/ rename the bin directory to bin.back ->ok
4/ rename the cfg directory to cfg.back ->ok
5/ Decompress the archive in your blitz3d folder ->ok ("Blitz3D.exe" and "bin" and "cfg" and "versions.txt")
6/ run blitz3d as you did before ->ok

But i have an error "toolbar bitmap failed to load!"


RemiD(Posted 2015) [#11]
I suppose that i have to copy paste the images and font of the old "cfg" directory to the new "cfg" directory ?


Bobysait(Posted 2015) [#12]
I removed the bitmaps as long as they are distributed in the official package. I forgot to mention :)
Just get them from the "back" directory


Floyd(Posted 2015) [#13]
It might be easier to not modify your original Blitz3D. Copy the entire installation to a new directory and then replace the relevant files in that.

Just remember to run the one you really want to use. In the past I've had multiple versions of Blitz3D and BlitzMax installed. I would sometimes forget which one I was dealing with.


Stevie G(Posted 2015) [#14]
update vB.003
-> RenterToTexture implemented.
Have fun ;)

For the next update, I'll add some more rendering functions
-> RenderEntity(entity,camera=0,recursive=true)
-> EntityToTexture(entity,texture,camera=0,recursive=true))
Because it makes the coe easier for multi-pass rendering
(else we have to deal with Hide/Show entity ... it's boring and unproductive)



That was quick!! Impressive stuff.

I hope you don't mind me asking some questions ..

What does the 'rendertotexture' actually render here? Is it the same as renderworld(), but direct to the texturebuffer instead of the backbuffer? I assume that both buffers must be the same size?

Normally when I do a copyrect from the backbuffer, I have the main camera's hidden using cameraprojmode = 0. The size of the camera I want to render will normally be a power of 2 in size, 128x128 etc.. but smaller than the graphics width/height. Remember textures round up to the nearest power on each axis when created. I would then copy the result from the backbuffer() to a specific offset on the texture buffer (again a power of 2 in size), assuming the texture is larger than the camera rendering the scene.

I'm probably being selfish but it would be handy, and more versatile, if you could specify almost the same paramaters as copyrect:

CopyRect src_x,src_y,src_width,src_height,dest_x,dest_y,[src_buffer],[dest_buffer]


Which would translate to ...

RenderToTexture src_x,src_y,src_width,src_height,dest_x,dest_y, texture,[Frame], [Tween#]


I appreciate that this would be alot more work but it's maybe something to consider in the future?


Rick Nasher(Posted 2015) [#15]
Again: wauw!


Bobysait(Posted 2015) [#16]
About RenderToTexture :
What it does -> internally : it sets the rendertarget to the texture then call renderworld and get back to the previous buffer
So, the scene is not shown on the screen but directly writen to the texture (it's as fast as a renderworld can be)
it copies the screen from the top-left corner regardless to any setup of your viewport "until texture.size" (of course it can't write outside the texture ^^, but it won't generate errors, it will just sort of skip the pixels that can't be rendered ... but you know, it's logical enough to not enter the details)

BTW, The texture can be larger or smaller than the viewport, it's up to you to setup the size of your texture, then you can render smaller resolution of your scene ... for blur effect or else (fake AA ?).


But ! there is a but (there is ALWAYS a but, sometimes it's a butt :) ) but this time it's a small one :
- render to texture make blitz3d a little bit less hardware-compatible as it does not work on all hardware. "But", the graphics cards that don't support it are actually pretty old (like ... graphics card sold before 2000), and thoose hardware already suffer from a bigger disease ... they almost all have a memory stick, or a processor or a motherboard ... that burnt and can't be replaced because no more sold, Anf for once in a lifetime, it's a good thing, because, we don't really need to care anymore about this guy that loved his gf mx-4000 with 32Mo Video Ram \o/ (ok, I loved it too ...)


I'm probably being selfish but it would be handy, and more versatile, if you could specify almost the same paramaters as copyrect:

There is no need for extra parameters like you mention because everything is already under user control and already almost "copyrect-like" :
And to be true, it would make thoose control really complicate if we specify src/dest on the rendertotexture : the results would be almost impredictible and hard to understand
-> you can use CameraViewport to specify the "src" parameters
-> you can use both UVs of the render mesh and scaletexture/positiontexture/rotatetexture to control the output and in a certain way, the source position and size.
So, you have really all the control of the viewport easier and faster.


Bobysait(Posted 2015) [#17]
A multi-view sample for RenderToTexture
(like I said, just use the CameraViewport to set the Source position and size, the PositionTexture can fake the Dest position and size)

But according to the purpose of RenderToTexture, I'm going to add a parameter "Camera" to it, and only render the camera specified (or all cameras if "camera=0"). It will make things easier.

format_codebox('

Const NVIEWSI% = 10
Const NVIEWSJ% = 7

Const TEX_RESW% = 800
Const TEX_RESH% = 600

Graphics3D TEX_RESW,TEX_RESH,0,2
SetBuffer BackBuffer()

AmbientLight 255,255,255

; render texture that cover 16* 128*128 views
Local render_texture = CreateTexture(TEX_RESW,TEX_RESH,1+256+1024);
Local rcam = CreateCamera ( );
CameraRange ( rcam , .1,2 );
Local quad = CreateMesh ( rcam );
Local surf = CreateSurface ( quad );
Local u# = Float(GraphicsWidth()) / TextureWidth(render_texture);
Local v# = Float(GraphicsHeight()) / TextureHeight(render_texture);
Local dh# = Float(GraphicsHeight())/GraphicsWidth();
AddVertex ( surf , -1,+dh,1,0,0 );
AddVertex ( surf , +1,+dh,1,u,0 );
AddVertex ( surf , +1,-dh,1,u,v );
AddVertex ( surf , -1,-dh,1,0,v );
AddTriangle ( surf , 0,1,2 );
AddTriangle ( surf , 0,2,3 );
EntityTexture ( quad , render_texture );

Local views%[NVIEWSI*NVIEWSJ]
Local vw = TEX_RESW/NVIEWSI
Local vh = TEX_RESH/NVIEWSJ

For b = 0 To NVIEWSJ-1
For a = 0 To NVIEWSI-1
Local i = a+b*NVIEWSI
views[i]= CreateCamera ( );
CameraViewport ( views[i], a*vw,b*vh,vw,vh );
CameraClsColor ( views[i], Rand(10,100), Rand(10,100), Rand(10,100) );
HideEntity ( views[i] );

Local obj= CreateCone ( Rand(3,64), 1, views[i] );
EntityColor ( obj , Rand(100,255), Rand(100,255), Rand(100,255) );
MoveEntity ( obj , 0,0,3 );
Next;
Next;

Repeat
; ------------------------------
; render each view
; ------------------------------

; hide render camera (view-quad)
HideEntity rcam

; render views to render_texture
Local tris = 0;
For i = 0 To NVIEWSI*NVIEWSJ-1
ShowEntity ( views[i] );
RenderToTexture ( render_texture );
HideEntity ( views[i] );
tris = tris + TrisRendered();
Next;

; ------------------------------
; render view-quad
; ------------------------------

ShowEntity ( rcam );
RenderWorld ( );

Text 10,10, tris;

Flip ( True );

Until KeyDown(1)
End;
')


RemiD(Posted 2015) [#18]
Hello,

I am grateful for your contribution, but...
I have done some tests and i find the functions createsbones() and setBone() confusing... And the necessity to recreate a skeleton with pivots is unecessary work imo (when many of us will probably have premade skeletons and premade animations and premade skinned meshes)

So if you don't mind, i want to suggest others possibilities and functions for this system :

Have the possibility to load a premade skeleton with joints (bones) which already has premade animations.
Skeleton = loadanimmesh("skeleton.b3d") (a b3d file which contains a skeleton with joints (bones) and animations, each joint (bone) having a name)

Have the possibility to skin some premade skinned meshes on this skeleton :
PartMesh = loadAnimMesh("leg.b3d") (a b3d file which contains a skeleton with joints (bones) and a mesh with skinned vertices (some influences of some joints (bones) over some vertices)

to get the influences of some joints (bones) over some vertices, have these functions :
CountInfluences%(Surface,VId%) ;return the number of influences on this vertex (VId)
For IId% = 1 to InfluencesCount
GetInfluenceJoint%(Surface,VId%,IId%) ;return the joint reference of this influence (IId) on this vertex (VId)
GetInfluenceWeight#(Surface,VId%,IId%) ;return the weight of this influence (IId) on this vertex (VId)
Next

to set the influences of some joints (bones) over some vertices have these functions :
SetInfluencesCount(Surface,VId%,ICount%) ;set the number of influences on this vertex (VId)
For IId% = 1 to InfluencesCount
SetInfluenceJoint(Surface,VId%,IId%,Joint%) ;set the joint reference of this influence (IId) on this vertex (VId)
SetInfluenceWeight(Surface,VId%,IId%,Weight#) ;set the weight of this influence (IId) on this vertex (VId)
Next

(of course you can use the word "bone" instead of "joint" if you prefer...)

To animate, it is possible to extract the premade animations associated to the premade skeleton with ExtractAnimSeq(), and then to play the animation with Animate()

This would allow us to use one premade skeleton with joints (bones) and premade animations, then to load different premade skinned meshes (body parts, clothes, armors), then to analyze the vertices of these parts (including the influences) then to create a final mesh (with the influences) which can then be animated by the skeleton...

What do you think ? What others think ?


Bobysait(Posted 2015) [#19]
I think there is a misanderstood with createbones
The demo is just a demo, not "The way to use it"
The function rips the hierarchy of the mesh and generates bones from each children and sub-children.
It doesn't matter if it's pivots made in the code or a skeleton loaded from a b3d or else ... but for the demo, I had to go from scratch to build a hierarchy. So, if you have a premade skeleton, you just need to call the function, the skeleton will be transformed into bones.
I could name it GenerateBones or ExtractBones, but it's a function that was already in the official source, I just wrapped it to the IDE to be usable, so I left the same name for three reasons :
- When I saw it, I understood immediatly what it was about, so, for me and for M.Sibly it seems to be a perfect name for the function.
- I don't want to use too much of my own style to rename functions, because I want to keep the code standard and generic as much as possible
- I don't think I'm more relevant than M.Sibly could be, so if he decided to call it "CreateBones" I didn't feel I could really rename it to something else. And as French say "Rend à César, ce qui lui appartient" ;)
But essentially, in my opinion, it's mostly a matter of it must be generic enough to be included in the source. I want to keep the additional stuff as low-level as possible to fit any purpose.
And actually, both SetBone and createbones functions are perfect for that.
You have all the ability to make what you want as you have all access to all data required.

Have the possibility to load a premade skeleton with joints (bones) which already has premade animations.
Skeleton = loadanimmesh("skeleton.b3d") (a b3d file which contains a skeleton with joints (bones) and animations, each joint (bone) having a name)


load your mesh
load your skeleton (set the mesh as parent)
CreateBones(mesh)
And that's all.
In theory, animations are preserved. (In theory : I have not tested the function further, but there is no reason the previous animations would be collapsed or overriden)


Have the possibility to skin some premade skinned meshes on this skeleton :
PartMesh = loadAnimMesh("leg.b3d") (a b3d file which contains a skeleton with joints (bones) and a mesh with skinned vertices (some influences of some joints (bones) over some vertices)



If I really understand what you say (and I must admit I find this a bit confused), it's way to complicated to be implemented.
I'm even not sure blitz3d allow this : it's sort of an md2 mixed with a b3d ... the two formats are not compatible

Or maybe you mean that the "mesh with skinned vertices" is a mesh which already contains bones ? (because you can't have vertices skinned without a bone hierarchy)
Eventually, you can have a mesh with vertices containing bone IDs and weights data without bone structur ... but in this case, there is no problem, load your skeleton and call CreateBones. If your hierarchy match the vertices data, it will work.
For now, the CreateBones function does exactly what is made in internal when you load a b3d animmesh.


Also, for the rest about the "influence", it's in the descriptions of the functions in the first post, the function "CountInfluences" that you'd like to see is the function "CountVertexBones", it returns the number of bones that affect the specified vertex, there is also "VertexBone" and "VertexWeight" that returns the bone index and the weight for each vertex. You really have access to all data you need, as far as b3d doesn't support anything else, everything is already there.

It's just a matter of semantic, or syntax, but what all you mentioned is already there.


RemiD(Posted 2015) [#20]

The function rips the hierarchy of the mesh and generates bones from each children and sub-children.
It doesn't matter if it's pivots made in the code or a skeleton loaded from a b3d or else ... but for the demo, I had to go from scratch to build a hierarchy. So, if you have a premade skeleton, you just need to call the function, the skeleton will be transformed into bones.


Ok good to know, i will try as you say.

edit : removed useless comments (because of wrong understanding)


RemiD(Posted 2015) [#21]
Hello Bobysait,

I have done several tests to load a premade skeleton with bones and premade animations and then to load a premade skinned mesh using the same skeleton/bones and then to recreate the mesh and to skin it on the skeleton (bones) but i am blocked at the skinning step, can you give more explanations please :

If i use a premade skeleton with bones (skeleton = loadanimmesh("skeleton.b3d"))) and which already has animations (animation = extractanimseq(skeleton,2,26))
How am i supposed to then use setbone(surfacereference%,vertexindex%,vertexboneindex%,boneindex%,weight#) knowing that i have no function to get the boneindex% of a bone in the skeleton ? (i can only get the bonereference with getchild() or with findchild()...)
(In your code example, boneindex seems to be an index% attributed to a bone in the skeleton when it is created (in the range 1->bonescount), but how to get this index% in a premade skeleton ?

Thanks,


Bobysait(Posted 2015) [#22]
The bone indices are sorted by blitz on the creation (it's the way it is in the original) :
the mesh itself is the ID 0
then it is recursive

format_codebox('
Function GetChildId%( root, searchentity)
Local curId%[1]:curId[0]=0
Local resId%[1]:resId[0]=0
GetSubChildId(root, searchentity, curId, resId)
Return resId[0];
End Function

Function GetSubChildId%( entity, search, curId%[1], resId%[1])
If search = entity Then resId[0] = curId[0];
curId[0]=curId[0]+1;
Local ic%
For ic = 1 To CountChildren(entity)
GetSubChildId(GetChild(entity,ic), search, curId, resId);
Next
End Function

Graphics3D 800,600,0,2
SetBuffer BackBuffer()


Local Head = CreatePivot(); 0
Local R0 = CreatePivot(Head);
Local R00 = CreatePivot(R0);
Local R000 = CreatePivot(R00);
Local R01 = CreatePivot(R0);
Local R010 = CreatePivot(R01);
Local R1 = CreatePivot(Head);
Local R10 = CreatePivot(R1);
Local R100 = CreatePivot(R10);
Local R2 = CreatePivot(Head);
Local R20 = CreatePivot(R2);
Local R200 = CreatePivot(R20);
Local R21 = CreatePivot(R2);
Local R210 = CreatePivot(R21);

Print GetChildId(Head,Head)
Print GetChildId(Head,R0)
Print GetChildId(Head,R1)
Print GetChildId(Head,R2)
Print GetChildId(Head,R00)
Print GetChildId(Head,R01)
Print GetChildId(Head,R10)
Print GetChildId(Head,R20)
Print GetChildId(Head,R21)
Print GetChildId(Head,R000)
Print GetChildId(Head,R010)
Print GetChildId(Head,R100)
Print GetChildId(Head,R200)
Print GetChildId(Head,R210)

WaitKey()
End
')


RemiD(Posted 2015) [#23]
@Bobysait>>Thanks.
So apparently the bones indexes are in the range 0->bonescount-1...


Bobysait(Posted 2015) [#24]
it's from 0 to bonescount [o for the mesh, 1 to bonescount for the children hierarchy]


RemiD(Posted 2015) [#25]
I still have some errors...

A few more questions please :

Let's say that i have a premade skeleton with bones and premade animations.
I want to use the same skeleton and the same animations for several characters.
And i want to build a different skinned mesh for each character by using skinned meshes parts (bodyparts, faces, hairs, clothes, armors)

To do that,
i load my premade skeleton ( premadeskeleton = loadanimmesh("skeleton.b3d") )
i extract the premade animation ( premadeanimation = extractanimseq(skeleton,2,26) )
i load some premade skinned meshes ( premadebody = loadanimmesh("body.b3d") | premadepants = loadanimmesh("pants.b3d") )

Now i want each character to have one skeleton with the same bones, which can be animated by the same animations, so for this character, i create a copy of the skeleton ( characterskeleton = copyentity(premadeskeleton) )
Then i want this character to have a mesh with a body and pants so i create a new mesh ( charactermesh = createmesh() ) then i analyze the premade skinned meshes ( premadebody and premadepants ) and i recreate them (with the influences of some bones over some vertices)

In this case, at which time should i use createbones(skeleton) or createbones(skinnedmesh) ?
From what i understand :
->once i have loaded the premade skinned meshes, ( premadebody and premadepants ) i must use for each one, createbones(skinnedmesh) so that i can get for each vertex, the influencescount and for each influence, the boneindex and the weight
->once i have used charactermesh = createmesh(), i must use createbones(charactermesh) so that i can set for each vertex, for each influence, the boneindex and the weight

Yes ? No ?



And then to animate the final skinned mesh (charactermesh) can i use the premadeanimation of the premadeskeleton or do i have to extract the animation of the copied skeleton (characterskeleton) ?



Thanks,


Bobysait(Posted 2015) [#26]
I think you own the reccord for "premade" use in a single text ...

Well, it's hard to answer accurately, models and hierarchy can be really very different from a model to another.
And, must admit you're not very clear with all this "premade" stuff :)

I just have the impression you're looking for something blitz3d can't do :
Share bones with model that are not copies.

You have to understand that each model (different one from the other) will have its own hierarchy, because only "copy" (created as copy) share animations and skeletons.

If that's clear, let's dig a bit further, we'll find an answer for your problem.

ps : I'm ok that everybody could learn from that, but, just for this one, go for french, because it's already very complicated with single words to explain your task ... it should be a bit easier for both you and me to understand what you're talking about.


RemiD(Posted 2015) [#27]

I think you own the reccord for "premade" use in a single text


:D


You have to understand that each model (different one from the other) will have its own hierarchy, because only "copy" (created as copy) share animations and skeletons.


Ok but if the animation refers to the scale/orientation/position of a boneindex in the skeleton (hierarchy), then if i use an animation which refers to boneindex in a skeleton which has these bones with the same boneindex, this should work ?

I think that my attempt is not far to work because all seems correct except the animation which does not animate the final skeleton and final skinned mesh.

Can i send you a .zip file somewhere so that you can take a look ?


Bobysait(Posted 2015) [#28]
If you know my email you can send me the zip (i don't want to leave my email as public, for reasons you may know) ... I'll take a look (but not tonight, I'm so tired I could fall asleep on the keybokdjjjjjjjjjjjjjjjjjjjjjj


RemiD(Posted 2015) [#29]
Is the email address in your blitzbasic profile ok ?

Or i could post the link here, no problem.


Bobysait(Posted 2015) [#30]
It wasn't (my email was hacked two monthes ago, I forgot to replace it with the new-old one)

It's updated.


RemiD(Posted 2015) [#31]
Here : <-pouf!->

(and thanks)
(and good night, i'm going to sleep now...)


Bobysait(Posted 2015) [#32]
I've read your code and dumped your b3d files ...
I think you're not going anywhere like this.
your "leg" file already contains everything (model, hierarchy and animation)
You add it an animation file and then createbones (that were already presents) etc ...
You duplicate so many instances of everything that the hierarchy is a big mess.

For what you're looking for, you have two ways to do it, but it will depend on your needs.
A - you want output a single surface mesh (or a single mesh with single/multiple surfaces)
B - you want output a single root (pivot or mesh) with different meshes parented (a mesh for the body, a mesh for the legs etc ...)

Because in each case, you'll need to implement it in a very different way.
in the case A, you'll have lots of memory used (each model will have its own vertex and triangle container), but it will run very fast because : Single mesh
in the case B, you'll have lots of entities duplicated and the animation will be harder to maintain (you'll probably have to recreated an animation using the keys of all sub-animations of all parts, OR animate each part individually)


RemiD(Posted 2015) [#33]

your "leg" file already contains everything (model, hierarchy and animation)


Yes


You add it an animation file and then createbones (that were already presents) etc ...
You duplicate so many instances of everything that the hierarchy is a big mess


No, all is well i have debugged it, i have the exact same number of bones and of vertices...
I load a premade skeleton (PremadeSkeleton) with bones and animations, i load a premade skinned mesh (PremadeLeg) influenced by the same skeleton with bones and animations (i should have removed the animations on this one but whatever)
Then i copy the premade skeleton (TestSkeleton)
Then i extract the premade animations in TestSkeleton (TestAnimation)
Then i recreate the mesh of the premade skinned mesh (with the same influences by the same bones) (TestMesh)
All seems to work well according to the debug datas.

But when i try to animate the skeleton, only the skeleton is animating, not the skinned mesh.
This is probably because i am not sure when to use createbones(hierarchy) and on which entity (PremadeSkeleton? PremadeMesh ? TestSkeleton ? TestMesh ?)

This is why i wanted you to take a look.

I have added spheres set as childs of each bone of the TestSkeleton and it seems that the skeleton is animating correctly, but the skinned mesh TestMesh does not follow)
Why ?

Here a new example with only the essentials :
>-pouf!-<


you want output a single surface mesh (or a single mesh with single/multiple surfaces)


Yes that's what i want to do, copy a premade skeleton with bones and animations and analyze several premade skinned meshes (associated to the same skeleton/bones) to create a final skinned mesh associated to the copied skeleton/bones (one copied skeleton + one unique mesh with one surface for each character)


Bobysait(Posted 2015) [#34]
I modified some syntax and indentation (sorry, I couldn't read your code the way it was, I need order in code ...)

Try this, it should work.
And, you must use Createbones :
- only on the copy that doesn't have bones
- only when you have copied the hierarchy to the mesh (else you won't dump any bones from the mesh)
So, for recall : CreateBones extract the entities from your mesh and convert the hierarchy to bones. If the mesh has no hierarchy, then there is no bones extracted.

format_codebox('
Graphics3D ( 1000,625, 0,2 );
SetBuffer ( BackBuffer() );

SeedRnd ( MilliSecs() );

Global Arial15Font = LoadFont ( "Arial", 15, False,False,False );

; -----------------------------------------------------------------------------
; - CAMERA -
; -----------------------------------------------------------------------------

Local root = BuildGhost ( );
Local head = GetChild ( root, 1 );
PositionEntity ( root, 0,1.65,-3, True );

Local Camera = CreateCamera ( );
CameraRange ( Camera, 0.1,100 );
CameraClsColor ( Camera, 020,040,060 );

; -----------------------------------------------------------------------------
; - LIGHT -
; -----------------------------------------------------------------------------

AmbientLight ( 016,016,016 );

Local DLight = CreateLight ( 1 )
; LightRange ( DLight, 1000+100 );
LightColor ( DLight, 240,240,240 );
PositionEntity ( DLight, 50,1000,-1000,True );
RotateEntity ( DLight, 45,0,0,True );
HideEntity ( DLight );

Local OLight = CreateLight ( 2, Camera );
LightRange ( OLight, 3.0 );
LightColor ( OLight, 224,224,224 );
; HideEntity ( OLight );


; -----------------------------------------------------------------------------
; - EDITOR PARAMETERS -
; -----------------------------------------------------------------------------

Const C2D% = 1
Const C3D% = 2

Global InteractionMode% = C3D

; -----------------------------------------------------------------------------
; - EDITOR SCENE -
; -----------------------------------------------------------------------------

Local Origine = CreateCube ( );
ScaleMesh ( Origine, 0.01/2,0.01/2,0.01/2 );


Global GroundMesh = CreateMesh ( )
Local Surface = CreateSurface ( GroundMesh )
AddVertex ( Surface, 0.0,0.0,100.0,0.0/8,0.0/8 )
AddVertex ( Surface, 100.0,0.0,100.0,8.0/8,0.0/8 )
AddVertex ( Surface, 0.0,0.0,0.0,0.0/8,8.0/8 )
AddVertex ( Surface, 100.0,0.0,0.0,8.0/8,8.0/8 )
AddTriangle ( Surface, 0,1,2 )
AddTriangle ( Surface, 2,1,3 )
UpdateNormals ( GroundMesh )

Local TxRes = 64;
Local GroundTexture = CreateTexture ( TxRes,TxRes, 1+2+256 );
SetBuffer ( TextureBuffer(GroundTexture) );
LockBuffer();
Local i,j
For j = 0 To TxRes - 1
For i = 0 To TxRes - 1
WritePixelFast(i,j, $00FFFFFF );
Next;
Next;
For i = 0 To TxRes - 1
WritePixelFast(i,1, $40FFFFFF );
WritePixelFast(i,TxRes-2, $40FFFFFF );
WritePixelFast(1,i, $40FFFFFF );
WritePixelFast(TxRes-2,i, $40FFFFFF );
Next;
For i = 0 To TxRes - 1
WritePixelFast(i,0, $FFFFFFFF );
WritePixelFast(i,TxRes-1, $FFFFFFFF );
WritePixelFast(0,i, $FFFFFFFF );
WritePixelFast(TxRes-1,i, $FFFFFFFF );
Next;
UnlockBuffer();
SetBuffer ( BackBuffer() );
ScaleTexture ( GroundTexture, 0.01,0.01 );
EntityTexture ( GroundMesh, GroundTexture );

; -----------------------------------------------------------------------------
; - ANIMATOR -
; -----------------------------------------------------------------------------

; step 0 : initialize templates
; Load the template hierarchy and hide it
Global TPL_Skeleton=LoadAnimMesh ( "test skeleton + animations 201512031932Fraged.b3d" )
HideEntity ( TPL_Skeleton )

; load the template animation -> this is useless if the model already contains the animation (which should be the case if you don't want to animate your stuff in code)
;Global TPL_Animation=ExtractAnimSeq ( TPL_Skeleton, 1,10 )

; load the template model and hide it
Global TPL_Leg = LoadAnimMesh ( "test leg 201512031932FragedEN.b3d" )
HideEntity ( TPL_Leg )

; load the template pants and hide it (actually : hide "them")
Global TPL_Pants= LoadAnimMesh ( "test pants 201512031932FragedEN.b3d" )
HideEntity ( TPL_Pants )


;First step : Create the mesh
; leave it empty for the moment
Global TestMesh = CreateMesh ( );

;Second : add the hierarchy to the mesh
Global TestSkeleton=CopyEntity ( TPL_Skeleton, TestMesh )

; Third : build/copy the surfaces
Local BoneOffset% = 3; YOU HAVE 3 PIVOTS UNTIL YOU REACH THE ACTUAL LEG ROOT -> SO YOU HAVE TO ADD THEM TO MATCH THE HIERARCHY !!!
Local is%=0, vi%, ii%, ti%;
For is = 1 To CountSurfaces(TPL_Leg)
Local OSurf = GetSurface ( TPL_Leg, is );
Local NSurf = CreateSurface ( TestMesh );
; copy vertices
For vi% = 0 To CountVertices(OSurf)-1
AddVertex ( NSurf,VertexX(OSurf,vi),VertexY(OSurf,vi),VertexZ(OSurf,vi) );
VertexNormal( NSurf,vi,VertexNX(OSurf,vi),VertexNY(OSurf,vi),VertexNZ(OSurf,vi) );
Local nbones% = CountVertexBones ( OSurf, vi );
For ii% = 0 To nbones-1
setBone(NSurf, vi, ii, BoneOffset+VertexBone(OSurf, vi, ii), VertexWeight(OSurf, vi, ii), (ii=nbones-1) );
Next
If nbones<4 Then setBone(NSurf, vi, nbones, -1, 0);
Next
; copy triangles
For ti% = 0 To CountTriangles(OSurf)-1 Step 1
AddTriangle(NSurf,TriangleVertex(OSurf,ti,0) ,TriangleVertex(OSurf,ti,1) ,TriangleVertex(OSurf,ti,2) )
Next
Next;

; fourth : build the bones
CreateBones ( TestMesh )

; finally : add some animation(s)
Global TestAnimation= ExtractAnimSeq ( TestSkeleton, 1,10 )

;Scale the scene after the animation extraction.
ScaleEntity ( TestMesh, 0.01,0.01,0.01 )

Global Timer = CreateTimer(30)

Main(root, head, Camera)

End()






Function Main(root, head, camera)

Local MPX%
Local MPY%
Local MXDiff%
Local MYDiff%

While( KeyDown(1)<>1 )

; Update input
; -------------------------------------------------------------------------

MPX = MouseX()
MPY = MouseY()
MXDiff = MouseXSpeed()
MYDiff = MouseYSpeed()

If KeyHit(15) Then InteractionMode = C2D + (C3D-C2D)*(InteractionMode=C2D)

Select (InteractionMode)

Case C2D

;

Case C3D

; update camera view angles
If MouseDown(2)
TurnEntity (root, 0,-MXDiff,0 );
TurnEntity (head, +MYDiff,0,0 );
EndIf;

; update speed
Local speed# = 0.10;
If KeyDown(29)
speed# = 0.01
ElseIf KeyDown(42)
speed# = 1.00;
EndIf

; update translation
Local vx# = Float(KeyDown(32)-KeyDown(30)) * speed; D-Q
Local vy# = Float(KeyDown(18)-KeyDown(16)) * speed; E-A
Local vz# = Float(KeyDown(17)-KeyDown(31)) * speed; Z-S

MoveEntity root, vx,vy,vz;

; camera->setTransform(head->transform)
TFormNormal ( 0,1,0, head, 0 ) : AlignToVector ( camera, TFormedX(), TFormedY(), TFormedZ(), 2,1 ); align Y
TFormNormal ( 0,0,1, head, 0 ) : AlignToVector ( camera, TFormedX(), TFormedY(), TFormedZ(), 3,1 ); align Z
TFormPoint ( 0,0,0, head, 0 ) : PositionEntity ( camera, TFormedX(), TFormedY(), TFormedZ(), True ); position Absolute

End Select;


; update animation(s)
; -------------------------------------------------------------------------

;hold key Space to animate the skeleton and the skinned mesh
If KeyDown(57)
If Not(Animating(TestSkeleton))
Animate(TestSkeleton,3,0.1,TestAnimation)
EndIf;
Else
Animate(TestSkeleton,0);
EndIf

UpdateWorld()


; update rendering
; -------------------------------------------------------------------------

WireFrame(KeyDown(2)>0)
SetBuffer(BackBuffer())

RenderWorld()


; 2D - debug
; -------------------------------------------------------------------------

drawHierarchy (camera,TestMesh);

PlotMeshVertices(camera,TestMesh,2,255,000,255)

SetFont(Arial15Font)
Color(255,255,255)
CText ( "Triangles = "+TrisRendered(),0,0 )
CText ( "AnimLength= "+AnimLength(TestSkeleton), 0,15 );
CText ( "AnimLength= "+AnimLength(TestMesh), 0,30 );
WaitTimer(Timer)
VWait():Flip(False)

Wend

End Function

Function drawHierarchy (camera,entity, x=-1,y=-1)
CameraProject camera, EntityX(entity,1), EntityY(entity,1), EntityZ(entity,1)
Local px = ProjectedX(), py = ProjectedY()
If x>0 And y>0 Then Line x,y, px,py
Local ic%, nbc% = CountChildren(entity);
For ic = 1 To nbc
drawHierarchy (camera, GetChild(entity,ic), px,py)
Next
End Function

Function CText(TextStr$,PX%,PY%)
Text(PX,PY,TextStr,False,False)
End Function

Function BuildGhost()
Local root = CreatePivot()
Local head = CreatePivot(root)
Return root
End Function

Function PlotMeshVertices(camera, mesh, Radius#=1, R%=255, G%=255, B%=255)
Local is%
Local nbs% = CountSurfaces(mesh)
For is = 1 To nbs
Local surf = GetSurface(mesh, is)
Local nbv% = CountVertices(surf), v%
For v = 0 To nbv-1
CameraProject(camera, VertexRiggedX(mesh, surf, v), VertexRiggedY(mesh, surf, v), VertexRiggedZ(mesh, surf, v))
Color(R,G,B)
Rect(ProjectedX()-Radius,ProjectedY()-Radius,Radius*2,Radius*2,True)
Next
Next
End Function
')


RemiD(Posted 2015) [#35]

I modified some syntax and indentation (sorry, I couldn't read your code the way it was, I need order in code ...)


My code is indented but only with spaces...


Thanks for the example i will study it and try to modify my code to make it work the same way.


RemiD(Posted 2015) [#36]
You wrote : "YOU HAVE 3 PIVOTS UNTIL YOU REACH THE ACTUAL LEG ROOT -> SO YOU HAVE TO ADD THEM TO MATCH THE HIERARCHY !!!"

Why are there 3 pivots until i reach the hierarchy ? I can understand that the root of TestMesh could be considered as one pivot and the root of TestSkeleton could be considered as one pivot but then what is the other ?


RemiD(Posted 2015) [#37]
double post


RemiD(Posted 2015) [#38]
Yes i don't understand the BoneOffset thing. What it is supposed to represent ? And why do you give it the value of 3 ?

Thanks for your time btw, :)


RemiD(Posted 2015) [#39]
Also can you explain what "normalize_weights%" represents ? And why it is necessary ? (in your code you wrote "(ii=nbones-1)")

edit : it does not seem necessary... Not sure what it does...


RemiD(Posted 2015) [#40]
If i add the boneoffset of 3 to the boneindex of each influence, it works well, (thanks!) but i don't understand why. Can you please explain ?


Bobysait(Posted 2015) [#41]
The bone offset is 3 because when you "createbones" it makes a bone for the mesh itself (which is the "0" bone)

You have a hierarchy on the skeleton which start from scene_root as a pivot (exported as a mesh, but whatever, it is an empty mesh)
You have a hierarchy on the leg (from loadanimmesh) which start from scene_root as the mesh model.

when you copy the skeleton hierarchy to the output mesh, you have one offset due to the skeleton being parented to the mesh (if you want to match perfectly, you should copy the skeleton only beginning by the first child and not the skeleton itself, but as long as you exported the animation on the scene_root, you have to copy the scene_root to enable the animation sequence to be copied too)
Then as your leg model is the scene_root of your model (while it should have the scene_root as parent of the model ^^) you have a second offset due to the need of matching with the skeleton

And as mentioned, the third is the output mesh itself which is added as the first bone in the hierarchy.

It doesn't have to be like this, it's just your b3d files that are not optimised for this.

For the normalizeweight, just consider that it's an internal requirement :
- you can set up to 4 bones, but blitz3d does know exactly how many are set up, it just knows that if it encounter a "255" on the 4 bones then there is no bone at this place and no bone after.
In the function, I replaced the "255" with a "-1" which I thought was more explicit.
Then comes the normalization : if you set first bone to 0.2 and second to 0.4 and ends bone here, the sum is 0.6 which will make the vertex having an almost impredictible behavior (it's in fact predictible : it will looks like it's stuck to the origin bone)
So, using normalization while setting the last bone, it will sum up all previous bones set for the vertex and normalize, so the weights will be 1.0



So, for optimizing your export, (don't know which software you use) export the hip directly if you can. B3d file format allows to have a root whith position offset, it doesn't have to start with a "Scene_root" at 0,0,0 (it's just the 3dsmax b3d exporter that make this happen)

Same thing for your model, remove any bones that are not directly a child or sub-child from the model (for the leg, there is no need to export the scene_root or the pelvis pivot)

In blitz3d, you 'll have just one offset with the mesh (and if you can get animation to work on the skeleton without the first root, you won't have any offset at all if your hierarchy match perfectly the hierarchy of the procedurally made leg)
-> it will be easier and it will run faster (it's always better when there are no extra entities to increase the loop count on the matrix updates)


RemiD(Posted 2015) [#42]
Thanks for the precisions.

About the names of bones, i use Fragmotion and the bones of TestSkeleton all have names...
The only entity which has no name is the TestMesh, but i have now used NameEntity() to give it a name. Anyway !

Thanks again, it can be very useful to be able to do that for some games.


Bobysait(Posted 2015) [#43]
I edited my message.
I had debugged the blitz3d created mesh instead of the b3d file's one :)
There were no names because we didn't set any :p


RemiD(Posted 2015) [#44]
Yes i understood why the offset is 3 with the explanations in your previous post.

The only thing i can do is remove the "Root" bone in the skeleton, because the "Scene_Root" bone i can't do anything about it, it is added automatically by Fragmotion when it exports the .b3d.

But it works well, that's enough for what i want to do. :)


I had debugged the blitz3d created mesh instead of the b3d file's one


Oh i see... :)


Bobysait(Posted 2015) [#45]
You can also do this :

-> remove the 2 first bones of the animation hierarchy, then recreate the keys and animation

-> then the offset is just "1" (for the destination mesh)
And you removed 2 entities from the hierarchy = less resources - better performance

format_codebox('

Function copyTransforms(dest, src, frame%=-1, pos_key%=True, rot_key%=True, scl_key%=True)
Local ic%, nbc% = CountChildren(src)
For ic = nbc To 1 Step -1
copyTransforms(dest, GetChild(src,ic), frame, pos_key, rot_key, scl_key);
Next
Local ent = FindChild(dest, EntityName(src));
RotateEntity ( ent, EntityPitch(src,0),EntityYaw(src,0),EntityRoll(src,0), 0 );
PositionEntity ( ent, EntityX(src,0),EntityY(src,0),EntityZ(src,0), 0 );
TFormVector(1,0,0, src, GetParent(src)): Local sclx# = Sqr(TFormedX()^2+TFormedY()^2+TFormedZ()^2);
TFormVector(0,1,0, src, GetParent(src)): Local scly# = Sqr(TFormedX()^2+TFormedY()^2+TFormedZ()^2);
TFormVector(0,0,1, src, GetParent(src)): Local sclz# = Sqr(TFormedX()^2+TFormedY()^2+TFormedZ()^2);
ScaleEntity ( ent, sclx, scly, sclz, 0 );
If frame>=0 Then SetAnimKey(ent, frame, pos_key, rot_key, scl_key);
End Function

; -----------------------------------------------------------------------------
; - ANIMATOR -
; -----------------------------------------------------------------------------

; step 0 : initialize templates
; Load the template hierarchy and hide it
Global TPL_Skeleton=LoadAnimMesh ( "test skeleton + animations 201512031932Fraged.b3d" )
HideEntity ( TPL_Skeleton )

; load the template animation -> this is useless if the model already contains the animation (which should be the case if you don't want to animate your stuff in code)
;Global TPL_Animation=ExtractAnimSeq ( TPL_Skeleton, 1,10 )

; load the template model and hide it
Global TPL_Leg = LoadAnimMesh ( "test leg 201512031932FragedEN.b3d" )
HideEntity ( TPL_Leg )

; load the template pants and hide it (actually : hide "them")
Global TPL_Pants= LoadAnimMesh ( "test pants 201512031932FragedEN.b3d" )
HideEntity ( TPL_Pants )


;First step : Create the mesh
; leave it empty for the moment
Global TestMesh = CreateMesh ( );

;Second : add the hierarchy to the mesh
Local skeleton_root=GetChild(GetChild(TPL_Skeleton,1),1); <- get the real root to copy (first child of the first child) ...
; not the seventh son of the seventh son, but hey ! we must start somewhere
Global TestSkeleton=CopyEntity ( skeleton_root, TestMesh ) ; <- copy the hierarchy and parent it to the mesh
CreateBones ( TestMesh ) ; the mesh is filled, we can extract the bones

; as we removed the root of the skeleton before copy, the keys have been removed too -> copy the sequence
Local frame%
For frame = 1 To 10
SetAnimTime (TPL_Skeleton, frame);
copyTransforms(TestSkeleton, skeleton_root, frame, False, True, False) ; <- just copy the rotations
; (scale is for setting the morphing of your model )
; (positions are useless on a hierarchy only animated using rotation)
Next

; add the animation.
Global TestAnimation=AddAnimSeq ( TestSkeleton, 11 );

; Third : build/copy the surfaces
Local BoneOffset% = 1; YOU HAVE 3 PIVOTS UNTIL YOU REACH THE ACTUAL LEG ROOT -> SO YOU HAVE TO ADD THEM TO MATCH THE HIERARCHY !!!
Local is%=0, vi%, ii%, ti%;
For is = 1 To CountSurfaces(TPL_Leg)
Local OSurf = GetSurface ( TPL_Leg, is );
Local NSurf = CreateSurface ( TestMesh );
; copy vertices
For vi% = 0 To CountVertices(OSurf)-1
AddVertex ( NSurf,VertexX(OSurf,vi),VertexY(OSurf,vi),VertexZ(OSurf,vi) );
VertexNormal( NSurf,vi,VertexNX(OSurf,vi),VertexNY(OSurf,vi),VertexNZ(OSurf,vi) );
Local nbones% = CountVertexBones ( OSurf, vi );
For ii% = 0 To nbones-1
setBone(NSurf, vi, ii, BoneOffset+VertexBone(OSurf, vi, ii), VertexWeight(OSurf, vi, ii), (ii=nbones-1) );
Next
If nbones<4 Then setBone(NSurf, vi, nbones, -1, 0);
Next
; copy triangles
For ti% = 0 To CountTriangles(OSurf)-1 Step 1
AddTriangle(NSurf,TriangleVertex(OSurf,ti,0) ,TriangleVertex(OSurf,ti,1) ,TriangleVertex(OSurf,ti,2) )
Next
Next;

;Finally : Rescale the scene
ScaleEntity ( TestMesh, 0.01,0.01,0.01 )
')


RemiD(Posted 2015) [#46]
Thanks, i will take a look... (even if i don't think that 2 bones will reduce performance significantly, especially considering they have no influence over any vertices, but i don't know how Blitz3d calculates the new position of a skinned vertex after the bones have been animated, so i am not sure if it is important or not)


Bobysait(Posted 2015) [#47]
For Each vertex, you sum up the matrix of the 1 to 4 bones set up multiply by the weight for each bone, so it doesn't seem to make any difference ... at first.

Then, you check how the bone matrix are composed :
Each bone has a transformation matrix that is "local", to calculate the global transformation, you must multiply each bone's matrix by its parent's then the parent's of the parent etc ... until you reach the blitz3d scene_root.
So, the deeper the hierarchy is, the lower the matrices compute.
Any time an entity is not required in a hierarchy, you should do all you can to remove it.

Of course, this is real for high amount of hierarchies in your scene.
If your game is designed to draw only one leg, then the optimisation is useless as it won't really affect the framerate.
(for at least 20-100 entities (or higher) with deep hierarchy such as humans, you should start to see a difference, depends on the scene complexity and of course, the hardware)

In your scene, the 2 entities I removed are not just 2 entities in the scene, but 2 nested entities which are on the top of your hierarchy, so that all the children of your leg are multiply by 2 matrices.
Imagine a full human body :
- 2 legs (4 matrices multiplication for all bones of the legs)
- 2 arms, the spline, the head etc ...
it can start to be considered as a leak of performance.

note that : a useless end-bone does not affect the performance -> no children are computed with them, it is for the top bones that it's important. (the parents are more important than the children ... every body knows that ^_^, you can leave a child at the gare, who cares ? it's just a child abandonned... but a parent ... police will be alerted with big warnings "he seems dangerous ! maybe a bomb alert or a rapist !")

ps : if this is more relevant

You have 4 bones A,B,C,D
- A is the root
- B child of A
- C child of B
- D child of C

matrix of A is -> A
matrix of B is -> B*A
matrix of C is -> C*B*A
matrix of D is -> D*C*B*A

if D is useless, it doesn't change anything but D
if A is useless the matrices are :
matrix of B is -> B
matrix of C is -> C*B
matrix of D is -> D*C*B

lots of calcul removed just by removing a useless bone :)


RemiD(Posted 2015) [#48]

lots of calcul removed just by removing a useless bone


Yes i understand but i have never found that the animation of rigged skinned meshes was what takes time in the kind of games i try to create (first person view action, third person view action, isometric view action, top down view action)
Also maybe because i use low lod meshes for far away meshes.

For info :
The humanoid that i have created myself has 20bones/joints (including the root). (you probably don't care)

The humanoid used for motion capture (ipisoft) has 23bones/joints (including the root). (you may care about that)



If your game is designed to draw only one leg


Yes that's what i was planning to do ^^, with a variety of pants as the equipment. ;)


RemiD(Posted 2015) [#49]
@Bobysait>>Can you please share the source code for the upgrade vB.002 if some of us want to use it, but also add others updates/upgrades ?


Also, when you have some free time, can you please explain what you have done to modify the source code and then to create a new blitz3d executable (for your upgrades) ? (which tools you have used and what is the process). This may help some of us to create others updates/upgrades...


Thanks,


Bobysait(Posted 2016) [#50]
I used an old MSVC 6.0 installed on a windows Xp 32 bits via VirtualBox.
(with the sp6 pack for msvc)

It required the dx7dsk (which is a bit hard to find nowadays...), freeimage and fmod

I will upload the modified sources in the week (If I don't forget)
(I need to copy the sources from the virtual OS, and I have no time at the moment)

BTW, I won't explain anything because, I have already commented (not documented) the source, every modifications are tagged with "<addon author='BobyC'> </addon>"

Almost all the modifications are self-explained as the function are above all getters.


RemiD(Posted 2016) [#51]
Thanks for the explanations i will try to follow this...


I will upload the modified sources in the week


Good, thanks again.


I won't explain anything because, I have already commented (not documented) the source, every modifications are tagged with "<addon author='BobyC'> </addon>"


I am not worried about understanding your code ( except maybe your weird indentation :P ), i just wanted to know how to open these old sources and how to modify them and how to recompile them to create a new executable.

Can you also explain what i have to do once i have modified the code as i want ? (to create the executable), is it as easy as with Blitz3d ?

Also to apply the update/upgrade, i suppose that i have to copy/paste the same files that you have provided in your upgrades but replace the executable with my executable, correct ?

Thanks,


Bobysait(Posted 2016) [#52]
I edited the first post to add a link to the modified sources.

The archive only contains the files I modified (to replace from the official sources)

-> Download modified sources only (in 7Z format) (compressed with 7zip -> 42 Ko)

As mentioned, all modification is tagged in the sources.


RemiD(Posted 2016) [#53]
Thanks, i will take a look later.


ThePaiva(Posted 2016) [#54]
This is awesome! The render to texture is going to be really useful for some of my projects, thanks a lot!!

Not sure if it's possible but any chance you could activate some other unused things like specular map, extra light functions(ambient color and shininess comes to mind), set the mask/alpha of a texture layer (for texture splatting on terrains or texture mask on models), or anything else along those lines?

I think it might be possible to add some of those natively since to use some all you gotta do is use a dx7 dll and a decls. I might be wrong though, but doesn't hurt to ask...


Bobysait(Posted 2016) [#55]
I'm not very familiar with Dx7, I've never really learnt the sdk (I'm more of an opengl programmer), so, it's very certainly possible, but I won't do it.

I'd better let this kind of stuff to the experts of this old library while, even if I could come to a solution, it would probably be a poor trick, and I wouldn't be able to code something really optimized nor fully reliable.

ps : Glad you like it.


RemiD(Posted 2016) [#56]

extra light functions(ambient color and shininess comes to mind)


this may help :
http://www.blitzbasic.com/Community/posts.php?topic=75711


RemiD(Posted 2016) [#57]
@Bobysait>>When you have some time, and if you want to, can you take look at the source code, and see if it would be easy enough to separate what happens in updateworld() in 2 functions : updatecollisions() (or detectcollisions() or calculatecollisions()) and updateanimations()

This would give us the possibility to structure the code in a better way (detect the collisions only when we want, and update the animations only when we want), this would be really useful imo, i never understood why these 2 systems were not separate...

Thanks,


Bobysait(Posted 2016) [#58]
It's probably doable, as far as I remember the two parts are not that dependant, but I can't do it before a long time.
Would be better if someone could continue the project, as it's not a "closed-project" and I don't give it any kind of restrictive license.

It's not that hard to implement, so RemiD, why wouldn't you do it ? you seem to be a stone of the blitz3d world, maybe it's your time to add your own stone to the project ;)


RemiD(Posted 2016) [#59]

why wouldn't you do it ?


I am not familiar with c++ so i will probably have difficulties to understand... I will try... This is not urgent anyway.

Thanks,


RemiD(Posted 2016) [#60]
Maybe you still have the links to find the files that you mentioned ?
MSVC 6.0
sp6 pack for msvc
dx7dsk
freeimage
fmod

Thanks,


Bobysait(Posted 2016) [#61]
I have links for dx7 sdk if needed (by uploading my current sdk)
freeimage and fmod are not a problem either.

MSVC 6.0 and the pack are shareware from microsoft (it's not the express edtion, but the professional with MFC-inside)

And we all know I can't tell you to find it via kind of a torrent link whatever this software isn't sold anymore anywhere on the planet.


Bobysait(Posted 2016) [#62]
So, here are the links :
- Dx7 Sdk
Dx7Sdk.7z (without samples : 7 Mo)
or
Dx7Sdk.zip (Full : 44 Mo)

- FreeImage 241 library
Freeimage 241 (4 Mo)

- FMod Api 375
fmod 375.zip (2 Mo)


RemiD(Posted 2016) [#63]
Thanks, i have already found the links in the readme of the blitz3d source.
And i think that i have found the appropriate version of MSVC 6.0.

I will take a look at this later. (currently trying to create convincing animations manually)


Yue(Posted 2016) [#64]
In theory , these modificciones you can create a program for editing, creating , animation of 3D models


RemiD(Posted 2016) [#65]
Yes, you can create a skeleton with joints/bones, then create vertices, then skin the vertices (set the weight of each joint/bone over some vertices), then create animation poses, then create an animation, then animate it.

You can also create a custom rigged skinned mesh using a premade skeleton and several premade rigged skinned parts (for example to create a custom character with different body, head, eyes, hair, clothes, armors, weapons)