"Breathing" style mesh deforming code

Blitz3D Forums/Blitz3D Programming/"Breathing" style mesh deforming code

_PJ_(Posted 2009) [#1]
I was sure this was in the code archives. I had a copy of it somewhere, but now I can't find it.

I can;t remember who wrote it, but it may have been Halo/Leadworks.

It was a couple of functions which deformed meshes in particular ways, to make them appear like they were pulsing/breathing...


Ross C(Posted 2009) [#2]
Do you have access to a modeller? Or even Ultimate Unwrap? You could put a bone in the model and set the vertex weights to fall-off, from the centre. Then move the bone to your needs.


_PJ_(Posted 2009) [#3]
I have UU, but I suck at all that stuff :S
Really.

I would be easier for me to have it in code format too as it needs to be timed (I know that with 3D models this can be achieved, but it's way beyond me hehe)

I'm sure I could possibly rustle something up based on some of the other mesh-deforming code, though. Il have a try :)


puki(Posted 2009) [#4]
It is one of "halo's" examples:

Samples\Blitz 3D Samples\halo\MeshFX\


puki(Posted 2009) [#5]
.


_PJ_(Posted 2009) [#6]
AAhaahah! Saved!
I KNEW I'd seen it!

Thanks, Puki - have a doughnut!


Guy Fawkes(Posted 2009) [#7]
can u guys make this code work for anim meshes as well as .x .3ds .b3d meshes? and for only ONE mesh? not 2?


Warner(Posted 2009) [#8]
I can try to explain how you can do it yourself?
Since Sin() is used, you can indeed alter the function to work with a single mesh instead of one original, and one copy.
Start off with making a backup of the original program. In case anything goes wrong. Ie: File->SaveAs->MeshFX2

1. Remove the second mesh parameter from the function
Function Breath(mesh,am#)

2. Remove the second mesh from the call that is made to Breath as well:
Breath(mesh,mesh2, ..) -> Breath(mesh, ..)
3. In the function Breath, remove the line surf2=GetSurface(..)
4. In the function, change every call to surf2 to surf.
5. Change the call to Breath into this:
Breath(mesh,(Sin(MilliSecs()*speed)*depth/100.0))
Now, the function should operate without a 'original' copy of the mesh.
Test if the program still runs.

If you want to use an AnimMesh, I'm not sure how it will work out with boned meshes, but you can give it a shot.
AnimMesh has a tree structure, with a 'root' parent and children. If one of the leaves of this tree structure is a mesh, it might be possible to deform them.
If they are not meshes, you can't deform them, GetSurface will return an error.
So, first make sure that the mesh that is passed to Breath is really a mesh and not a bone/pivot/something else.

Immediately after "Function" add the line:
If EntityClass(mesh)="Mesh" Then

And before "End Function" add the line
EndIf

The entire content of the function is now only executed if the entity is a mesh.

Now the function has to be called for each child of the entity.
At the end of the function, before "End Function", after "End If", add the lines:
For i = 1 To CountChildren(mesh)
	Breath(GetChild(mesh,i),am)
Next

Since this will call "Breath" for each child entity, any sub-children (grandchildren?) will be encountered as well.

That should do it, unless I forgot something. If you want to test it, change the line mesh=LoadMesh(.. etc to
mesh=LoadAnimMesh("C:\program files\blitz3d\samples\mak\anim\makbot\mak_robotic.x");test.3ds")

And perhaps remove anything that is needed for the eggtube effect, such as the second mesh, the selection of the FX etc.


Guy Fawkes(Posted 2009) [#9]
thanks warner!


Guy Fawkes(Posted 2009) [#10]
for everybody who wishes to use:

Function Breath(mesh,am#)
If EntityClass(mesh)="Mesh" Then
For k=1 To CountSurfaces(mesh)
surf=GetSurface(mesh,k)
For index=0 To CountVertices(surf)-1
newx#=VertexX(surf,index)+VertexNX(surf,index)*am
newy#=VertexY(surf,index)+VertexNY(surf,index)*am
newz#=VertexZ(surf,index)+VertexNZ(surf,index)*am
VertexCoords surf,index,newx,newy,newz
Next
Next
For i = 1 To CountChildren(mesh)
	Breath(GetChild(mesh,i),am)
Next
EndIf
End Function



Warner(Posted 2009) [#11]
Ah cool, glad it works. One thingie: the For..Next loop should be placed after EndIf.


Guy Fawkes(Posted 2009) [#12]
ah ok. very well, warner :)

will do :)

fixed function:

Function Breath(mesh,am#)
If EntityClass(mesh)="Mesh" Then
For k=1 To CountSurfaces(mesh)
surf=GetSurface(mesh,k)
For index=0 To CountVertices(surf)-1
newx#=VertexX(surf,index)+VertexNX(surf,index)*am
newy#=VertexY(surf,index)+VertexNY(surf,index)*am
newz#=VertexZ(surf,index)+VertexNZ(surf,index)*am
VertexCoords surf,index,newx,newy,newz
Next
Next
EndIf
For i = 1 To CountChildren(mesh)
	Breath(GetChild(mesh,i),am)
Next
End Function



_PJ_(Posted 2009) [#13]
Biit late seeing this, but I doubt I'd've been much help.

That's pretty neat, DSW, nice and compact too! I was sure it could be done without needing a second mesh and it''s much better to be able to! Thanks :)

Just a consideration, though...
Function Breathe(Mesh%,Recursive%=False,Animation%=1)
If (EntityClass(Mesh)="Mesh")
For k=1 To CountSurfaces(Mesh)
surf=GetSurface(Mesh,k)
For index=0 To CountVertices(surf)-1
newx#=VertexX(surf,index)+VertexNX(surf,index)*Animation
newy#=VertexY(surf,index)+VertexNY(surf,index)*Animation
newz#=VertexZ(surf,index)+VertexNZ(surf,index)*Animation
VertexCoords surf,index,newx,newy,newz
Next
Next
If (Recursive)
For i = 1 To CountChildren(Mesh)
	Breathe(GetChild(Mesh,i),True,Animation)
Next
End If
End If
End Function



_PJ_(Posted 2009) [#14]
meh. Stoopid double post.


Guy Fawkes(Posted 2009) [#15]
Malice! ur right! thanks for the contribution! if u guys could modify this code to STOP AFTER the model breathes and it changes the vertex, u COULD create a code that can grow muscles on a character! :D

I thought of it last night! :D


Guy Fawkes(Posted 2009) [#16]
Also, if u could do this, like edit the code, so that u can select which joint to use the breath code, so i could like select the stomach of my model, and it would breathe. :)

because the way the code is now, my model acts like a balloon... lol


Warner(Posted 2009) [#17]
How should the function know which bone you need? By it's name, or it's handle?


Guy Fawkes(Posted 2009) [#18]
probably handle. because the name can be anything. unless theres a way to detect that..


_PJ_(Posted 2009) [#19]
I have no clue about bones and all that malarkey ;)

But certainly, you should only need to call the function a set number of times to 'breathe' to a limit, effecti vely you would have somewhere:

If TimeToBreathe()
For f=1 to BreatheLimit
Breathe(Mesh,blah,blah)
Next
End If


Perhaps some other parameter could be introduced to specify whether "breathe in / out" ?


Guy Fawkes(Posted 2009) [#20]
hmm.. warner, what do u think?


_PJ_(Posted 2009) [#21]
Ooooh Nope. Actually, that's bad. Probably better to keep a track somewhere of the "Amount Of Breathing Done" - ratehr than have for/next loops running BEFORE any rendering.


Guy Fawkes(Posted 2009) [#22]
true. warner, again, what do u think?


_PJ_(Posted 2009) [#23]
Ah.. I see the am (Animation) parameter controls the direction, is that right?

I p[roriginally just assumed it was something to do with animation frames!


Guy Fawkes(Posted 2009) [#24]
yes. am controls it.


Warner(Posted 2009) [#25]
@malice, That parameter determines how much a vertex should be moved forward. "Forward" is then the direction of the vertex normal. VertexNX,NY,NZ. It is an (x,y,z) vector that indicates which direction a triangle/face faces. It is commonly used for lighting. So it is in fact the normal combined with this paramter that indicates the direction.

@dsw, I was just thinking sort of out loud. In fact, a bone is assigned to a set of vertices, with a percentage that indicates how much the vertices should be affected by the bone. That information is normally not available in Blitz, not without 'hacking certain properties' (topic title).
I'm not sure, and I have no model to try it on, but you could try scaling the bone. For instance, as a first step, like this:
ScaleEntity bone, 2, 1, 1
That should affect the part of the vertex that is assigned to the bone.
I'm not sure how it works internally, maybe the bone/vertex animations are performed in UpdateWorld, so you might need to place this scale command after 'UpdateWorld'.
If that is possible, you could write something that scales the bone with a Sin(), such as this:
scale# = Sin(Millisecs() / 100.0) * 0.25 + 0.5
ScaleEntity bone, scale, scale, scale

It might mess things up though, since the bones are used for animation as well, and other bones might be linked to this bone, and therefore they are affected by this scaling. Still, with some effort it should be possible to create this breathing effect.


Guy Fawkes(Posted 2009) [#26]
right. which is why i think we should have the code allow for u to select MULTIPLE limbs OR a single limb, depending on which u select :)


Warner(Posted 2009) [#27]
I don't understand that? Basically, you can't pass bones to the above function at all, since it deforms a mesh itself. I do believe that scaling a bone should be a good first step at least.


Guy Fawkes(Posted 2009) [#28]
no. i meant pass the vertex change to EACH limb, or a SELECTED limb or MULTIPLE selected limbs...


Warner(Posted 2009) [#29]
Ah, so 'limbs' in the form of a sub-mesh, and not bones, right? Then it is more easy. At the start of the function, beside checking if the entity is a mesh, also check what the name of the entity is.
Ie: If (EntityClass(mesh) = "Mesh") and (EntityName$(mesh) = "Cube01")


Guy Fawkes(Posted 2009) [#30]
well. yes. instead of changing the vertex of bones, change the vertex of the selected joint(s) depending on what u want to do :)


_PJ_(Posted 2009) [#31]
I admit I don't know much at all about boned meshes and allt hat, but aren't joints just a form of pivot, i.e. they have no geometry (verts)

 If (EntityClass(mesh) = "Mesh") and (EntityName$(mesh) = "Cube01") 


I think if that' the route this idea is to take, then a 'generalised' breathe function for all becomes pretty much redundant.
Perhaps looking at it the other way and selecting the individual parts of the mesh (bones or whatever) elsewhere before calling a function to just change the verts, essentially, we're back to square 1

Oversimpliified pseudo code:
Function TakeBreath(Mesh)

Select Mesh
Case=MyMesh1
Breathe(Bone11)
Breathe(Bone12)
Breathe(Bone13)
Exit
Case=MyMesh2
Breathe(Bone21)
Breathe(Bone22)
Breathe(Bone23)
Exit
Default
End Select
End Function



Guy Fawkes(Posted 2009) [#32]
so what should we do?


Warner(Posted 2009) [#33]
First, a testing model would be practical.


Guy Fawkes(Posted 2009) [#34]
use markio/mariorun.x inside the castle folder. thats what i did :)


Guy Fawkes(Posted 2009) [#35]
how did it go?


_PJ_(Posted 2009) [#36]
I like the idea of using Sin, that way both the change between breathing in and out PLUS the 'limit' on how "much each breath 'is' " is taken care of with the one command.

I'm still having a few issuers trying to find a reasonable coefficient multiplier though. Of course, this is all extremely dependant on the particular size of the mesh (note: not the scale, however)


Guy Fawkes(Posted 2009) [#37]
i see. so just let us know when u figure it out.


Guy Fawkes(Posted 2009) [#38]
figure it out yet?