Game Development Community

dev|Pro Game Development Curriculum

Custom Shape Mod

by Duncan Gray · 04/03/2005 (9:43 am) · 84 comments

Download Code File

This resource still works in TGE 1.51 if you copy/past from the included pdf file.

This mod involves applying scaling factors to vertices according to the bone nodes to which they are attached. Basically you select a bone, select a scaling factor for x,y,z and those scaling factors get stored in a vector list which is instanced for each character/vehicle/shape. Additionally, the scaling is fully ghosted on the clients making it possible for each player to enter the game with his own unique character proportions, visible to all other players.

It's thus also possible to dynamically scale body proportions while mid game. So if a player bumps his head, you can make his head swell up etc.

The idea is to let the user scale his character proportions which then get saved in prefs. When he joins a game, his details get sent to the server which then ghosts the character settings to all the clients.

It's not only of use for characters. The mod is done mostly in shapebase.cc which is the base class for all shapes. Therefore, in theory, you can make trees, vehicles etc and scale sections of the shape as long as you place a "bone" in that area and assign a vertex group to the bone. You will then be able to select that bone and scale the participating verticies dynamically, at run time, from script which can add a whole new element to your game.

[Edit]

Updated the readme.txt with notes about TGE 1.4

[edit]
For a solution to the "floating above ground" problem, go here

SCREENSHOTS

[edit]
I also made an update, in the shapebase.cc section, use the following rather than the version in the pdf
ConsoleMethod( ShapeBase, setScalePerBone, void, 6, 6, "ShapeBase.setScalePerBone( x, y, z , bone-index )" )
{
	argc;
	Point3F scale;
	S32 boneNdx = dAtoi(argv[5]);
	TSShapeInstance* si = object->getShapeInstance();
	scale.set(strtod(argv[2],(char **)NULL),strtod(argv[3],(char **)NULL),strtod(argv[4],(char **)NULL));
	si->setScalePerBone( scale, boneNdx );
	char DNA[20];
	dSprintf(DNA,sizeof(DNA) ,"%03u %1.2f %1.2f %1.2f"	,boneNdx,scale.x,scale.y,scale.z);
	object->setDNA(DNA);
}

That will let you do server script based (or console) scaling by issuing the setScalePerBone(bla) command.
You don't need all the guiplayerview changes if you only want to scale from server script. Example, when a player spawns, give a random 30% scale change to relevant body parts so that all players look a little different from each other.
#21
04/19/2005 (5:17 am)
#1 I Will look and tell you whats up.
#2 Thats how I figured out this was going on.
#3 Been looking through it, just didn't have time to read every line of code.
#4 serverCmdSetDNA is located in server/scripts/commands.cs

*Update*
#1 made me think for a bit and I realized that CommandToServer('SendDNA',blah); was only being called once, and that was upon login. Anyways the fix was pretty simple, I just added the CommandToServer to OptClose and now it works fine!
#22
04/19/2005 (10:53 am)
Ok, I'm getting cranky :)
For reasons I don't really understand, opening, adjusting and closing more than once or twice in a game causes some very serious strangeness.

This may at least in part be due to my choice of animations in the optionsDlg (I have chosen to have my character dance rather than run.

Anyways, after about the second or third time I open adjust and then close, it appears to be trying to blend my dancing and running animations together as soon as I leave first person and move my mouse. Furthermore once the character begins to do this, he appears to be losing any new adjustments I make, so what I basically wind up with is an Orc who likes to poke himself in the head with his own sword. Wish I could make a movie and show you, it's actually quite funny in it's own strange sort of way.

I'm going to revert back to a non cel animation like running and see if this still occurs.

*Update*
Strangely no the above no longer occurs when I changed from dance to forward. However now my character has one leg behind him (like he's halfway through running), and moves forward and back w/o animating... He does however play his combat animations just fine. Ok back to the drawing board.
#23
04/19/2005 (1:31 pm)
Claude-Alain Fournier implemented this mod straight from the pdf and is using it in www.adellion.com without any problems.
#24
04/19/2005 (1:42 pm)
And yet I've been having problems getting it to work with Dream, no biggie most of my integration problems have come from an incomplete understanding of your code, more so than anything particulary wrong with your mod.

Incidently I think I've tracked my player freeze problem down to a bug in the way I was implementing the Mod from the very start, if I'm right hopefully this will be the last bug I encounter related to this mod.
#25
05/01/2005 (5:30 am)
This tutorial worked great with ver 1.3.
Now, I just need custom rigged .dts shapes with bones in the face, etc. and some code adjusting and I should be in business!
Has anyone used this code while in game (ie. flatten a bot with a hammer etc.)?

Ari
#26
05/01/2005 (8:02 am)
Yep, I use it all the time to enlarge and various parts of players depending on whats going on with thier stats.
#27
05/12/2005 (1:49 pm)
I managed to convert this over to the more powerful and more generic GuiObjectView for TSE (not TGE). If anyone wants it, give a shout (proof of ownership requireed). I won't detail any scripting, as its pretty much the same as Duncans work, with just a few minor changes required, so no newbies please. If you know what you're doing, and working in TSE, this file will save you an hour or two.
#28
05/26/2005 (9:44 am)
@Eric:
I happen to need this for TSE, so would you mind I drop you a mail for it. Thanks in advance.

Steven
#29
06/20/2005 (10:54 pm)
I got a small problem. If I make legs shorter or longer, it change the overall size of the model, so collision box is not anymore adapted. So with shorter legs the character float over ground, with long legs the feet stick in the ground.

Any idea how to change that ?

Otherwise I have no problem with the ressource, it work fine. There is one thing I don't like though is the fact that bone size is cumulated over the child bones, so you can't realy change a non terminal bone without affecting the child bone. This is due to the way the animation is processed by the engine, it multiply matrix.
#30
07/21/2005 (1:33 pm)
This resource crashes Torque when you change bodies numerous times. In a debug build it will give an invalid keyframe assert.
#31
11/23/2005 (10:37 pm)
This resource does not work with TGE 1.4 when you drop the engine folder over yours.

I am testing out manual modding of the files right now.

Test was a failure due to the PDF file not being specific enough in some area's.
#32
12/03/2005 (6:31 pm)
It does work with TGE 1.4 except in one area, the script section in optiondlg.cs where setmodal() uses a path consisting of $usermods

TGE 1.4 has added "creator;" to the front of the $usermods path which means you need to remove it or replace $usermods with your own mod path. Failure to do so results in a crash/hang situation.

All other C++ code is still valid for TGE1.4
#33
12/11/2005 (12:11 am)
I notice that when I run getDNA, I am only getting one value at a time. For instance I may receive "0 0.5 0.5 0.5", so when I run setDNA it is only affecting one node. I get around this by setting multiple global variables (DNA0, DNA1, DNA2, etc.), but I was under the impression that getDNA would return the information for all nodes.

Also the %client.player.setScalePerBone does not work at all (no error), and %client.player.setDNA only allows one node at a time to be changed. However when you set one node, it first resets the model to its default DNA, then sets the DNA on the node selected.

Anyone else having similar problems?

This looks very promising and you've done an excellent job. Now if we can just get around these minor errors we'll be golden! We also need to figure out how to modify the bounds because when you shrink down your character in-game, he floats in mid air.

Well done, Duncan!
#34
12/11/2005 (2:35 am)
@Robert., the basic description of what happens is as follows. Console method shapebase::setDNA takes a string of format "n x y z n x y z"etc, where n=node or bone and x,y,z are the scales 0-1 (float), and passes it ShapeBase::setDNA. ShapeBase::setDNA then sets the network skinmask flag, causing the server to pass the the above string to all its clients. When the client receives the data, it calls uploadScalePerBoneList which updates the particular shape instance with the new values.

The DNA string is stored in TSShapeInstance in an array of xyz values per node. When initialized or reset, all xyz values are set to 1. The scaling occurs during the shape instance render cycle. It simple checks the array and applies the scales.

The above is all you need to get the scale per bone part to work over a network. ALL the other console methods in the resource operate on the local copy of TSShapeInstance and were created as a convenient means of getting the various sliders in optiondlg.cs to affect changes to the scales. You don't actually need them if you don't want a gui interface for setting scales per bone.

Which of course means that if you use the sliders to affect the scales, you still need to tell the server about it so that it can replicate the changes to the other clients. For this purpose, the optiondlg.cs OptClose() function was used to create a string of scales and send them to the server.
function OptClose()
{
    PlayerView.getDNA(); // this will set the $pref::Player::DNA variable with the DNA string
    commandToServer('SendDNA', $pref::Player::DNA, $pref::Player::skin); //tell the server
}

In order to minimise network traffic, ONLY the altered scales are passed between client and server.

getDNA is a console method which calls void TSShapeInstance::getScalePerBoneList() which in turn goes through the local array and checks for any scales which are not 1 and adds them to the DNA string in the above format. The string is then used to set the $pref::Player::DNAvariable because all prefs are conveniently saved between games.

Be aware that there is another console method called setDNA, but it is a guiPlayerView method which only updates the local TSShapeInstance and not the server so make sure you use the correct setDNA in the correct place. The guiPlayerView version uses the saved $pref::Player::DNA values to set the shape scale when the optionDlg.cs onWake function is invoked so that you see what you last scale choices look like.

There are other console methods for setting and getting individual bone scales, namely setScalePerBone and getScalePerBone. All these 'local' console methods are stored in guiplayerview.cc as they are used there and only affect the client.

I hope that clears things up a bit.

For the Kyle type people, its not plug and play in 1.4 because the files included with the resource are from 1.3. Just follow the instructions in the pdf and it will work fine. I'm using it in 1.4.
#35
12/11/2005 (9:41 am)
Thanks Duncan. We used your code so I would assume that, barring any changes, it would store the entire string. Just a quick question: What would the whole string look like? Do you have an example?

We can always reconstruct it if getDNA is only returning one node. If we know the separator between the various nodes' info, then we can pass the entire string of changes to setDNA.

Thanks again!

-R
#36
01/23/2006 (1:53 am)
Fantastic resource, thanks for sharing it.

Quote:I got a small problem. If I make legs shorter or longer, it change the overall size of the model, so collision box is not anymore adapted. So with shorter legs the character float over ground, with long legs the feet stick in the ground.

Any idea how to change that ?

Is there a solution to this ?
#37
01/23/2006 (3:37 am)
You will have to look in the player class where it creates the bounding box and adjust the size of the bounding box to match the legs etc.

I have not tried it but it should be possible.
#38
01/23/2006 (9:32 pm)
Has this been updated to 1.4? Reason I'm asking is it looks like the code files included in the zip were for 1.3 and some of the functions are different now.

The real question is which animated DTS resource did you use so we know what is a pre-req for this resource!?
#39
01/23/2006 (10:21 pm)
The game is crashing when I attempt to go to the options diologue. It is crashing in file: optionsDlg.cs on this line:

OptBoneAreaList.add("Whole Body", PlayerView.findThisNode("Bip01 Pelvis"));

The only difference between this file and the one that comes with this resource is I changed the following line:

PlayerView.setModel(%playerList[1] @ "/player.dts", "", %playerList[1] @ "/player_forward.dsq" );

to be:

PlayerView.setModel(%playerList[1] @ "/player.dts", "" );

due to the fact that I have a stock guiplayerview.cc I'm working with.


in guiplayerview.cc here is the findThisNode and findNode info:

onsoleMethod( GuiPlayerView, findThisNode, S32, 3, 3, "playerView.findThisNode( 'Bip01 Pelvis' )" )
{
	argc;
	GuiPlayerView* view = static_cast<GuiPlayerView*>( object );
	return view->findNode(argv[2]);
}

U32 GuiPlayerView::findNode( const char *name )
{
	TSShape* shape = mModel->getShape();
	return shape->findNode(name); //"Bip01 Pelvis" etc
}


I'm using the standard orc player model that comes with the starter.fps for this if that matters. Any thoughts?

When it crashes, neither Torsion nor my console.log say anything.

EDIT: Removed console.log
#40
01/23/2006 (11:15 pm)
AS stated before, the included cc and h files are for 1.3. To make it work in 1.4, just copy paste from the pdf file.

I don't have time to update the cc and h file to 1.4. If you want to do it, I can include your files in the zip.

The optionsdlg.cs file MUST use the guiplayerview functions from the pdf or use the included guiplayerview.cc file. If it cannot find the dts or dsq it will crash as you described. You probably did not update the path for 1.4
Quote:
It does work with TGE 1.4 except in one area, the script section in optiondlg.cs where setmodal() uses a path consisting of $usermods

TGE 1.4 has added "creator;" to the front of the $usermods path which means you need to remove it or replace $usermods with your own mod path. Failure to do so results in a crash/hang situation.

All other C++ code is still valid for TGE1.4