Need advice on interacting with OpenB3D's C++ code
BlitzMax Forums/MiniB3D Module/Need advice on interacting with OpenB3D's C++ code
| ||
Hi all, I'm dabbling with Brucey's newton.mod and OpenB3D. I realise there are very few people that will fall within in this particular overlap of relatively obscure module intersections, but hope someone will 'get' this! I'm using col's method of copying matrices between OpenB3D and Newton in order to get OpenB3D entities to appear in sync with Newton's physics bodies. This works for simple demos, but if you then try to use OpenB3D commands such as EntityX/EntityYaw, etc, to retrieve the resulting positions/rotations, it doesn't work. I believe this is because these commands interact with OpenB3D's entity.cpp/entity.h internals, which aren't being updated by the matrix copies. Take the example of calling EntityX to get a physics object's x-position: the BMX EntityX wrapper, in a round-about way, calls Entity::EntityX, located within entity.cpp: entity.cpp: ... float Entity::EntityX(int global){ if(global==false){ return px; }else{ return mat.grid[3][0]; } } ... This returns part of the internal matrix if you request the global parameter (which you would do where you need the position of a child entity in world space), but, in the more common case of obtaining a 'parent' or 'childless' entity's position using the default 'false' global parameter -- eg. you're just interacting with a basic cube -- it returns an internal 'px' field. This can be seen in the definition of the Entity class, along with some scale, rotation and (quaternion?) equivalents: entity.h: class Entity{ public: // static entity list static list<Entity*> entity_list; // relations list<Entity*> child_list; Entity* parent; // transform Matrix mat; Matrix rotmat; float px,py,pz; float sx,sy,sz; float rx,ry,rz; float qw,qx,qy,qz; ... As you can see, these are updated by the likes of MoveEntity: entity.cpp: ... void Entity::MoveEntity(float mx,float my,float mz){ rotmat.TransformVec(mx,my,mz); //transform point by internal matrix px = px + mx; //add to position py = py + my; pz = pz + mz; MQ_Update(); } ... For focus, let's just assume I want to call EntityX to get a B3D entity's x-position after I've updated its matrix from the Newton matrix: because updating the matrix doesn't update px, py, pz, the result of EntityX is incorrect. Can anyone suggest an appropriate way to update these fields without too much fuss/meddling with OpenB3D internals? I suppose I could add some functions to entity.cpp and call them from an intermediary bmx/cpp wrapper, but I'm not convinced I'll be able to figure out the matrix stuff (eg. I've no idea what the equivalent of return mat.grid[3][0] would be for local co-ordinates!) and it's not ideal, having to break from the 'standard'. In short, I need a way to also update px/px/pz and the sx, rx, qx equivalents when updating the B3D matrix from the Newton matrix, so that EntityX then works! I'm thinking a wrapper between Newton and B3D, but suspect that trying to import entity.h/cpp is just going to be a nightmare of dependencies and ultimate failure... |
| ||
I'm thinking a wrapper between Newton and B3D... I'd be inclined to agree. |
| ||
For focus, let's just assume I want to call EntityX to get a B3D entity's x-position after I've updated its matrix from the Newton matrix Can anyone suggest an appropriate way to update these fields Unfortunately I know nothing about Newton or OpenB3D. If the problem arises with a parent/child relationship then what did that Newton matrix represent? Does Newton know about this? Perhaps you could work around the problem by temporarily breaking the parent/child bond, updating from Newton and then reparenting. Maybe everything will be magically updated. It's worth trying a few variations on this theme before embarking on the much more arduous wrapper quest. |
| ||
How about extracting the euler angles from the matrix that newton returns and apply the rotation and position using the regular commands? I think I did mention it very briefly in your original thread ;-) I can't get NG to build at the moment but here are a couple of links that may help in the meantime Euler angles from 4x4 transformation matrix Extracting euler angles |
| ||
Thanks, guys -- might be a bit advanced for me, col, but I'm at work on a bank holiday, so will at least have a read! Floyd, nice thinking -- I'll have to look and see if ParentEntity (EntityParent?) does anything to these internals, might be an option. > I'm thinking a wrapper between Newton and B3D... I'd be inclined to agree. Yeah, I think writing out the problem at least made clear I need to have a go-between of some sort. Might dabble with importing entity.cpp/h into a C++ file and seeing if I can get Blitz to play, but I'm useless with this stuff and expect endless 'xyz not found/defined/whatever' errors! However I do it, I suppose I can just override the EntityX and co methods/functions in my proxy/wrapper thingy anyway. Not sure how to do that in C++ if I need to, but I guess I'll figure that out. Thanks again! |
| ||
The priority is to get a simple setup that you can debug and try different things. This is matrix math and will take some trial and error. There's this function in entity.cpp, MQ_GetMatrix, it transforms the matrix you give it from identity (null) to the transformation stored in the translation px,py,pz, the scale sx,sy,sz and the rotation in the 'rotmat' matrix (which seems to be a clean matrix with just rotation values). What you need is to create a function "MQ_SetMatrix" that does the opposite, it overwrites the matrix of the entity and also fills in those px,py,pz, sx,sy,sz and rotmat properties all based on an input matrix that you send to the function. This matrix that you use with MQ_SetMatrix is the one that comes from Newton. You also need to expose that MQ_SetMatrix function to BlitzMax code so you can call it from there, from the Newton update callbacks or whatever place you're required to do this. |
| ||
In these 4x4 matrices used for 3D transformations (linear algebra), the scale and rotation are usually represented by the same vectors: The rotation is represented by three vectors, each pointing in the X, Y and Z directions that you want the entity to be rotated to. If these vectors are not all orthogonal you can get warping effects like shear etc. The scale is encoded into these rotation vectors as their length (default length is 1.0). So if you look at the entity.cpp MQ_GetScaleXYZ function, it does just that, it gets the length of the X, Y and Z rotation vectors: https://github.com/markcwm/openb3d.mod/blob/f152c0280812508814e7bf81f336eacf7d9b65cd/openb3dlib.mod/openb3d/src/entity.cpp#L1434 That function actually transforms 3 vectors by the entity matrix and gets the length of those, I'm not sure why it doesn't get the length of the rotation vectors of the matrix directly. This is why you need to setup a debug environment, because it's small things like these that you'll have to test until getting right. Good luck. |
| ||
Thanks, Kryzon, that looks really helpful. Not had chance to play around yet, but this stuff ought to help me big time! |
| ||
Finding the wrapper approach impossible! Given the OpenB3D wrapper is effectively dead, just going to hack away at my working version, currently attempting MQ_SetMatrix. So far, major job just getting a dummy 'return 1' version implemented! (Stop chuckling, Brucey, it's rude.) Had to update all of: openb3d.mod\openb3dlib.mod\openb3d\src\entity.cpp openb3d.mod\openb3dlib.mod\openb3d\src\entity.h openb3d.mod\openb3dlib.mod\methods.cpp openb3d.mod\openb3dlib.mod\methods.h openb3d.mod\openb3dlib.mod\openb3dlib.bmx openb3d.mod\openb3dex.mod\inc\TEntity.bmx That's working, though -- can call it from a test program -- so at least I have the basic interaction going and can now faff about attempting to get values out of the matrix. |
| ||
Good going, you imported that function from C++ to BlitzMax. As for the body of MQ_SetMatrix, if you're looking for ideas: |
| ||
Kryzon, that's amazing, thanks! I realise it may need some tweaking still, but hopefully will point me in the right direction for some trial-and-error based fumbling. If I can get the right results from this, the adding of relevant C++ functions and wrapping into BlitzMax shouldn't be too much a problem. Thanks again! |
| ||
Kryzon, I... I think I love you! Finally got to sit down with this, and although I need to do something about the nasty temp:TMatrix here, EntityX/Y/Z at least now work. Turned out I had to keep the matrix copy operation in the Newton body callback code below, then comment out mat.Overwrite( inputMatrix ) in matrix.cpp, otherwise it kept failing in various ways. Might investigate that further, but at least I know I can get the correct result now, so thanks a million! Amazing that your code basically just worked! ' Fill in OpenB3D's TEntity.mat[:TMatrix].grid from Newton TNMatrix... Method AlignEntity:Int (matrix:Float Ptr) MemCopy mesh.mat.grid, matrix, 64 Local temp:TMatrix = TMatrix.CreateObject (TEntity.GetInstance (Self.mesh)) temp.grid = matrix mesh.MQ_SetMatrix temp End Method |
| ||
OK, EntityPitch/Roll/Yaw don't quite work (well, EntityPitch seems to work, the others basically give -0.0 or 180.0), but I might be able to figure this out, as I see you do something with the rotmat thing in the C++ code... |
| ||
Hi. If Newton gives you a float array then it might be better to pass that along to MQ_SetMatrix and avoid having to create that 'temp' TMatrix BlitzMax object which I think has to be garbage collected. Your AlignEntity function will be called each frame for several objects, so it needs to be fast. So something like this (renamed the function to something more appropriate): void Entity::MQ_ApplyNewtonTransform( const float* newtonMatrix ) { memcpy( mat.grid, newtonMatrix, 64 ); ...Once this is working (your OpenB3D object is being controlled by Newton) then you can focus on getting the px,py,pz etc. values working. |
| ||
Hi Kryzon, meant to reply to this 3 weeks ago, sorry! I think I've got it working now (after several aborted attempts since your post), but I wondered if you might be able to check my logic at some point? I implemented your MQ_ApplyNewtonTransform in "openb3d.mod\openb3dlib.mod\openb3d\src\entity.cpp" after I accidentally got EntityPitch & co working -- basically by changing the Pitch/Yaw/Roll matrix that was being used, from: // Pitch (X vector). if ( sx != 0.0 ) { rotmat.grid[0][0] = inputMatrix.grid[0][0] / sx; rotmat.grid[0][1] = inputMatrix.grid[0][1] / sx; rotmat.grid[0][2] = inputMatrix.grid[0][2] / sx; ... to: // Pitch (X vector). if ( sx != 0.0 ) { rotmat.grid[0][0] = mat.grid[0][0] / sx; rotmat.grid[0][1] = mat.grid[0][1] / sx; rotmat.grid[0][2] = mat.grid[0][2] / sx; } The logic here is that I've overwritten the entity's matrix with the Newton matrix at the start of MQ_ApplyNewtonTransform using: memcpy( mat.grid, newtonMatrix, 64 ); ... so I'm now working with the updated mat.grid when getting the pitch/roll/yaw. Your comments mentioned "Update the BlitzMax (wrapper) matrix?" at the end, suggesting it be updated from the Blitz side, but as far as I can tell, this isn't necessary, since overwriting mat.grid and updating rotmat.grid has effectively done this anyway. Does this make sense? This is my current newton.mod and openb3d.mod with a test program (in "newtonb3d_testing"): http://www.hi-toro.com/blitz/newtonb3d.7z The example seems to suggest it's working -- if you hold the space bar it manually aligns a semi-transparent cube based on the Newton cube's resulting EntityX/Y/Z and EntityPitch/Roll/Yaw. MQ_ApplyNewtonTransform is called from "NewtonB3D\newtonb3d_testing\hitoro.mod\newtonb3d.mod\newtonbody.bmx" -> AlignEntity, BTW. NB. If you try the archive, it's ~30 MB that expands to over 330 MB! I didn't want to try to remove all of the built parts of the module, but on the plus side, it should avoid having to rebuild if you select x86 builds! (EDIT: Er, on Windows anyway... ) |
| ||
Hi. You're right, it's not necessary to change anything in the BlitzMax module after updating the matrix, it only uses the C++ object, it doesn't have its own unique matrices etc. I tried to run the example you posted but it seems to be BlitzMax NG, so my vanilla Max complained about things (those are cool things though, like overloading the New method, using Public and Private inside types etc.). I read the code and found nothing off, so hopefully it's working right. |
| ||
Thanks for having a look, appreciate it -- it does seem to be working well so far. I might have a go at making it vanilla Max-compatible, not sure if that's even possible while using the NG features, though! Thanks again. |
| ||
Hmm, you can use easily ?bmxng to wrap NG-only stuff, which works fine, eg:Type XYZ ?bmxng Private ? ?bmxng Public ? ... End Type ... but it looks like newton and openb3d can't build on vanilla Max anyway... unless I'm doing something stupid. |
| ||
Been playing about with this -- little executable demo* in this archive (in examples folder), along with my WIP Newton/OpenB3D go-between source, which is still just me messing about: http://www.hi-toro.com/blitz/newtonb3d/newtonb3d.zip - Checked with VirusTotal * Built for x86 Windows only, physics running at 120 fps to accommodate fast-moving 'bullets'. ![]() Fun stuff: add/remove ground, spawn cubes/spheres with -/+, shoot them out of the sky with Space (or shoot the wall), reset all with R. BTW, Kryzon, your MQ_ApplyNewtonTransform is currently as below -- I've kept the scaling stuff just in case it turns out to be needed for scaled entities, but currently working great with just this: void Entity::MQ_ApplyNewtonTransform( const float* newtonMatrix ){ memcpy( mat.grid, newtonMatrix, 64 ); float tempPX, tempPY, tempPZ; tempPX = mat.grid[3][0]; tempPY = mat.grid[3][1]; tempPZ = mat.grid[3][2]; if ( parent != NULL ) parent->mat.TransformVec( tempPX, tempPY, tempPZ, 1 ); px = tempPX; py = tempPY; pz = -tempPZ; } |
| ||
Thank you for sharing, real-time physics is a nice addition to OpenB3D. |
| ||
Well, Brucey did the hard part (besides the Newton Dynamics guys)! I'm just wrapping up some functions for ease of use. Once I have a decent setup I'll put my slightly modified modules on Github, will be a while yet, though, as you can probably tell by my progress so far! If anyone wants another dump of my current progress in the meantime, just shout. |