Gamestudio Links
Zorro Links
Newest Posts
folder management functions
by VoroneTZ. 04/16/24 11:18
lookback setting performance issue
by 7th_zorro. 04/16/24 03:08
zorro 64bit command line support
by 7th_zorro. 04/15/24 09:36
Zorro FIX plugin - Experimental
by flink. 04/14/24 07:48
Zorro FIX plugin - Experimental
by flink. 04/14/24 07:46
LPDIRECT3DCUBETEXTUR
E9

by Ayumi. 04/12/24 11:00
Sam Foster Sound | Experienced Game Composer for Hire
by titanicpiano14. 04/11/24 14:56
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
7 registered members (VoroneTZ, 11honza11, ricky_k, Nymphodora, rki, 7th_zorro, Volkovstudio), 433 guests, and 2 spiders.
Key: Admin, Global Mod, Mod
Newest Members
11honza11, ccorrea, sakolin, rajesh7827, juergen_wue
19045 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
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 Offline OP
User
EpsiloN  Offline 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 grin ). 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() :
Code:
...
	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 :
Code:
// -------------------------
// --- 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 :
Code:
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 :
Code:
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.


Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
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
C
CodeMaster Offline
Junior Member
CodeMaster  Offline
Junior Member
C

Joined: Oct 2010
Posts: 73
0110111
thanks

Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max [Re: CodeMaster] #453688
08/08/15 14:58
08/08/15 14:58
Joined: Apr 2005
Posts: 1,988
Canadian, Eh
DLively Offline
Serious User
DLively  Offline
Serious User

Joined: Apr 2005
Posts: 1,988
Canadian, Eh
Wow!
do you think you could put it in a zip file so i'd just have to run it to test it out? laugh

Thanks for this contribution laugh


A8 Pro 8.45.4
YouTube: Create Games For Free
Free Resources: www.CGForFree.com
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max [Re: DLively] #453709
08/09/15 08:52
08/09/15 08:52
Joined: Apr 2005
Posts: 795
U.S.A. Michigan
exile Offline
User
exile  Offline
User

Joined: Apr 2005
Posts: 795
U.S.A. Michigan
Great contribution as always EpsiloN. Thanks and keep up the good work!

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 Offline OP
User
EpsiloN  Offline 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 laugh


Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
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 Offline
Serious User
txesmi  Offline
Serious User

Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
Hi,
there is a big missunderstanding on your code.

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.

Code:
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.

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 Offline OP
User
EpsiloN  Offline OP
User

Joined: Jan 2006
Posts: 968
I'm still learning the syntax of Lite-C grin

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 laugh

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. laugh


Extensive Multiplayer tutorial:
http://mesetts.com/index.php?page=201
Re: Posing - Bone rotation with Gizmos similar to 3D Studio Max [Re: EpsiloN] #453979
08/21/15 21:56
08/21/15 21:56
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
txesmi Offline
Serious User
txesmi  Offline
Serious User

Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
Go hard! grin

My best wishes on your way,
txes


Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1