About Monkey 2 › Forums › Monkey 2 Programming Help › Mojo3D Vertex animation/morphing – how?
This topic contains 11 replies, has 3 voices, and was last updated by
Diffrenzy
1 year, 6 months ago.
-
AuthorPosts
-
October 2, 2017 at 8:09 am #10927
I’d like to morph between two (or more) sets of vertices, keeping the triangles intact.
I’m adding the vetices myself, so I haver their indexes.
How would I go about this?
October 2, 2017 at 3:45 pm #10936I tried something but I did not get any results, whoever wants to continue the search I will mention the details.
I went to mojo3d.graphics.mesh and I added this method (after the TransformVertices):
Monkey123456789101112131415Method TransformVertex(index:Int, position:Vec3f)If index > 0 Or index < _vbuffer.LengthReturnEndLocal matrix := New AffineMat4f(position)Local vertices := Cast<Vertex3f Ptr>(_vbuffer.Data)Local cofactor := matrix.m.Cofactor()vertices[index].position=matrix * vertices[index].positionvertices[index].normal=(cofactor * vertices[index].normal).Normalize()vertices[index].tangent.XYZ=(cofactor * vertices[index].tangent.XYZ).Normalize()_vbuffer.Invalidate()_dirty|=Dirty.BoundsEndThen I did a rebuild:
Monkey1mx2cc_windows makemods mojo3dAnd then at the “makequad” example I added this on the update loop.
Monkey123Local position := New Vec3f(0, 0, 0)position.X = Sin(Now()) * 100_model.Mesh.TransformVertex(0, position)Unfortunately I did not get any results, but this is how it should be done. Once I get more familiar with the inner workings of the Mojo3D I will know better, but this is the first time I every looked at it.
October 6, 2017 at 4:57 am #11005Ok, finally got around to doing something here.
The latest develop branch includes new versions of VertexBuffer and IndexBuffer and a new ‘Renderable’ entity class.
There’s also a ‘morpher.monkey2’ in mojo3d/tests dir that shows you how to create your own renderable entity classes. It’s hopefully quite sensible:
Monkey1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768Class Morpher Extends Renderable'note: meshes must have same number of vertices and same indices.'Method New( mesh0:Mesh,mesh1:Mesh,material:Material,parent:Entity=null )Super.New( parent )'get mesh vertices - don't need entire meshes'_vertices0=mesh0.GetVertices()_vertices1=mesh1.GetVertices()_material=material'create vertexbuffer'_vbuffer=New VertexBuffer( Vertex3f.Format,_vertices0.Length )'create and initialize indexbuffer'Local indices:=mesh0.GetIndices( 0 )_ibuffer=New IndexBuffer( IndexFormat.UINT32,indices.Length )_ibuffer.SetIndices( indices.Data,0,indices.Length )EndProtectedMethod OnRender( rq:RenderQueue ) overrideLocal alpha:=Sin( Now() )*.5+.5'lock vertex bufferLocal vp:=Cast<Vertex3f Ptr>( _vbuffer.Lock() )For Local i:=0 Until _vbuffer.LengthLocal v:=_vertices0[i]'interpolate positionv.position=_vertices0[i].position.Blend( _vertices1[i].position,alpha )'interpolate normalv.normal=_vertices0[i].normal.Blend( _vertices1[i].normal,alpha ).Normalize()vp[i]=vNext'invalidate all vertices_vbuffer.Invalidate()'unlock vertices_vbuffer.Unlock()'add renderoprq.AddRenderOp( _material,Self,_vbuffer,_ibuffer,3,_ibuffer.Length/3,0 )EndPrivateField _vertices0:Vertex3f[]Field _vertices1:Vertex3f[]Field _material:MaterialField _vbuffer:VertexBufferField _ibuffer:IndexBufferField _nvertices:IntEndBasically, renderers need to implement OnRender() which is passed a ‘RenderQueue’ which you can add render ops to.
A render op is basically a combination of material,instance,vertexbuffer,indexbuffer and draw count etc.
Batching render ops like this allows for multiple render passes if necessary without having to call OnRender multiple times. It also potentially allows for ‘state sorting’ (doesn’t do that yet), better instancing using GL extensions (doesn’t do that yet either), and potentially culling. The render ops are also used to render shadow maps if Renderable.CastsShadow is true.
Renderable is now used by Model, Sprite and ParticleSystem, although there’s a big kludge in there for Sprites.
OnRender is called once per camera, and will probably get a camera param at some point. It would also be possible to have a ‘baked’ renderqueue that was camera independant and didn’t have to be rebuilt all the time.
Note that custom Renderers like this must manage vertex/index buffers themselves (as above), although ‘helper’ classes could easily be added. Renderer is as simple as possible.
I also modified/simplified vertex/index buffers quite a bit. They are now (mostly) statically sized and ‘lockable’. There’s a convience Resize() in there, but they no longer act like mini-stacks, ie: no more AddVertices. Mesh should be pretty much the same though, so as long as you’ve been using tha6t you should be OK. Didn’t have to change meshprims.monkey2 anyway.
October 6, 2017 at 8:33 am #11012Wow! That is so elegant, and it just works!
In my own code, I get a “Memory Access Violation” in Mesh->Method AddVertices( vertices:Vertex3f Ptr,count:Int )
at libc.memcpy( _vertices.Data.Data+first*Vertex3f.Pitch,vertices,count * Vertex3f.Pitch )
should I make a reproducable example, or is this expected?
October 6, 2017 at 8:52 am #11013should I make a reproducable example, or is this expected?
Example please, just had a quick look and can’t see anything obviously wrong.
October 6, 2017 at 8:55 am #11014Probably my code then, something that did not use to bomb, will investigate.
October 6, 2017 at 9:55 am #11017I think I reproduced it:
Monkey1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889#Import "<std>"#Import "<mojo>"#Import "<mojo3d>"Using std..Using mojo..Using mojo3d..Class MyWindow Extends WindowField _scene:SceneField _camera:CameraField _light:LightField _model:ModelMethod New()'get scene'_scene=Scene.GetCurrent()'create camera'_camera=New Camera_camera.Near=.1_camera.Far=100_camera.Move( 0,0,-5 )'create light'_light=New Light'create quad mesh'Local vertices:=New Vertex3f[4]vertices[0].position=New Vec3f( -1, 1,0 )vertices[1].position=New Vec3f( 1, 1,0 )vertices[2].position=New Vec3f( 1,-1,0 )vertices[3].position=New Vec3f( -1,-1,0 )Local indices:=New UInt[6]indices[0]=0indices[1]=1indices[2]=2indices[3]=0indices[4]=2indices[5]=3Local mesh:=New Mesh( )mesh.AddVertices(vertices)mesh.AddTriangles(indices)mesh.AddVertices(vertices) ' <-Error here' mesh.AddTriangles(indices)mesh.UpdateNormals()'create model for the mesh'_model=New Model_model.Mesh=mesh_model.Material=New PbrMaterial( Color.Red )_model.Material.CullMode=CullMode.NoneEndMethod OnRender( canvas:Canvas ) OverrideRequestRender()_model.RotateY( 1 )_scene.Render( canvas,_camera )canvas.DrawText( "Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )EndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndOctober 6, 2017 at 10:06 am #11018.
October 6, 2017 at 8:48 pm #11027Fixed in develop branch.
October 9, 2017 at 11:16 am #11046Confimed working.:-)
I’m probably being dim, but I don’t get why you don’t have to multiply by pitch, for the destination address.
If Local first:=_vertices.Length gets the number of elements, and memcpy needs a pointer to the destination address in bytes, your original code seems correct.
October 9, 2017 at 9:01 pm #11051I’m probably being dim, but I don’t get why you don’t have to multiply by pitch, for the destination address.
Good question!
Like c/c++, monkey2 pointer addition/subtraction takes the size of the data actually pointed to into account. So ‘p+10’ where p is an int ptr will actually add 40 to p, as ints are 4 bytes long. Ditto p[10] will reference the memory at address ‘p+40’ (using [ ] with pointers is just a special type of pointer addition).
However, libc.memcpy doesn’t know anything about types, it just takes void ptrs and a byte size. Monkey2 ‘fixes’ the pointer params, but not the size so you need to premultiply it by pitch.
It might be an idea to add some ‘typed’ memcpys somewhere, eg:
Monkey1234Function t_memcpy:T Ptr( dst:T Ptr,src:T Ptr,count:Int )libc.memcpy( dst,src,count*libc.sizeof<T>() )EndThis way, you dont’t have to premultiply count by pitch, so the SetVertices code is even simpler.
October 10, 2017 at 9:07 pm #11060Thanks, I get it now, this is Pointer arithmetics.
Your ‘typed’ memcpys seems nice!
-
AuthorPosts
You must be logged in to reply to this topic.