ScaleMesh() Question
Blitz3D Forums/Blitz3D Programming/ScaleMesh() Question
| ||
I've been using ScaleMesh() to move to 'origin' of a mesh to its centre/bottom. (Simply to centre the mesh, scaling doesn't actually matter.) It's been working fine. Now I want to do the same with hierarchical meshes (with child entities) and unfortunately MeshWidth() etc returns -2000000 or some such number. I then tried to recurse through the children but of course scaling each of those meshes just produces nonsense. Bearing in mind that the meshes are not my own (else there'd be no problem) but imported, does anyone have a technique or piece of code for doing this? |
| ||
To center a mesh I wouldn't use scaleMEsh at all, instead I'd use FitMesh: Fitmesh mesh, -meshwidth(mesh)/2.0,-meshheight(mesh)/2.0,-meshdepth(mesh)/2.0,meshwidth(mesh),meshheight(mesh),meshdepth(mesh) But of course, you still need to use MeshWidth here. Once upon a time I used a radical method that used simple cubes and MeshesIntersect, so the cube did a binary search of the start and end of the mesh in x,y and z. If you compare this with the logical position of the entity, you'll know'll how you need to PositionMesh the children to center the entire thing. Of course, a complicated method. |
| ||
That's easy for you to say - you're THE jfk! Seriously, that's beyond me. I guess from what you're saying is that simply doing x = EntityX(childmesh1) etc for each child, then changing the positions based on that original info is not going to work. Else you would have done it? In fact, will x = EntityX(childmesh1) actually work? - I think I know ahead of time that it will return a message of 'childmesh1 is not an entity'. It's a simple idea - changing the origin/rotation point of a mesh to centre/bottom for easier manipulation. ScaleMesh or FitMesh allow this, no problem, but not if there are children. This really is a stinker. |
| ||
Sorry. I'm just going to bump this once in the hope that someone can help me. How can I centre a hierarchical mesh in the same way that we can centre a single mesh using FitMesh() or maybe another way? |
| ||
2 Kludges I know but... You could traverse the children and modify each ones vertices directly to scale them. Or you could traverse the mesh, copy each child, scale them, addmesh them to a new mesh and delete the original mesh (containing all the children) after you have finished...this probably destroys the hierarchy though =/ [Edit] This appears to work for me but then I may have got hold of the wrong end of the stick...wouldn't be the first time. Function Mesh_Scale(mesh%) Local childcount%=CountChildren(mesh%) Local child%=0 ;use either ScaleMesh mesh%,Rnd(2)+1,1,Rnd(2)+1 ;or ;If childcount%=0 ScaleEntity mesh,Rnd(2)+1,1,Rnd(2)+1 For child%=1 To childcount% Mesh_Scale(GetChild(mesh%,child%)) Next End Function |
| ||
PositionMesh works better. |
| ||
Yeah, I tried the recursive style you use Shambler, but since the logic was 'find the centre/bottom of the mesh', which therefore became 'each mesh', then the table top ended up on the floor (-well, that _is_ logical). Wish it was that simple. PCD Guy, FitMesh() allows positioning within the call, so that wasn't the problem. Since in my app I want to be able to allow the import of eg .3DS files then tweak them to move the 'origin/rotation' point from whereever is was originally to bottom/centre, I was doing fine on single meshes, but hierarchical meshes defeat me. When I try to think it through I get a headache. I must admit I dread that the only answer is to do it vertex by vertex - I just hope someone has a simpler way. |
| ||
Are you talking about animated meshes here, or just a bunch of meshes parented together? MeshWidth() etc returns -2000000 or some such number. Really? I just tried it on some cubes parented together and it seems to work. Are you saying MeshWidth() has a bug? |
| ||
I had recent experience of this and yes MeshWidth/Height/Depth all returned something like -2000000 for the root node of a mesh loaded with LoadAnimMesh. Regarding the scalemesh on child entities...I think the mesh I used each child was parent to a pivot at the centre of that child...so you could try 1) Store the childs parent 2) Parent the child to a temporary pivot 3) Scalemesh 4) Parent the child back to its original parent 5) Delete the temporary pivot |
| ||
Thanks for confirming that Shambler. I think you've described the obvious way to handle this (temporary pivots). I'll give it a go, and let you know. |
| ||
Well, it's tearing hair out time! I've simulated a hierarchical mesh by parenting 3 cubes to a sphere. Then I try to get the position of each child (before I even begin to investigate Shambler's idea), and lo! X,Y,Z all return zero! How insane is that? It doesn't matter whether I use the True or False flag as you see below. Please feel free to tell me I'm an idiot, but why can't I get the x,y,z of the children? Graphics3D 800,600 SetBuffer BackBuffer() camera=CreateCamera() PositionEntity camera, 0,0,-5 light=CreateLight() AmbientLight 200,200,200 Global piv = CreateSphere() : EntityColor piv,255,255,0 : EntityAlpha piv,0.5 Global cube1=CreateCube() : EntityColor cube1,255,0,0 : EntityAlpha cube1,0.5 Global cube2=CreateCube() : EntityColor cube2,0,255,0 : EntityAlpha cube2,0.5 Global cube3=CreateCube() : EntityColor cube3,0,0,255 : EntityAlpha cube3,0.5 PositionMesh cube1, 1,1,1 PositionMesh cube2, 3,3,3 PositionMesh cube3, 5,5,5 EntityParent cube1,piv EntityParent cube2,piv EntityParent cube3,piv While Not KeyDown(1) TurnEntity piv,1,1,1 UpdateWorld RenderWorld info(piv) Flip Wend End ;------------------------- Function info(piv) ;------------------------- Local x#,y#,z# Color 255,255,255 x# = EntityX#(piv) y# = EntityY#(piv) z# = EntityZ#(piv) ty = 0 : Text 0,ty,"Piv "+x#+" "+y#+" "+z# cc = CountChildren(piv) For c = 1 To cc childent = GetChild(piv,c) x# = EntityX#(childent,False) y# = EntityY#(childent,False) z# = EntityZ#(childent,False) ty = ty + 20 : Text 0,ty,Str$(c)+"false "+x#+" "+y#+" "+z# x# = EntityX#(childent,True) y# = EntityY#(childent,True) z# = EntityZ#(childent,True) ty = ty + 20 : Text 0,ty,Str$(c)+"true "+x#+" "+y#+" "+z# Next End Function |
| ||
but why can't I get the x,y,z of the children? Because you're using PositionMesh instead of PositionEntity. PositionMesh moves all the verts - the the mesh origin stays where it is, hence EntityX/Y/Z all equal zero. :) |
| ||
Understood, Big10p. Ok, forget my last post. Let's simplify it. Here's a hierarchical table mesh. I can get the children and recolor them. But EntityX() etc is telling me that the positions of each child as regards the parent are all the same! |
| ||
You have to use the global flag for Entityx/y/z i.e. EntityX(mesh%,1) [Edit] Just read your post properly and you are using true...must have another think about this one lol [Edit] Like big10p says, if you use positionentity then it should work. |
| ||
Shambler, as I said forget that last code. Instead I've loaded in a 3rd party table whch more correctly illustrates the situation: the x,y,z of each child are meaningless. |
| ||
OK, people, I think I've cracked it. This code can centre a hierarchical (multi-child) mesh, either dead-centre on 3 axes, or centred on x,z aligned to y-bottom. A portion of Mr Pickelsworth's code from the archive has been used (thanks Mr.P) I certainly wouldn't mind if a few people tried this out in situ, before I post it in the code archives. As usual, thanks to everyone who chipped in on this one. ; ; Usage: CentreAnimMesh(mesh[,0/1]) ; ;-------------------- Function CentreAnimMesh(mesh,mode=0) ;-------------------- ; mode=0 : centre on 3 axes ; mode=1 : centre on x,z; align to y bottom Local origx#,origy#,origz# Local allx#,ally#,allz# Local newx#,newy#,newz# Local cc,c,childent,mult ; get orig position origx# = EntityX#(mesh) origy# = EntityY#(mesh) origz# = EntityZ#(mesh) ; get 'all' vertices positions allx# = MeshAllX#(mesh) If mode=0 Then ally# = MeshAllY#(mesh) If mode=1 Then ally# = MeshAllYlowest#(mesh) allz# = MeshAllZ#(mesh) ; find difference newx# = (origx# - allx#) newy# = (origy# - ally#) newz# = (origz# - allz#) ; move one or all meshes cc = CountChildren(mesh) If cc = 0 PositionMesh mesh, newx#,newy#,newz# Else For c = 1 To cc childent = GetChild(mesh,c) mult = 2 PositionMesh childent, mult * newx#,mult * newy#,mult * newz# Next EndIf End Function ;-------------------- Function MeshAllX#(parent) ;-------------------- Local LeftX#,RightX# Local cc,c,childent,vx#,x# cc = CountChildren(parent) If cc = 0 x# = MeshX#(parent) Else For c = 1 To cc childent = GetChild(parent,c) vx# = MeshX#(childent) If vx#<LeftX# Then LeftX#=vx# If vx#>RightX# Then RightX#=vx# Next x# = LeftX# + ( (RightX# - LeftX#) / Float(2) ) EndIf Return x# End Function ;-------------------- Function MeshAllY#(parent) ;-------------------- Local BottomY#,TopY# Local cc,c,childent,vy#,y# cc = CountChildren(parent) If cc = 0 y# = MeshY#(parent) Else For c = 1 To cc childent = GetChild(parent,c) vy# = MeshY#(childent) If vy#<BottomY# Then BottomY#=vy# If vy#>TopY# Then TopY#=vy# Next y# = BottomY# + ( (TopY# - BottomY#) / Float(2) ) EndIf Return y# End Function ;-------------------- Function MeshAllYlowest#(parent) ;-------------------- Local BottomY#,TopY# Local cc,c,childent,vy#,y# cc = CountChildren(parent) If cc = 0 y# = BottomMost#(parent) Else For c = 1 To cc childent = GetChild(parent,c) vy# = BottomMost#(childent) If vy#<BottomY# Then BottomY#=vy# If vy#>TopY# Then TopY#=vy# Next y# = BottomY# + ( (TopY# - BottomY#) / Float(2) ) EndIf Return y# End Function ;-------------------- Function MeshAllZ#(parent) ;-------------------- Local BackZ#,FrontZ# Local cc,c,childent,vz#,z# cc = CountChildren(parent) If cc = 0 z# = MeshZ#(parent) Else For c = 1 To cc childent = GetChild(parent,c) vz# = MeshZ#(childent) If vz#<BackZ# Then BackZ#=vz# If vz#>FrontZ# Then FrontZ#=vz# Next z# = BackZ# + (FrontZ# - BackZ#)/ 2 EndIf Return z# End Function ;------------------------------------------------------------------------------------ ;-------------------- Function MeshX#(mesh) ;-------------------- Local LeftX#,RightX# Local s,su,v,vx#,x# For s = 1 To CountSurfaces(mesh) su = GetSurface(mesh,s) For v = 0 To CountVertices(su)-1 vx# = VertexX#(su,v) If vx#<LeftX# Then LeftX#=vx# If vx#>RightX# Then RightX#=vx# Next Next x# = LeftX# + ( (RightX# - LeftX#) / Float(2) ) Return x# End Function ;-------------------- Function MeshY#(mesh) ;-------------------- Local BottomY#,TopY# Local s,su,v,vy#,y# For s = 1 To CountSurfaces(mesh) su = GetSurface(mesh,s) For v = 0 To CountVertices(su)-1 vy# = VertexY#(su,v) If vy#<BottomY# Then BottomY#=vy# If vy#>TopY# Then TopY#=vy# Next Next y# = BottomY# + ( (TopY# - BottomY#) / Float(2) ) Return y# End Function ;-------------------- Function MeshZ#(mesh) ;-------------------- Local BackZ#,FrontZ# Local s,su,v,vz#,z# For s = 1 To CountSurfaces(mesh) su = GetSurface(mesh,s) For v = 0 To CountVertices(su)-1 vz# = VertexZ#(su,v) If vz#<BackZ# Then BackZ#=vz# If vz#>FrontZ# Then FrontZ#=vz# Next Next z# = BackZ# + (FrontZ# - BackZ#) / 2 Return z# End Function ;-------------------- Function BottomMost#(mesh) ;-------------------- Local BottomY#,TopY# Local s,su,v,vy# For s = 1 To CountSurfaces(mesh) su = GetSurface(mesh,s) For v = 0 To CountVertices(su)-1 vy# = VertexY#(su,v) If vy#<BottomY# Then BottomY#=vy# If vy#>TopY# Then TopY#=vy# Next Next Return BottomY# End Function |
| ||
coolio John, Well done - Mr. Tenacious! :) IPete2. |
| ||
Thanks Pete. I've tested it on a few different models tonight, and it seems fine. It works on both hierarchical and non-hierarchical meshes. Err... so I think - job done. |