3 registered members (frutza, Quad, AndrewAMD),
385
guests, and 1
spider. |
Key:
Admin,
Global Mod,
Mod
|
|
|
Posing - Bone rotation with Gizmos similar to 3D Studio Max
#453518
07/30/15 08:22
07/30/15 08:22
|
Joined: Jan 2006
Posts: 968
EpsiloN
OP
User
|
OP
User
Joined: Jan 2006
Posts: 968
|
Here's a script to rotate bone joints with gizmos (like in 3D Studio Max for example). Before anything, you should know this... All bones rotate with local angles, which means, if you rotate the shoulder, the elbow points in a different direction, but its local orientation remains the same! There is a function to get the bone orientation, but it returns the absolute orientation, not the local one! By using local_pan/tilt/roll skills and manipulating them each time we rotate a bone, we can keep track of the local angles of a joint. As a side note, its not implemented yet, but we could use a temp vector to store the local bone orientation before the wait(1) in the while loop of the gizmo. Then, when the loop begins again, we can check if this local angle changed and update the bone local angle too. This way we can set a bone's local orientation to a certain value outside of the gizmo function (for example, writing rShoulderGizmo.local_pan = 45, which will set the gizmo and bone local orientation to 45 degrees.) Just bonerotate if the old (before wait(1)) angles are different than the next iteration... In the main function, create an entity with puppet_act function, start the gizmoController() function and start propagate_rotation() which will update the gizmo orientation and local angles down the chain for every joint. The puppet_act function initializes the gizmos, meaning, it saves all joint positions, all bone handles and 'bias' between actual bone orientation and local bone orientation. It is not currently used, but you can use it to have the real bone orientation (where the bone is pointing). In there we create the gizmos at the specific joint position, we save the parent entity of the gizmo (puppet_act) and we save the bone handle that the gizmo controls. We also save the parent gizmo for that given gizmo, in order to orient it correctly. Function get_gizmo_parent() returns the handle of the parent gizmo if the current gizmo has a parent gizmo, otherwise 0. Function propagate_rotation() orients all gizmos to the real local angles of the bones, by adding the parent gizmos local angles up the chain. There is some problem with this, but I just noticed it, so its not fixed. When you rotate a gizmo, its child gizmos will rotate at a strange axis not following the mouse any more... Function torsoRotator() is the gizmo function (it was originally for the torso, so its not renamed yet to a more general name ). It just follows its joint x coordinates each frame and controls its FLAG2 to be ignored if another gizmo is being controlled right now... Function gizmoController() is the function that controls the gizmos when you press the left mouse button. If you hold the mouse button over the gizmo it traces to find the new point (where the mouse is) and calculates an axis perpendicular to new point and the original point (where you first clicked). It then rotates around that axis by the angle between the new and original points... If you go outside the gizmo the function builds a vector with magnitude = the distance to the last gizmo controlled (which is somewhere around the gizmo...) and then traces a vector from the gizmo's origin (x/y/z) to the mouse vector that was build. Then, it scales that new vector with magnitude gizmo.max_x (which is the radius of the gizmo if c_setminmax was called) and this last vector is the new position on the visible edge of the gizmo... Here's the code: Function main() :
...
puppet = ent_create( "HumanCasualRigged.mdl" , NULLVECTOR , puppet_act );
gizmoController();
mouse_mode = 2;
mouse_map = arrow_bmp;
while(1) {
if(mouse_right == 1) { if(mouse_mode == 2) { mouse_mode = 0; } } else { mouse_mode = 2; }
vec_set( mouse_pos.x , mouse_cursor );
propagate_rotation();
wait(1);
}
...
File def.c :
// -------------------------
// --- PUPPET AND GIZMOS ---
// -------------------------
ENTITY* puppet;
ENTITY* gizmo;
ENTITY* neckGizmoX;
ENTITY* chestGizmoX;
// Right arm
ENTITY* rsGizmoX;
ENTITY* reGizmoX;
ENTITY* rwGizmoX;
// Left arm
ENTITY* lsGizmoX;
ENTITY* leGizmoX;
ENTITY* lwGizmoX;
// Right leg
ENTITY* rhGizmoX;
ENTITY* rkGizmoX;
ENTITY* raGizmoX;
// Left leg
ENTITY* lhGizmoX;
ENTITY* lkGizmoX;
ENTITY* laGizmoX;
// Objects definitions
#define gizmoObject 1
// Gizmo properties
#define object_type skill4
#define parent_entity skill5
#define bone_handle skill6
#define local_pan skill7
#define local_tilt skil8
#define local_roll skil9
#define parent_gizmo skill40
File gizmo.c :
ENTITY* currentGizmoControlled;
function get_gizmo_parent( ENTITY* childEnt ) {
me = childEnt;
you = ent_next( NULL );
while( you ) {
if( handle( you ) == my.parent_gizmo ) {
return you;
}
you = ent_next( you );
}
return 0;
}
function propagate_rotation() {
ENTITY* parentGizmo;
ENTITY* currentGizmo;
currentGizmo = ent_next( NULL );
while( currentGizmo ) {
if( currentGizmo.object_type == gizmoObject ) {
vec_set( currentGizmo.pan , NULLVECTOR );
parentGizmo = get_gizmo_parent( currentGizmo );
while( parentGizmo ) {
ang_rotate( currentGizmo.pan , parentGizmo.local_pan );
parentGizmo = get_gizmo_parent( parentGizmo);
}
}
ang_rotate( currentGizmo.pan , currentGizmo.local_pan );
currentGizmo = ent_next( currentGizmo );
}
}
function torsoRotator() {
my.object_type = gizmoObject;
wait(1);
my.alpha = 30;
set( my , TRANSLUCENT );
set( my , UNLIT );
my.ambient = 100;
set( my , POLYGON );
vec_set( my.scale_x , vector( 0.33 , 0.33 , 0.33 ) );
wait(1);
c_setminmax( me );
ENTITY* parentEnt;
while(1) {
if( mouse_right == 1 ) { set( my , INVISIBLE ); }
else { reset( my , INVISIBLE ); }
parentEnt = ptr_for_handle( my.parent_entity );
if( parentEnt != NULL ) {
vec_for_bone( my.x , parentEnt , (long)my.bone_handle );
}
if( currentGizmoControlled != NULL ) {
if( currentGizmoControlled != me ) {
set( my , FLAG2 );
}
else {
reset( my , FLAG2 );
}
}
else {
reset( my , FLAG2 );
}
wait(1);
}
}
function gizmoController()
{
VECTOR vPos, vTarget;
ENTITY* entParent;
VECTOR vDir1;
VECTOR vDir2;
ANGLE angOld;
ANGLE localAngOld;
VECTOR vAxis;
ANGLE angRot;
while(1) {
if(mouse_left == 1) {
vec_set( vPos, camera.x );
vec_set( vTarget, mouse_dir3d );
vec_scale( vTarget, 1000 );
vec_add( vTarget, vPos );
c_trace( vPos, vTarget, IGNORE_FLAG2 );
if ( HIT_TARGET ) {
currentGizmoControlled = you;
vec_diff ( vDir1, hit.x, you.x );
vec_normalize ( vDir1, 1 );
vec_set ( angOld, you.pan );
vec_set ( localAngOld , you.local_pan );
you.alpha = 90;
while ( mouse_left ) {
vec_set ( vPos, camera.x );
vec_set ( vTarget, mouse_dir3d );
vec_scale ( vTarget, 1000 );
vec_add ( vTarget, vPos );
c_trace ( vPos, vTarget, IGNORE_FLAG2 );
if ( HIT_TARGET ) {
if ( you == currentGizmoControlled ) {
draw_point3d ( hit.x, COLOR_WHITE, 100, 1 );
vec_diff ( vDir2, hit.x, you.x );
vec_normalize ( vDir2, 1 );
vec_cross ( vAxis , vDir1 , vDir2 );
ang_for_axis( angRot, vAxis, acosv ( vec_dot ( vDir1 , vDir2 ) ) );
vec_set ( you.pan, angOld );
ang_add( you.pan, angRot );
vec_set ( you.local_pan , localAngOld );
ang_add( you.local_pan , angRot );
entParent = ptr_for_handle( you.parent_entity );
if( entParent != NULL ) {
ent_bonereset( entParent , (long)you.bone_handle );
ent_bonerotate( entParent , (long)you.bone_handle , you.local_pan );
}
}
else {
vec_set ( vPos, camera.x );
vec_set ( vTarget, mouse_dir3d );
vec_scale ( vTarget, vec_dist( camera.x , currentGizmoControlled.x ) );
vec_add ( vTarget, vPos );
vec_set( vDir2 , vTarget );
vec_sub( vDir2 , currentGizmoControlled.x );
vec_normalize( vDir2 , currentGizmoControlled.max_x );
vec_add( vDir2 , currentGizmoControlled.x );
draw_point3d ( vDir2 , COLOR_RED , 100, 1 );
vec_diff ( vDir2, vDir2 , currentGizmoControlled.x );
vec_normalize ( vDir2, 1 );
vec_cross ( vAxis , vDir1 , vDir2 );
ang_for_axis( angRot, vAxis, acosv ( vec_dot ( vDir1 , vDir2 ) ) );
vec_set ( currentGizmoControlled.pan, angOld );
ang_add( currentGizmoControlled.pan, angRot );
vec_set ( currentGizmoControlled.local_pan , localAngOld );
ang_add( currentGizmoControlled.local_pan , angRot );
entParent = ptr_for_handle( currentGizmoControlled.parent_entity );
if( entParent != NULL ) {
ent_bonereset( entParent , (long)currentGizmoControlled.bone_handle );
ent_bonerotate( entParent , (long)currentGizmoControlled.bone_handle , currentGizmoControlled.local_pan );
}
}
}
else {
vec_set ( vPos, camera.x );
vec_set ( vTarget, mouse_dir3d );
vec_scale ( vTarget, vec_dist( camera.x , currentGizmoControlled.x ) );
vec_add ( vTarget, vPos );
vec_set( vDir2 , vTarget );
vec_sub( vDir2 , currentGizmoControlled.x );
vec_normalize( vDir2 , currentGizmoControlled.max_x );
vec_add( vDir2 , currentGizmoControlled.x );
draw_point3d ( vDir2 , COLOR_RED , 100, 1 );
vec_diff ( vDir2, vDir2 , currentGizmoControlled.x );
vec_normalize ( vDir2, 1 );
vec_cross ( vAxis , vDir1 , vDir2 );
ang_for_axis( angRot, vAxis, acosv ( vec_dot ( vDir1 , vDir2 ) ) );
vec_set ( currentGizmoControlled.pan, angOld );
ang_add( currentGizmoControlled.pan, angRot );
vec_set ( currentGizmoControlled.local_pan , localAngOld );
ang_add( currentGizmoControlled.local_pan , angRot );
entParent = ptr_for_handle( currentGizmoControlled.parent_entity );
if( entParent != NULL ) {
ent_bonereset( entParent , (long)currentGizmoControlled.bone_handle );
ent_bonerotate( entParent , (long)currentGizmoControlled.bone_handle , currentGizmoControlled.local_pan );
}
}
DEBUG_VAR ( currentGizmoControlled.pan, 10 );
DEBUG_VAR ( currentGizmoControlled.tilt, 40 );
DEBUG_VAR ( currentGizmoControlled.roll, 70 );
wait(1);
}
currentGizmoControlled.alpha = 30;
currentGizmoControlled = NULL;
}
}
else {
vec_set( vPos, camera.x );
vec_set( vTarget, mouse_dir3d );
vec_scale( vTarget, 1000 );
vec_add( vTarget, vPos );
c_trace( vPos, vTarget, IGNORE_FLAG2 );
if ( HIT_TARGET ) {
if( currentGizmoControlled != NULL ) {
currentGizmoControlled.alpha = 30;
}
currentGizmoControlled = you;
you.alpha = 90;
}
else {
if( currentGizmoControlled != NULL ) {
currentGizmoControlled.alpha = 30;
currentGizmoControlled = NULL;
}
}
}
wait(1);
}
}
File puppet.c :
STRING* boneName_str = "";
function puppet_act() {
set( my , UNTOUCHABLE );
my.flags2 |= UNTOUCHABLE;
my.alpha = 50;
set( my , TRANSLUCENT );
// -------------------------
// -- GET JOINT POSITIONS --
// -------------------------
//
// *** Right body ***
// . Upper
VECTOR* rShoulder[3];
vec_for_bone( rShoulder.x , my , "RShoulder" );
VECTOR* rElbow[3];
vec_for_bone( rElbow.x , my , "RElbow" );
VECTOR* rWrist[3];
vec_for_bone( rWrist.x , my , "RWrist" );
VECTOR* rMidFingerBase[3];
vec_for_bone( rMidFingerBase.x , my , "RMidFinger" );
// . Lower
VECTOR* rHip[3];
vec_for_bone( rHip.x , my , "RHip" );
VECTOR* rKnee[3];
vec_for_bone( rKnee.x , my , "RKnee" );
VECTOR* rAnkle[3];
vec_for_bone( rAnkle.x , my , "RAnkle" );
VECTOR* rFoot[3];
vec_for_bone( rFoot.x , my , "RFoot" );
// *** Left Body ***
// . Upper
VECTOR* lShoulder[3];
vec_for_bone( lShoulder.x , my , "LShoulder" );
VECTOR* lElbow[3];
vec_for_bone( lElbow.x , my , "LElbow" );
VECTOR* lWrist[3];
vec_for_bone( lWrist.x , my , "LWrist" );
VECTOR* lMidFingerBase[3];
vec_for_bone( lMidFingerBase.x , my , "LMidFinger" );
// . Lower
VECTOR* lHip[3];
vec_for_bone( lHip.x , my , "LHip" );
VECTOR* lKnee[3];
vec_for_bone( lKnee.x , my , "LKnee" );
VECTOR* lAnkle[3];
vec_for_bone( lAnkle.x , my , "LAnkle" );
VECTOR* lFoot[3];
vec_for_bone( lFoot.x , my , "LFoot" );
// * Middle Body
VECTOR* Neck[3];
vec_for_bone( Neck.x , my , "Neck" );
VECTOR* SkullBase[3];
vec_for_bone( SkullBase.x , my , "SkullBase" );
VECTOR* Chest[3];
vec_for_bone( Chest.x , my , "Chest" );
VECTOR* Base[3];
vec_for_bone( Base.x , my , "Base" );
// ----------------------------
// -- GET JOINT ORIENTATIONS --
// ----------------------------
VECTOR* tempBiasVec[3];
// *** Right Upper Body ***
// rShoulder
ANGLE* rShoulderBias[3];
vec_set( tempBiasVec.x , rElbow.x );
vec_sub( tempBiasVec.x , rShoulder.x );
vec_to_angle( rShoulderBias.pan , tempBiasVec.x );
// rElbow
ANGLE* rElbowBias[3];
vec_set( tempBiasVec.x , rWrist.x );
vec_sub( tempBiasVec.x , rElbow.x );
vec_to_angle( rElbowBias.pan , tempBiasVec.x );
// rWrist
ANGLE* rWristBias[3];
vec_set( tempBiasVec.x , rMidFingerBase.x );
vec_sub( tempBiasVec.x , rWrist.x );
vec_to_angle( rWristBias.pan , tempBiasVec.x );
// *** Left Upper Body ***
// lShoulder
ANGLE* lShoulderBias[3];
vec_set( tempBiasVec.x , lElbow.x );
vec_sub( tempBiasVec.x , lShoulder.x );
vec_to_angle( lShoulderBias.pan , tempBiasVec.x );
// lElbow
ANGLE* lElbowBias[3];
vec_set( tempBiasVec.x , lWrist.x );
vec_sub( tempBiasVec.x , lElbow.x );
vec_to_angle( lElbowBias.pan , tempBiasVec.x );
// lWrist
ANGLE* lWristBias[3];
vec_set( tempBiasVec.x , lMidFingerBase.x );
vec_sub( tempBiasVec.x , lWrist.x );
vec_to_angle( lWristBias.pan , tempBiasVec.x );
// *** Lower Body ***
// Right side
ANGLE* rHipBias[3];
vec_set( tempBiasVec.x , rKnee.x );
vec_sub( tempBiasVec.x , rHip.x );
vec_to_angle( rHipBias.pan , tempBiasVec.x );
ANGLE* rKneeBias[3];
vec_set( tempBiasVec.x , rAnkle.x );
vec_sub( tempBiasVec.x , rKnee.x );
vec_to_angle( rKneeBias.pan , tempBiasVec.x );
ANGLE* rAnkleBias[3];
vec_set( tempBiasVec.x , rFoot.x );
vec_sub( tempBiasVec.x , rAnkle.x );
vec_to_angle( rAnkleBias.pan , tempBiasVec.x );
// Left Side
ANGLE* lHipBias[3];
vec_set( tempBiasVec.x , lKnee.x );
vec_sub( tempBiasVec.x , lHip.x );
vec_to_angle( lHipBias.pan , tempBiasVec.x );
ANGLE* lKneeBias[3];
vec_set( tempBiasVec.x , lAnkle.x );
vec_sub( tempBiasVec.x , lKnee.x );
vec_to_angle( lKneeBias.pan , tempBiasVec.x );
ANGLE* lAnkleBias[3];
vec_set( tempBiasVec.x , lFoot.x );
vec_sub( tempBiasVec.x , lAnkle.x );
vec_to_angle( lAnkleBias.pan , tempBiasVec.x );
// *** Middle Body ***
// Neck
ANGLE* NeckBias[3];
vec_set( tempBiasVec.x , SkullBase.x );
vec_sub( tempBiasVec.x , Neck.x );
vec_to_angle( NeckBias.pan , tempBiasVec.x );
// Chest
ANGLE* ChestBias[3];
vec_set( tempBiasVec.x , Chest.x );
vec_sub( tempBiasVec.x , Base.x );
vec_to_angle( ChestBias.pan , tempBiasVec.x );
// ------------------
// -- BONE HANDLES --
// ------------------
//
// *** Upper Body ***
// . Right side
var rShoulderHandle = 0;
var rElbowHandle = 0;
var rWristHandle = 0;
var rMidFingerBaseHandle = 0;
// . Left Side
var lShoulderHandle = 0;
var lElbowHandle = 0;
var lWristHandle = 0;
var lMidFingerBaseHandle = 0;
// *** Middle Body ***
var neckHandle = 0;
var chestHandle = 0;
// *** Lower Body ***
// . Right Side
var rHipHandle = 0;
var rKneeHandle = 0;
var rAnkleHandle = 0;
var rFootHandle = 0;
// . Left Side
var lHipHandle = 0;
var lKneeHandle = 0;
var lAnkleHandle = 0;
var lFootHandle = 0;
var boneHandle;
var i = 0;
for(i = 0; i < ent_bones( my ); i++ ) {
boneHandle = ent_bonehandle( my , boneName_str , i );
// Right Upper
if(str_cmpi(boneName_str,"RElbow") == 1) { rElbowHandle = boneHandle; }
if(str_cmpi(boneName_str,"RShoulder") == 1) { rShoulderHandle = boneHandle; }
if(str_cmpi(boneName_str,"RWrist") == 1) { rWristHandle = boneHandle; }
if(str_cmpi(boneName_str,"RMidFinger") == 1) { rMidFingerBaseHandle = boneHandle; }
// Left Upper
if(str_cmpi(boneName_str,"LElbow") == 1) { lElbowHandle = boneHandle; }
if(str_cmpi(boneName_str,"LShoulder") == 1) { lShoulderHandle = boneHandle; }
if(str_cmpi(boneName_str,"LWrist") == 1) { lWristHandle = boneHandle; }
if(str_cmpi(boneName_str,"LMidFinger") == 1) { lMidFingerBaseHandle = boneHandle; }
// Middle Body
if(str_cmpi(boneName_str,"Neck") == 1) { neckHandle = boneHandle; }
if(str_cmpi(boneName_str,"Chest") == 1) { chestHandle = boneHandle; }
// Lower Body
// Right Side
if(str_cmpi(boneName_str,"RHip") == 1) { rHipHandle = boneHandle; }
if(str_cmpi(boneName_str,"RKnee") == 1) { rKneeHandle = boneHandle; }
if(str_cmpi(boneName_str,"RAnkle") == 1) { rAnkleHandle = boneHandle; }
if(str_cmpi(boneName_str,"RFoot") == 1) { rFootHandle = boneHandle; }
// Left Side
if(str_cmpi(boneName_str,"LHip") == 1) { lHipHandle = boneHandle; }
if(str_cmpi(boneName_str,"LKnee") == 1) { lKneeHandle = boneHandle; }
if(str_cmpi(boneName_str,"LAnkle") == 1) { lAnkleHandle = boneHandle; }
if(str_cmpi(boneName_str,"LFoot") == 1) { lFootHandle = boneHandle; }
}
chestGizmoX = ent_create( "Sphere.mdl" , Chest.x , torsoRotator );
chestGizmoX.parent_entity = handle(me);
chestGizmoX.bone_handle = chestHandle;
neckGizmoX = ent_create( "Sphere.mdl" , Neck.x , torsoRotator );
neckGizmoX.parent_entity = handle(me);
neckGizmoX.parent_gizmo = handle(chestGizmoX);
neckGizmoX.bone_handle = neckHandle;
rsGizmoX = ent_create( "Sphere.mdl" , rShoulder.x , torsoRotator );
rsGizmoX.parent_entity = handle(me);
rsGizmoX.parent_gizmo = handle(neckGizmoX);
rsGizmoX.bone_handle = rShoulderHandle;
reGizmoX = ent_create( "Sphere.mdl" , rElbow.x , torsoRotator );
reGizmoX.parent_entity = handle(me);
reGizmoX.parent_gizmo = handle(rsGizmoX);
reGizmoX.bone_handle = rElbowHandle;
rwGizmoX = ent_create( "Sphere.mdl" , rWrist.x , torsoRotator );
rwGizmoX.parent_entity = handle(me);
rwGizmoX.parent_gizmo = handle(reGizmoX);
rwGizmoX.bone_handle = rWristHandle;
while(1) {
if( mouse_right == 1 ) { reset( my , TRANSLUCENT ); my.alpha = 100; }
else { set( my , TRANSLUCENT ); my.alpha = 30; }
wait(1);
}
}
My next goal is to implement an animation system with interpolation between key frames (saved from all local gizmo angles), but first I have to fix the rotation problem with the propagation function. When I fix it, if I dont forget, I will post the update.
|
|
|
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max
[Re: EpsiloN]
#453682
08/08/15 10:25
08/08/15 10:25
|
Joined: Oct 2010
Posts: 73 0110111
CodeMaster
Junior Member
|
Junior Member
Joined: Oct 2010
Posts: 73
0110111
|
|
|
|
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max
[Re: exile]
#453952
08/20/15 19:41
08/20/15 19:41
|
Joined: Jan 2006
Posts: 968
EpsiloN
OP
User
|
OP
User
Joined: Jan 2006
Posts: 968
|
I am sorry, I couldn't zip it all, because I'm using models which I don't have permission to share. By the way, I'm working on the keyframe system so I have something goin on, but development has been really slowed down due to me moving in a new apartment and the daily job... There is also another method of rotation, with mouse movement relative to the screen orientation, but I will post it when I have more free time to strip down the junk code
|
|
|
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max
[Re: EpsiloN]
#453955
08/21/15 00:39
08/21/15 00:39
|
Joined: Jun 2007
Posts: 1,337 Hiporope and its pain
txesmi
Serious User
|
Serious User
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
|
Hi, there is a big missunderstanding on your code.
VECTOR* rShoulder[3];
vec_for_bone( rShoulder.x , my , "RShoulder" );
'rShoulder' is an array of vector pointers. You should declare a vector struct instead.
VECTOR rShoulder; // A vector struct
vec_for_bone( rShoulder , my , "RShoulder" );
You can improve the code a lot by using data structs to allocate all the needed data. Since the bones of an entity are allocated into an array you can continue treating the data as arrays for ease and forget about specific pointers for each gizmo so you can modify any kind of bone hierarchy with a common code.
// -------------------------------------------------------------------------
// GIZMO SKILLS
// -------------------------------------------------------------------------
#define skGizmoContainer skill1
#define skEntity skill2
#define skBoneName skill3
#define skBoneHandle skill4
#define skLocalPan skill5
#define skLocalTilt skill6
#define skLocalRoll skill7
#define skChildrenCount skill19
#define MC_CHILDREN_ARRAY_BASE 20
//#define skChildren skill20<->skill92 (max of 72 bones)
// -------------------------------------------------------------------------
// GIZMOS CONTAINER
// -------------------------------------------------------------------------
typedef struct
{
int iGizmoCount;
ENTITY **entGizmo;
} ENT_BONE_GIZMOS;
ENT_BONE_GIZMOS *gizmosCreate ( ENTITY *ent )
{
if ( !ent )
return NULL;
int iBoneCount = ent_status ( ent, 14 );
if ( !iBoneCount )
return NULL;
ENT_BONE_GIZMOS *ebg = sys_malloc ( sizeof(ENT_BONE_GIZMOS) );
ebg->iGizmoCount = iBoneCount;
ebg->entGizmo = sys_malloc ( sizeof(ENTITY*) * iBoneCount );
ent_bonereset_all ( ent );
int iBoneIndex = 0;
for ( ; iBoneIndex<iBoneCount; iBoneIndex+=1 )
{
ENTITY *entGizmo = ent_create ( "gizmo.mdl", nullvector, NULL );
*(ebg->entGizmo+iBoneIndex) = entGizmo;
STRING *strBoneName = str_create ( "" );
long hdlBone = ent_bonehandle ( ent, strBoneName, iBoneIndex+1 );
entGizmo->skGizmoContainer = (ENT_BONE_GIZMOS*)ebg;
entGizmo->skEntity = (ENTITY*)ent;
entGizmo->skBoneName = (STRING*)strBoneName;
entGizmo->skBoneHandle = (long)hdlBone;
vec_set ( &entGizmo->skLocalPan, nullvector );
entGizmo->skChildrenCount = 0;
entGizmo->flags |= ZNEAR;
vec_for_bone ( &entGizmo->x, ent, hdlBone );
ang_for_bone ( &entGizmo->pan, ent, hdlBone );
long hdlParent = ent_boneparent ( ent, NULL, hdlBone );
if ( hdlParent )
{
int iParentIndex = 0;
for ( ; iParentIndex<iBoneIndex; iParentIndex+=1 )
{
ENTITY *entParent = *(ebg->entGizmo+iParentIndex);
if ( entParent->skBoneHandle != hdlParent )
continue;
entGizmo->parent = entParent;
entParent->skill[MC_CHILDREN_ARRAY_BASE+entParent->skChildrenCount] = (ENTITY*)entGizmo;
entParent->skChildrenCount += 1;
break;
}
}
else
{
entGizmo->parent = NULL;
}
}
return ebg;
}
void gizmosRemove ( ENT_BONE_GIZMOS* ebg )
{
if ( !ebg )
return;
int iBoneIndex = 0;
for ( ; iBoneIndex<ebg->iGizmoCount; iBoneIndex+=1 )
{
ENTITY *entGizmo = *(ebg->entGizmo+iBoneIndex);
str_remove ( (STRING*)entGizmo->skBoneName );
ent_remove ( entGizmo );
}
sys_free ( ebg->entGizmo );
sys_free ( ebg );
}
// -------------------------------------------------------------------------
// GIZMOS ROTATION
// -------------------------------------------------------------------------
void gizmoChildrenUpdate ( ENTITY *entGizmo, ENTITY *ent )
{
int iChildIndex = 0;
for ( ; iChildIndex<entGizmo->skChildrenCount; iChildIndex+=1 )
{
ENTITY *entChild = (ENTITY*)entGizmo->skill[MC_CHILDREN_ARRAY_BASE+iChildIndex];
long hdlChild = (long)entChild->skBoneHandle;
vec_for_bone ( &entChild->x, ent, hdlChild );
ang_for_bone ( &entChild->pan, ent, hdlChild );
gizmoChildrenUpdate ( entChild, ent );
}
}
void gizmoRotate ( ENTITY *entGizmo, ANGLE *angRotation )
{
ang_add ( &entGizmo->pan, angRotation );
ang_add ( &entGizmo->skLocalPan, angRotation );
ENTITY *ent = (ENTITY*)entGizmo->skEntity;
long hdlBone = (long)entGizmo->skBoneHandle;
ent_bonereset ( ent, hdlBone );
ent_bonerotate ( ent, hdlBone, &entGizmo->skLocalPan );
gizmoChildrenUpdate ( entGizmo, ent );
}
// -------------------------------------------------------------------------
// MAIN
// -------------------------------------------------------------------------
void main ()
{
video_mode = 10;
mouse_mode = 4;
wait(1);
level_load ( "" );
camera->x = -200;
camera->bg = pixel_for_vec ( COLOR_BLACK, 100, 8888 );
ENTITY *entModel1 = ent_create ( "knight.mdl", nullvector, NULL );
ENT_BONE_GIZMOS *ebg1 = gizmosCreate ( entModel1 );
ENTITY* entGizmo1 = *(ebg1->entGizmo+2);
gizmoRotate ( entGizmo1, vector(0,45,0) );
while ( !key_esc )
{
gizmoRotate ( entGizmo1, vector(5*time_step,0,0) );
wait(1);
}
gizmosRemove ( ebg1 );
ent_remove ( entModel1 );
sys_exit ( NULL );
}
Maybe I went too far with the example xP Hope it helps
|
|
|
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max
[Re: txesmi]
#453976
08/21/15 21:11
08/21/15 21:11
|
Joined: Jan 2006
Posts: 968
EpsiloN
OP
User
|
OP
User
Joined: Jan 2006
Posts: 968
|
I'm still learning the syntax of Lite-C I know I could have used a more generic approach (with arrays), but my first goal was to get a prototype working for a standard 3DSMax biped. I am also still (just) learning about structs, so I posted it as is while it still works I am still learning structs, so its far from done, but my goal will be to build a system with animation templates that can be plug & played on any biped model and possibly tweaked with ease in-game. Thanks for your example (I haven't tested it yet) and lets hope we could all use this for animation some day.
|
|
|
|