Jump to content

How to: make your animations Petite Mesh Avatar Compatible


Judith Flow
 Share

You are about to reply to a thread that has been inactive for 2792 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

For those who don't know what Petite Mesh Avatars are: they're mesh avatars created by Yabusake Loon which are only about a third the size of a regular Avatar. Because of their size and certain other properties of these avatars, many regular animations actually do NOT play correctly. Specifically, animations involving hip-movement will not play perfectly well on these avatars, though the impact of any distortions can be so small that it's hardly noticable. However, on certain animations, like ground sits, floor- and poledances, the distortion can be very apparent, causing Petite Mesh Avatars to float in mid-air or sink through the ground.

 

This little guide is for manually adjusting your LOCAL animation files, so unless you're a creator, you probably won't have any use for this guide since it involves directly hacking into the .BVH files.

Tools needed: Notepad or a similar program, but for this guide I'll assume you use notepad.

 

Okay, the first thing to do is: make your animation as usual, process it and everything as usual as well. Just everything you usually do untill the moment where you'd usually upload your bvh file to Second Life as a regular animation.

Now, instead of uploading to Second Life, open the .bvh file in notepad. Notepad++ or certain other editors might work as well, but just good old Notepad works perfectly.

Next, TURN OFF WORD WRAP. I know you'll getting some extremely long lines, but don't worry. We need to edit some things, and those things are right at the beginning of the lines involved

Scroll down a bit, untill you get to:

MOTION
Frames:    (some number, probably 30)
Frame Time:    (another number)

Right below that, you'll get a long list of all kinds of numbers And we're going to edit some of them: the first, second and third number on each line!

These first three numbers are the positions of the avatars HIP, in the order X, Z, Y. Yes, Z and Y have been reversed.

Now let's see how exactly we're going to adjust these numbers.
For the first and third number on each line, divide the number by 3. That's it, just divide by 3. Why 3? That's because your avatar is only a third the size of a normal avatar, so hip movement needs to be only a third the amount of movement found on regular avatars.

The second number on each line except the first needs adjustment too, but this one is a bit trickier! The default vertical offset for the hip is usually something around 43.5, where the X and Y default offsets are 0. That's why those were easier to adjust. The safest method I found, was writing the second number from each line down, so I'd get a list looking like:
43.528519
37.764259
32.000000
24.500401
12.000000
2.000000
2.000000

Behind that, I write down the increments from the previous line, so:
43.528519       0
37.764259       ~-6
32.000000       ~-6
24.500401       ~-9
12.000000       ~-12
2.000000        ~-10
2.000000        0

Next, I divide those new numbers by 3 again, so I'd get:
43.528519       0            0
37.764259       ~-6          -2
32.000000       ~-6          -2
24.500401       ~-9          -3
12.000000       ~-12        -4
2.000000        ~-10         -3.5
2.000000        0             0

And finally, I start from the first line, adding those last numbers I got to get a new list of z-offsets:
43.528519       0            0          43.528519
37.764259       ~-6          -2         41
32.000000       ~-6          -2         39
24.500401       ~-9          -3         36
12.000000       ~-12        -4          32
2.000000        ~-10         -3.5       28.5
2.000000        0             0            28.5

And use those numbers in the list I got
Another way would be to use the formula: (new offset - default offset from the first line) / 3 + default offset from the first line.
So if a is the Z offset from the first line (43.528519)
And b is the Z offset from the line you're working on (for example, 32 from the third line), you'd get:
(b-a)/3 + a =>
 (32 - 43.5)/3 + 43.5 =>
  -11.5/3 + 43.5 = >
  -3.8 + 43.5 = 39.6. So 39 wasn't too far off for a crude estimate ^_^
 
Now save the file, preferrably change the name to save your old one incase something messes up, and upload the new file to SL. There you have your Petite compatible Animation!


Note on all these divisions by 3: the amount is actually *roughly* 3. So you might need more fiddling to get an animation aligned just perfect, but it's close enough already to make distortions hardly noticable.

 


I'm sure someone could write a little external program or poser plug-in to automate updating your .bvh files, and I actually parsed this information to someone and asked him to do so, but untill then, manual has to do.

 

In case someone decides to automate this process: I post this to help the community in general. I'll support you in automating it, but I won't support anyone using this information to establish a monopoly on its use, and will merily unleash legal hell if things like DMCA's are used against other people trying to automate this process. I want to help make SL a better place, not help you get filthy rich over some faulty abuse of permissions.

Judith Flow

  • Like 5
Link to comment
Share on other sites

  • 4 weeks later...
  • 3 years later...

Hello,

I have just automated this process. Not sure how to give the program but perhaps I can just paste it here ? Note that this is C code, it is not LSL code (it does not work in second life itself). It is written on and tested with GNU/Debian/Linux, using gcc. Compile on a GNU/Linux machine: gcc bvh2resize.c -o bvh2resize ; Then to run and get usage message: bvh2resize --help. This code will likely work on other implementations of C, for example for a windos compiler. (I do not use windos and can hence not help with it, sorry.)

/* Name: bvh2resize * * Usage: > cat FILE.bvh | bvh2resize -f FRACTION > NEWFILE.bvh *        > bvh2resize -h|--help * * Description: A program that will adapt numbers in a *.bvh file, so that  *              the root (hip) movement is resized according to a supplied *              argument (a fraction). A *.bvh file is a file relating *              to 3D simulated worlds, encoding an "animation" on an *              "avatar". Note that 'resize' does not refer to file size, *              but to the size of the avatar on which the animation plays. *              It affects numerical values in the BVH file, which are *              adjusted according to a user supplied fraction. * *               Method of computation provided by 'Judith Flow', link: * https://community.secondlife.com/t5/Animation-Forum/How-to-make-your-animations-Petite-Mesh-Avatar-Compatible/td-p/1651619 * * Author: by Jos Boersema (Josjoha / joshb). *         aug 25 07:32:39 UTC 2016, on Debian 8/GNU/Linux, using gcc. *         2016 © Jos Boersema * * License: This program is free software. It is provided 'as is,' without *          any warranty or assumed fitness for a particular purpose. See *          for complete License: http://www.gnu.org GNU General Public *          License, version 3 (GPLv3). * * (Indent tab size = 4) This is version: 0.91 */#include <stdio.h>#include <string.h>#define LINE_BUFFER_LEN 1000 // The length of the buffer that records each        // line in the file.  An example of some BVHs showed its maximum line        // length was 611 characters.#define FIND_START "Frame Time:" // This is what we look for as a marker in the        // BVH file, to find the start of the data (based on face value look at        // a BVH file).#define FIND_START_LEN 11 // This is the length of the just above string        // FIND_START.void print_help ( ){	printf ( "bvh2resize: change root movement in a BVH animation file.\n" ) ;	printf ( "            Reads standard input, writes changed file to standard output.\n" ) ;	printf ( "Usage: bvh2resize -h|--help|-f FRACTION\n" ) ;	printf ( "       FRACTION: < 1.0 is smaller ~, "	    "> 1.0 bigger avatar\n" ) ; 	printf ( "Example: cat dance.bvh | bvh2resize -f 0.30 > "	    "dance_petite.bvh\n") ;	printf ( "Returns: success 0, usage error 1, FRACTION input error 2, "	    "input file error 3 \n" ) ;	printf ( "© Jos Boersema 2016, This program is Free Software (GPLv3).\n" ) ;}// This function gets one line of input, does the error handling, and // returns non-zero when a program abort error occured, zero on success.// It writes the variable 'line' as existing in main ( ).// Note: this function error-aborts when fgets() hits End Of File, meaning// it cannot be used to detect the End Of File when it is expected. Use of// feof() after fgets_plus is necessary when EOF is expected.int fgets_plus ( char * getline ){	if ( NULL == fgets ( getline , LINE_BUFFER_LEN , stdin ) ) return 3 ;		// read failed	// Detect line buffer filled to capacity, assuming it was likely	// even longer, thus aborting with error.	if ( ( LINE_BUFFER_LEN - 1 ) <= strlen ( getline ) )	{		fprintf ( stderr , 			"Error: too long line for line buffer size %i; "			"recompile program with a larger LINE_BUFFER_LEN, "			"aborting.\n" ,			LINE_BUFFER_LEN ) ;		return 3 ; // File Input error (abort program)	}	return 0 ; // success}// This function returns a pointer to the desired number in a string,// the numbers are separated by spaces. Ex: bvh_number ( line , 3 ) // returns the 3rd number on a BVH data line (latter data block in BVH).// Starts count from 0. Returns NULL pointer on error.char * bvh_number ( char * data , int list_n ){	int count ; // count off the numbers.	char * chr_n = data ; // Shifts through 'line' until found list_n number.		if ( 0 == list_n ) return data ; // special case: no searching		for ( count = 0 ; count < list_n ; count ++ )	{		chr_n = strchr ( chr_n + 1 , ' ' ) ;		if ( NULL == chr_n ) // Error: Could not find next occurance of ' '		{			fprintf ( stderr , 				"Error: Could not find needed number in BVH, aborting.\n" ) ;			return NULL ;  // Program abort with file format error 3.		}	}	return chr_n + 1 ; // + 1 because it returns the leading space location.}// Wraps the scanf() call with some error handling, "scanf-f(loat)-plus"()// Also takes in the call to bvh_number(...).int scanf_fplus ( char * data , int list_n , float * store ){	char * source ; // get the start of the number using bvh_number(...)		// Find where this number is	if ( NULL == ( source = bvh_number ( data , list_n ) ) ) return 3 ; 		// bvh_number() already prints an error to stderr		// bvh_number() encountered an error: program abort		// Scan it in	if ( 1 != sscanf ( source , "%f" , store ) )	{ // failed (probably not a BVH file or corrupted.)		fprintf ( stderr , "Error: unable to scan a number in input,"			", aborting. Problem occured at the first element of this "			"data (which is not necessarily the start of a BVH line):\n" ) ; 		fprintf ( stderr , "%s\n" , source ) ; 		return 3 ; // file format error	}	return 0 ; // success: value stored}int main ( int argc , char * argv [ ] ) {	float resize_fraction ; // Program argument: the animation is resized	    // to this number.	char line [ LINE_BUFFER_LEN ] ; // Each line in the input file we will 	    // read first, then process it if needed: thus need storing it.	float original_rootz ; // This is the 2nd number of the 1st line of the data	    // block in a BVH file, which is the 'root' joint. Once read then kept.	float root_x ; // The x-coordinate of the root, 1st number on a data line.	float root_z ; // The z-coordinate of the root, 2nd number on a data line.	float root_y ; // The y-coordinate of the root, 3rd number on a data line.		// -----------------------------v---------------------------------------	//                    Program user arguments		if ( argc > 1 ) // There is at least 1 argument	{		// detect a request for usage help:		if ( ( ( 0 == strcmp ( "-h" , argv [ 1 ] ) )		               ||		               ( 0 == strcmp ( "--help" , argv [ 1 ] ) ) ) )		{			print_help ( ) ;			return 0 ;		}		// GNU recommends license/author arguments as well ... TODO		// GNU recommends long arguments: --fraction=N ... TODO				// process the user input of a fraction to resize animation to:		else if ( 0 == strcmp ( "-f" , argv [ 1 ] ) )		{			if ( argc > 2 ) // There is at least 2 arguments			{				int error ; // record return value from sscanf()				error = sscanf ( argv [ 2 ] , " %f" , & resize_fraction ) ;				// Some error detection. Zero input is also not allowed (math				// error) Not using scanf_fplus because of other error message.				if ( 0.0 == resize_fraction || 1 != error ) 				{					fprintf ( stderr , "Error: unable to read resize "					    "fraction, or 0.00 input: '%s', aborting\n" ,					    argv [ 2 ] ) ;					return 2 ; // fraction user input error				}			}			else // Expects the fraction argument as well			{				fprintf ( stderr , 				       "Error: no fraction given with '-f', aborting.\n" ) ;				print_help ( ) ; // Keeping it simple: no user-interaction.				return 1 ; // usage error			}		}		else // An unrecognized argument: usage error		{			fprintf ( stderr , 			    "Error: unrecognized argument '%s', aborting.\n" ,			    argv [ 1 ] ) ;			print_help ( ) ; // Keeping it simple, no user-interaction.			return 1 ; // usage error		}	} 	else // absence of all arguments	{		fprintf ( stderr , 		    "Error: no arguments received, aborting.\n" ) ;		print_help ( ) ; // Keeping it simple, no user-interaction.		return 1 ; // usage error	}	// End processing arguments.	// -------------------------------^------------------------------------		// -------------------------------v------------------------------------	//                    Flush the header to output	//	// Start processing the input: first look for the marker FIND_START in	// the input. What precedes it is not needing changes, and echoed unto	// stdout unchanged.	do	{		// Getting an input file line in the line buffer, followed by error		// handling:		if ( 0 != fgets_plus ( line ) ) // fills 'line'		{			if ( 0 != feof ( stdin ) ) // End Of File reached			{   // Since we have not even reached data to process, this is a				// file format error. Probably the input is not a BVH file, or				// erroneously truncated.				fprintf ( stderr , 				    "Error: unexpected End Of File, aborting.\n" ) ;				return 3 ; // File Input error (abort program)			}			else			{				// If not that, then abort with a generic message.				fprintf ( stderr , "Error: problem reading file, "				    "aborting.\n" ) ;				return 3 ; // error (abort program)			}		}				// All input is handled by fgets(), all output by printf().		printf ( "%s" , line ) ; // Echo this header info line back on 		    // stdout, to form the header of the new resized file as well.		    // With line read in hand, we'll scan for the marker:	} while ( 0 != strncmp ( FIND_START , line , FIND_START_LEN ) ) ; 	    // Found the marker: we have reached the data block in the input.	// ----------------------------^---------------------------------------		// ----------------------------v---------------------------------------	//              Handle the special first data line		// The next line seems to be an initialization line of sorts. This will	// be handled as a special case, outside the reading loops. At this point	// the buffer 'line' holds the line containing the marker.		// Getting a line in the line buffer, followed by error handling.	if ( 0 != fgets_plus ( line ) ) return 3 ; // error abort	printf ( "%s" , line ) ; // This line is also to be output back as is.		// Scan in the special root height initialization number:	if ( 0 != scanf_fplus ( line , 1 , & original_rootz ) ) return 3 ;	// I have not added code to change the root original offset, because	// a user can edit the BVH file at that point by hand, nor is there	// information on whether this would ever be useful.		// ----------------------------v---------------------------------------	//                   Main data processing	// Start processing the first 3 numbers of each line.	// The formula is; 1st and 3rd number are multiplied with the fraction.	// The difference with the original_rootz and the 2nd number is also	// multiplied with the fraction, and then added to original_rootz		do	{		// INPUT: Getting an input file line, followed by condition handling:		char * start_number_p ; // Holding space for bvh_number() return value		if ( 0 != fgets_plus ( line ) ) // fills 'line'		{			    // Expected End Of File: assumes succes, program end.			if ( 0 != feof ( stdin ) ) return 0 ; // ok PROGRAM END.						fprintf ( stderr , "Error: problem reading file, "			    "aborting.\n" ) ;			return 3 ; // error abort		}				// CONVERT: Get the 3 numbers read in as floats:		if ( 0 != scanf_fplus ( line , 0 , & root_x ) ) return 3 ;		if ( 0 != scanf_fplus ( line , 1 , & root_z ) ) return 3 ;// Z, not Y		if ( 0 != scanf_fplus ( line , 2 , & root_y ) ) return 3 ;				// COMPUTE:		root_x = root_x * resize_fraction ;		root_z = ( root_z - original_rootz ) * resize_fraction +		                                                      original_rootz ;		root_y = root_y * resize_fraction ;				// PRINT: Get the start of the remainder of the line, print all.		if ( NULL == ( start_number_p = bvh_number ( line , 3 ) ) ) return 3 ;		printf ( "%f %f %f %s" , root_x , root_z , root_y , start_number_p ) ; 			} while ( 1 ) ; // See fputs_plus() if-then for program end.}

We resized a dance with FRACTION 0.30 for petite avis and it worked perfectly. Thank you Judith for providing the BVH resize methodoly. I hope the code is fairly bug free.

 

 

In the likely case you want to convert many animations at once, you can do so on GNU/Linux with the following Zshell script:

 

#!/usr/bin/zsh --# Writes a group of new BVH files, sourced from the same directory as # the program is running in. Writes the new files in /tmp/ directory.# (This is a Zshell script.) #            (Author: Jos Boersema. Licensed: GNU G.P.L. version 3.)MARK="petite-" # Your markerFRACTION="0.30" # Your fraction OUTPUT_DIR="/tmp/bvh2resize_${MARK}${FRACTION}" # Your output directorymkdir ${OUTPUT_DIR}for i in $( ls ./*.bvh ) {	NEWFILE="${i:r}_${MARK}${FRACTION}.${i:e}"	echo "Converting file '${i}' into '${OUTPUT_DIR}/${NEWFILE}'"	cat $i | bvh2resize -f "${FRACTION}" > ${OUTPUT_DIR}/${NEWFILE}}

 

 

P.S. Isn't this weird: Judith post was on 08-28-2012 12:28 PM, my last (hopefully final) addition/revision on the programcode was on 08-28-2016 12:41 PM. That seems to be exactly 4 years (and 13 minutes) later. (aug 28 12:34 group-bvhresized.zsh)

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2792 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...