Reply

i’m exporter to maya the objects and put in the Visual c++ code for using, but the texture it is seen but clear of which they are? i dont know why

I don’t know anything about maya, but it looks like the material properties are not correctly set.

From reading all of your posts I think i have some idea of what you are on about, although I’m not entirely sure so I’ll answer all possibilities…

Maya4.0 started using the seperate specular extension for the viewport display. This means that the specular highlight is added after the texture is applied.

Normally openGL calculates the specular highlight before the texture which means your specular is a bit muted.

You will need to set the material properties for your objects before you draw them.

a basic example :

// include the gl extensions
#include “glext.h”

void ApplyMaterial()
{
float ambient = {0.3f,0.3f,0.3f,0.0f};
float diffuse = {0.7f,0.7f,0.7f,0.0f};
float specular = {1.0f,1.0f,1.0f,0.0f};
float emission = {0.0f,0.0f,0.0f,0.0f};

glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,specular);
glMaterialfv(GL_FRONT,GL_EMISSION,emission);
glMaterialf(GL_FRONT,GL_SHININESS,20);

// !!! YOU MUST CHECK THAT THE GRAPHICS CARD SUPPORTS
// OPENGL1.2 OR THIS EXTENSION FIRST BEFORE CALLING THIS LINE !!!
glLightModelf ( GL_LIGHT_MODEL_COLOR_CONTROL_EXT,GL_SEPARATE_SPECULAR_COLOR_EXT);
}

//==================================

It is unclear from your posts how you are getting the data, I presume it is one of these ways :

  1. obj export

  2. C++ exporter coded in the API

  3. a mel script to export the data

  4. obj export
    The maya exporter does not support material information so you’ll probably have to do 3, or 2 using the obj exporter source code in the devkit.

  5. ammend the exporter to look for MFn::kLambert, MFn::kPhong material types and use the MFnDependencyNode function set to get the data

  6. Mel script,

something like this should get the data for you…

// open a file
$fp = fopen "OutputFile.txt" "w";

string $materials = ls -type lambert;
// output the materials to the file
//
fprint $fp ("MATERIAL_COUNT “+size($materials)+”
{
");

// for each material…
//
for($i=0;$i<size($materials);$i++)
{
// get the ambient, diffuse and emission colours
//
float $ambient = getAttr ($materials[$i]+".ambientColor");
float $diffuse = getAttr ($materials[$i]+".color");
float $emission = getAttr ($materials[$i]+".incandescence");
float $specular;
for($j=0;$j<4;$j++)
{
$specular[$j] = 0;
}
float $shininess = 10.0;

  string $texture = "none";
  
  //	try and find a texture connected to the colour channel
  //
  string $possibleTextures[] = `listConnections -s true -d true ($materials[$i]+".color")`;
  
  //	trya and find a "file" node
  //
  for($j=0;$j<size($possibleTextures);$j++)
  {
  	if(`nodeType $possibleTextures[$j]` == "file")
  	{
  		$texture = `getAttr ($possibleTextures[$j]+".ftn")`;
  		$diffuse[0] = $diffuse[1] = $diffuse[2] = 0.5;
  	}
  }
  
  //	blag the specular and shininess values
  //
  if( `attributeExists "specularColor" $materials[$i]` == true)
  {
  	$specular = `getAttr ($materials[$i]+".specularColor")`;
  }
  if( `attributeExists "cosinePower" $materials[$i]` == true )
  {		
  	$shininess = `getAttr ($materials[$i]+".cosinePower")`;
  }
  if(`attributeExists "roughness" $materials[$i]` == true)
  {
  	$shininess = 10 + 118*(1-`getAttr ($materials[$i]+".roughness")`*
  							 `getAttr ($materials[$i]+".highlightSize")`);
  }
  if(`attributeExists "eccentricity" $materials[$i]` == true)
  {
  	$shininess = 10 + 118*(1-`getAttr ($materials[$i]+".eccentricity")` *
  						  `getAttr ($materials[$i]+".specularRollOff")`);
  }
  
  //	output the data
  //
  fprint $fp ("	MATERIAL "+$materials[$i]+"

{
“);
fprint $fp (” AMBIENT “+$ambient[0]+” “+$ambient[1]+” “+$ambient[2]+” “+$ambient[3]+”
“);
fprint $fp (” DIFFUSE “+$diffuse[0]+” “+$diffuse[1]+” “+$diffuse[2]+” “+$diffuse[3]+”
“);
fprint $fp (” SPECULAR “+$specular[0]+” “+$specular[1]+” “+$specular[2]+” “+$specular[3]+”
“);
fprint $fp (” EMISSION “+$emission[0]+” “+$emission[1]+” “+$emission[2]+” “+$emission[3]+”
“);
fprint $fp (” SHININESS “+$shininess+”
“);
fprint $fp (” TEXTURE “+$texture+”
}

“);
}
fprint $fp (”}

");

// close the file
fclose $fp;

Hopefully the answer you want is in there somewhere…

[This message has been edited by Rob The Bloke (edited 08-17-2002).]

thank’s men and i’m sorry for my english, im not write english very well.
i have a question for you? where find good examples and information for extensions?

thank’s for your time

Extenstions eh? Well, here are some sites I like that have stuff about extensions.
http://www.nutty.org http://developer.nvidia.com http://nate.scuzzy.net http://nehe.gamedev.net http://www.ati.com/developer/

Those sites have stuff about extensions. Actually, opengl.org here has stuff about them too!

-SirKnight

thank’s men but the sample code is not working i’m not find a header files for run this examples.

someone know where download a good translator?

Originally posted by Visualc++:
someone know where download a good translator?

translator of what to what?

from Maya, 3ds,obj to Opengl source code, i’m using deep exploration but this program not export all the attributes to teh animation (bump maping , paint effects,exprersion)

The best thing to do is not convert the models to opengl code like you’re doing, but to load in the model format that you want. So that way you have direct access to all the attributes you want/need. There are many many articles/tutorials/specs online on how to load just about every file format you can think of. You will be much better off doing that. Sure it may be a little more difficult than how you’re doing it now but it’s worth it.
http://www.gametutorials.com has a good number of excellent tutorials on loading various types of model formats. Really it’s not all that hard as long as you are familiar with file i/o and 3d data structures a little bit.

-SirKnight

[This message has been edited by SirKnight (edited 08-20-2002).]

good idea men, this page i finder before, but m3d? how translated maya animations (*.ma) to m3d…? damm i’m bad

You can’t get animation data out of Maya unless you program some exporter of your own. The .ma/.mb files only contain mel commands to create the scene when they are loaded. In order to understand them you would have to re-program maya so that you could interpret them. Kinda pointless. As I said before, either use a mel script to get the data or write your own exporter in the API.

This is the script I use with my students to get them started with OpenGL, so you should have a fair amount to use there and have a good starting point when getting the data…

It supports skin weights, poly’s, nurbs, animation and transforms. If it’s not enough then extend it. You will have to load this yourself because there wont be a conversion for it in any package…

Sorry to everyone about the extremely long post

the mel script…

////////////////////////////////////////////////////////////////////////////////
//
// some global variable to hold data between various odd callbacks, kinda a bit
// easier than messing about with passing extra variables between callbacks.
//
////////////////////////////////////////////////////////////////////////////////

// global string to hold the output filename
global string $file = “”;

// use global string array to hold names of transforms to output
global string $transformsToWangInFile;

// this global array will hold the names of the t
global string $transformsInOrderedList;

// global variable used to determine how many tabs are required
global int $indent = 0;

// global list of normals and the poly indices for them
//
// This is required because there is no way in mel to get the list of normals.
// therefore we build the list instead and assign our own indices.
//
global float $g_NormalList;
global int $g_NormalIndices;

////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Proc : multMatrix
// Params : $matrix - the matrix transformation
// $pos - the vertex to be transformed
// Returns : the transformed position
// Notes : transforms the specified vector by the matrix
////////////////////////////////////////////////////////////////////////////////
proc float multMatrix(float $matrix,float $pos)
{
float $v[3];
$v[0] = $matrix[0] * $pos[0] + $matrix[4] * $pos[1] + $matrix[ 8] * $pos[2] + $matrix[12];
$v[1] = $matrix[1] * $pos[0] + $matrix[5] * $pos[1] + $matrix[ 9] * $pos[2] + $matrix[13];
$v[2] = $matrix[2] * $pos[0] + $matrix[6] * $pos[1] + $matrix[10] * $pos[2] + $matrix[14];
return $v;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : multMatrixNormal
// Params : $matrix - the matrix transformation
// $pos - the normal to be transformed
// Returns : the transformed normal
// Notes : transforms the specified normal by the matrix
////////////////////////////////////////////////////////////////////////////////
proc float multMatrixNormal(float $matrix,float $pos)
{
float $v[3];
$v[0] = $matrix[0] * $pos[0] + $matrix[4] * $pos[1] + $matrix[ 8] * $pos[2];
$v[1] = $matrix[1] * $pos[0] + $matrix[5] * $pos[1] + $matrix[ 9] * $pos[2];
$v[2] = $matrix[2] * $pos[0] + $matrix[6] * $pos[1] + $matrix[10] * $pos[2];
return $v;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : getConnectedMaterial
// Params : $shape - the surface to query for a material assigned
// Returns : the name of the material or none
// Notes : has a flaw in that it will only return the first material found and
// not for each polygon face. **** it I say…
////////////////////////////////////////////////////////////////////////////////
proc string getConnectedMaterial( string $shape )
{
string $connections = listConnections -type shadingEngine $shape;

if(size($connections) == 0)
{
return “none”;
}
string $shadingEngineConns = listConnections -type lambert $connections[0];

return $shadingEngineConns[0];
}

////////////////////////////////////////////////////////////////////////////////
// proc : getNurbsSurfaceKnots
// args : $surface - the name of nurbs surface to query
// $uKnots - an array of floats to be filled with the u Knot vals
// $vKnots - an array of floats to be filled with the v Knot vals
// returns : true or false depending on if failed or not
// notes : Creates a surface info node that is attached to the nurbs surface
// to allow you to read back the values. Bear in mind that Maya
// ignores the first and last knot values so you should add an
// additional knot at the beginning and one at the end if you are
// exporting this data anywhere else.
////////////////////////////////////////////////////////////////////////////////

proc int getNurbsSurfaceKnots( string $surface, float $uKnots, float $vKnots )
{
// create info Node.
//
string $infoNode ;
if( catch( $infoNode = createNode surfaceInfo ) )
{
return 0; // failed
}

// connect surface on to the info node.
//
string $outAttr = $surface + “.local” ;
string $inAttr = $infoNode + “.is” ;
connectAttr $outAttr $inAttr ;

// read the knots.
//
$uKnots = getAttr ($infoNode + ".knotsU");
$vKnots = getAttr ($infoNode + ".knotsV");

// delete surface info node.
//
delete $infoNode ;

// worked
//
return 1;
}

////////////////////////////////////////////////////////////////////////////////
// proc : getSurfaceKnotsAsString
// args : $surface - the name of nurbs surface to query
// returns : data string
// notes : takes all the nurbs surface information and creates a data string
// with it that it then returns. Inserts the additional knots that
// maya ignores.
////////////////////////////////////////////////////////////////////////////////
proc string getSurfaceKnotsAsString( string $surface )
{
float $uKnots,$vKnots;
string $returnValue;
if( !(getNurbsSurfaceKnots $surface $uKnots $vKnots) )
{
return $returnValue;
}

{
// check to see if the knots are periodic or closed
//
$returnValue += " KnotsInU: " + (size($uKnots)+2) +"
";

  //	insert the knot that maya ignores that should be there!
  //
  if($uKnots[0] == $uKnots[1])
  {
  	$returnValue += $uKnots[0];
  }
  else
  {
  	$returnValue += ($uKnots[0]-1);
  }

  //	output all of the u knot values to the string
  //
  for($i=0;$i<size($uKnots);$i++)
  {
  	$returnValue += (" " + $uKnots[$i]);
  }

  //	insert the knot that maya ignores that should be there!
  //
  if($uKnots[0] == $uKnots[1])
  {
  	$returnValue += (" " + $uKnots[size($uKnots)-1]);
  }
  else
  {
  	$returnValue += (" " + ($uKnots[size($uKnots)-1]+1));
  }

  $returnValue += "

";

  //	check to see if the knots are periodic or closed
  //
  $returnValue += "		KnotsInV: " + (size($vKnots)+2) +"
  ";
  //	insert the knot that maya ignores that should be there!
  //
  if($vKnots[0] == $vKnots[1])
  {
  	$returnValue += $vKnots[0];
  }
  else
  {
  	$returnValue += ($vKnots[0]-1);
  }

  //	output all of the u knot values to the string
  //
  for($i=0;$i<size($vKnots);$i++)
  {
  	$returnValue += (" " + $vKnots[$i]);
  }

  //	insert the knot that maya ignores that should be there!
  //
  if($vKnots[0] == $vKnots[1])
  {
  	$returnValue += (" " + $vKnots[size($vKnots)-1]);
  }
  else
  {
  	$returnValue += (" " + ($vKnots[size($vKnots)-1]+1));
  }

  $returnValue += "

";
}
return $returnValue;
}

////////////////////////////////////////////////////////////////////////////////
// proc : getNurbsType
// args : $surface - the name of the nurbs surface to query
// returns : data string
// notes : returns a string with info about the nurbs surface degree, type
// and number of spans in U & V.
//
// Type : 0 - open, 1 - closed, 2 - periodic
// Degree : Degree for U & V curve segments
// Spans : Number of U & V spans
////////////////////////////////////////////////////////////////////////////////

proc string getNurbsType( string $surface )
{
string $w;

// Curve Type
//
int $formU = eval("getAttr " + $surface + “.formU”);
int $formV = eval("getAttr " + $surface + “.formV”);
$w = " U_Type: " + $formU + "
V_Type: " + $formV + "

";

// Curve Degree
//
int $degreeU = eval("getAttr " + $surface + “.degreeU”);
int $degreeV = eval("getAttr " + $surface + “.degreeV”);
$w += " DegreeU: " + $degreeU + "
DegreeV: " + $degreeV + "

";

// Surface Spans in U & V
//
int $nspansU = eval("getAttr " + $surface + “.spansU”);
int $nspansV = eval("getAttr " + $surface + “.spansV”);
$w += " SpansU: " + $nspansU + "
SpansV: " + $nspansV + "

";

return $w;
}

////////////////////////////////////////////////////////////////////////////////
// proc : getNurbsCVs
// args : $surface - the name of nurbs surface
// returns :
// notes : recursively adds the parents of a given transform to the current
// selection list until it hits the root node. Used to ensure
// sensible data is exported.
////////////////////////////////////////////////////////////////////////////////

proc string getNurbsCVs( string $surface )
{
string $w;

// create info Node.
//
string $infoNode = createNode surfaceInfo;

// connect surface on to the info node.
//
string $outAttr = $surface + “.ws[0]” ;
string $inAttr = $infoNode + “.is” ;
connectAttr $outAttr $inAttr ;

// get number of CVs in U and V (always degree+spans even
// for periodics since overlapping CVs are available separately)
//
int $degreeU = eval( "getAttr " + $surface + “.degreeU” );
int $spansU = eval( "getAttr " + $surface + “.spansU” );
int $numCVsU = $spansU + $degreeU;

int $degreeV = eval( "getAttr " + $surface + “.degreeV” );
int $spansV = eval( "getAttr " + $surface + “.spansV” );
int $numCVsV = $spansV + $degreeV;

int $dim = size ( eval( "getAttr " + $surface + “.cv[0][0]” ) );

$w = " CV_in_U: " + $numCVsU + "
CV_in_V: " + $numCVsV + "
";

// print out the CV positions including overlapping ones
//
$w += "
CVs:

";

int $numCV = -1;
for( $i=0 ; $i<$numCVsU ; $i++ )
{
for( $j=0 ; $j<$numCVsV ; $j++ )
{
$numCV++;
float $cvs = getAttr ( $infoNode + ".cp["+$numCV+"]" );
float $weight = getAttr ( $surface + ".wt["+$numCV+"]" );
$w += " " + $i + " " + $j + " ";
for( $k=0 ; $k<3 ; $k++ )
{
$w += $cvs[$k] + " “;
}
$w += ($weight+”
");
}
}
delete $infoNode;
return $w;
}

////////////////////////////////////////////////////////////////////////////////
// proc : getNurbsSurfaceData
// args : $surface - the name of nurbs surface
// returns :
// notes : builds up a single string that contains all nurbs surface data
////////////////////////////////////////////////////////////////////////////////

proc string getNurbsSurfaceData( string $surface )
{
string $returnValue;

$returnValue = " NURBS_SURFACE: " + $surface + "
{
“;
$returnValue += (” USES_MATERIAL " + getConnectedMaterial $surface+"
");
$returnValue += getNurbsType $surface;
$returnValue += getSurfaceKnotsAsString $surface;
$returnValue += getNurbsCVs $surface;
$returnValue += " }
";

return $returnValue;
}

////////////////////////////////////////////////////////////////////////////////
// proc : exportNurbsData
// args : $fp - file handle
// returns :
// notes : outputs all nurbs surfaces to a file
////////////////////////////////////////////////////////////////////////////////

proc exportNurbsData( int $fp)
{
string $surfaces = ls -type nurbsSurface;

if(size($surfaces)==0)
return;

int $surfacesToExport;
int $i;

// run through each mesh to find the ones that have materials
// assigned
//
for($i=0;$i<size($surfaces);$i++)
{
string $conns = listConnections -s true -d true ($surfaces[$i]);
for($j=0;$j<size($conns);$j++)
{
if( nodeType $conns[$j] == “shadingEngine” )
{
$surfacesToExport[ size($surfacesToExport) ] = $i;
}
}
}

fprint $fp (“NURBS_SURFACE_COUNT: " + size($surfacesToExport) +”
{
");
for($i=0;$i<size($surfacesToExport);$i++)
{
fprint $fp getNurbsSurfaceData $surfaces[ $surfacesToExport[ $i ] ];
}
fprint $fp "}

";

}

////////////////////////////////////////////////////////////////////////////////
// proc : recursiveParentSelect
// args : $transform - the name of transform
// returns :
// notes : recursively adds the parents of a given transform to the current
// selection list until it hits the root node. Used to ensure
// sensible data is exported.
////////////////////////////////////////////////////////////////////////////////

proc recursiveParentSelect(string $transform)
{
// get a list of parents to this transform so that they can inturn be added
// to the selection list
//
string $parents = listRelatives -type transform -p $transform;
if(size($parents)>0)
{
// select the parents of this transform
//
select -add $parents;

  //	recursively select the parents of the parents for a laugh
  //
  for($i=0;$i<size($parents);$i++)
  {
  	recursiveParentSelect $parents[$i];
  }

}
}

////////////////////////////////////////////////////////////////////////////////
// proc : buildListOfTransforms
// args :
// returns :
// notes : fills the above array with names of root nodes that we want to
// wang out into file - just like the name says!
////////////////////////////////////////////////////////////////////////////////
proc buildListOfTransforms()
{
// mel cackyness if you want to use a global variable
//
global string $transformsToWangInFile;

// remove any names currently held…
//
clear $transformsToWangInFile;

// you might want to change this to do some recursive magic with
// the listRelatives call cos this is tres pants in my view
//
string $transforms;

// get a list of all transforms in the scene
$transforms = ls -type transform;

// pick out only the root nodes and store their names.
int $rootCount = 0;
for($i=0;$i<size($transforms);$i++)
{
// get a list of parents for this transform
string $parents = listRelatives -p -type transform $transforms[$i];

  //	if there are no parents and the transform is not one of the
  if(	size($parents)  == 0       &&
  	$transforms[$i] != "front" &&
  	$transforms[$i] != "top"   &&
  	$transforms[$i] != "side"  &&
  	$transforms[$i] != "persp" )
  {
  	//	add the transform to the list
  	$transformsToWangInFile[$rootCount] = $transforms[$i];
  	$rootCount++;
  }

}
}

////////////////////////////////////////////////////////////////////////////////
// proc : recursiveTransformOutput
// args : $transformName - the name of the transform to output
// $startTime - the time to start sampling the animation
// $endTime - the time to stop sampling at
// $n - the frame increment
// $fp - the file handle
// $fileType - the extension of the file selected
// returns :
// notes : recursive function that outputs the animation data for the transform
// and then does all of its children,
////////////////////////////////////////////////////////////////////////////////
proc recursiveTransformOutput( string $transformName, float $startTime, float $endTime, int $n, int $fp )
{
global int $indent;
global string $transformsToWangInFile;

// get an array of the children for this transform
//
string $kiddies = listRelatives -c -type transform $transformName;

// indent the line
//
for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}

// print the name of the transform and the number of children
//
fprint $fp ("TRANSFORM “+$transformName+” " + "
");

// indent once more and wang down a bracket
//
for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}
fprint $fp "{
";

// increment the indent
//
$indent++;
float $i;

select -r $transformsToWangInFile;
eval gotoBindPose;

for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}

fprint $fp ("Bind_Pose:
");

for($j=0;$j<=$indent;$j++)
{
fprint $fp " ";
}

// write out some transform info
//
fprint $fp (
"tx " + getAttr ($transformName+".translateX") +
" ty " + getAttr ($transformName+".translateY") +
" tz " + getAttr ($transformName+".translateZ") +
" rx " + getAttr ($transformName+".rotateX") +
" ry " + getAttr ($transformName+".rotateY") +
" rz " + getAttr ($transformName+".rotateZ") +
" sx " + getAttr ($transformName+".scaleX") +
" sy " + getAttr ($transformName+".scaleY") +
" sz " + getAttr ($transformName+".scaleZ") + "
" );

for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}

fprint $fp ("Num_Keyframes: “+($endTime-$startTime+1)+”
");

// output the animation data for each time increment
//
for( $i=$startTime; $i<=$endTime; $i+=$n )
{
// set the current frame to grab some data stuff
//
currentTime $i;

  for($j=0;$j<$indent;$j++)
  {
  	fprint $fp "	";
  }

  //	write out some transform info
  //
  fprint $fp ("	"+$i+
  		" tx " + `getAttr ($transformName+".translateX")` +
  		" ty " + `getAttr ($transformName+".translateY")` +
  		" tz " + `getAttr ($transformName+".translateZ")` +
  		" rx " + `getAttr ($transformName+".rotateX")`    +
  		" ry " + `getAttr ($transformName+".rotateY")`    +
  		" rz " + `getAttr ($transformName+".rotateZ")`    +
  		" sx " + `getAttr ($transformName+".scaleX")`     +
  		" sy " + `getAttr ($transformName+".scaleY")`     +
  		" sz " + `getAttr ($transformName+".scaleZ")`     + "

" );
}

for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}

// child geometries…
//
{
// get a list of all child geometries
//
string $meshes = listRelatives -c -type mesh -type nurbsSurface $transformName;
int $meshesToExport;
int $i;

  //	run through each mesh to find the ones that have materials
  //	assigned
  //
  for($i=0;$i<size($meshes);$i++)
  {
  	string $conns[] = `listConnections -s true -d true ($meshes[$i])`;
  	for($j=0;$j<size($conns);$j++)
  	{
  		if( `nodeType $conns[$j]` == "shadingEngine" )
  		{
  			$meshesToExport[ size($meshesToExport) ] = $i;
  		}
  	}
  }
  
  //	output the child mesh names
  //
  fprint $fp ("Num_Meshes: "+size($meshesToExport)+"

");

  for($i=0;$i<=$indent;$i++)
  {
  	fprint $fp "	";
  }
  
  for($i=0;$i<size($meshesToExport);$i++)
  	fprint $fp ($meshes[ $meshesToExport[$i] ]+" ");
  	
  fprint $fp "

";
}

// child transforms…
//
for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}

fprint $fp ("Num_Children: “+size($kiddies)+”
");

// output all the children of this transform
//
for($j=0;$j<size($kiddies);$j++)
{
recursiveTransformOutput $kiddies[$j] $startTime $endTime $n $fp;
}

// decrease the indent
//
$indent–;

// add a closing bracket
//
for($j=0;$j<$indent;$j++)
{
fprint $fp " ";
}
fprint $fp "}
";
}

////////////////////////////////////////////////////////////////////////////////
// Proc : outputVertices
// Params : $fp - a handle to an open file
// $mesh - maya name of the mesh to output
// $bWorldSpace - boolean flag to determine if output is in worldspace
// Returns :
// Notes : outputs all vertices for the current mesh in triangle order
////////////////////////////////////////////////////////////////////////////////

proc outputVertices( int $fp, string $mesh, int $bWorldSpace )
{
// get the parent transform for this mesh
//
string $transform = listRelatives -p $mesh;

// query the matrix transform of this joint/transform
//
float $m = xform -q -ws -m $transform[0];

// get the number of vertices in the mesh
//
int $vertCount = polyEvaluate -v;

// output the vertex data
//
fprint $fp ("
VERTS “+$vertCount[0]+”
");

for($i=0;$i<$vertCount[0];$i++)
{
float $vert = getAttr ($mesh+".vt["+$i+"]");
float $offset = getAttr ($mesh+".pt["+$i+"]");

  //	final vert pos = vertex + offset, output it!
  //
  $vert[0] += $offset[0];		
  $vert[1] += $offset[1];
  $vert[2] += $offset[2];
  
  //	if requested in world space
  //
  if($bWorldSpace!=0)
  {
  	//	calculate in world space
  	//
  	$vert = `multMatrix $m $vert`;	
  }
  
  //	output the vertex co-ordinate
  //
  fprint $fp ("			" +
  		($vert[0]) + " " +
  		($vert[1]) + " " +
  		($vert[2]) +"

");
}
}

////////////////////////////////////////////////////////////////////////////////
// Proc : outputTexturingCoords
// Params : $fp - a handle to an open file
// $mesh - maya name of the mesh to output
// Returns :
// Notes : outputs all uv coords for the current mesh in triangle order
////////////////////////////////////////////////////////////////////////////////
proc outputTexturingCoords( int $fp, string $mesh )
{
// get the number of faces
//
int $uvCount = polyEvaluate -uv;

fprint $fp ("
UVS “+$uvCount[0]+”
");

for($i=0;$i<$uvCount[0];$i++)
{
float $vert = getAttr ($mesh+".uv["+$i+"]");

  //	output the uv co-ordinate
  //
  fprint $fp ("			" +
  		($vert[0]) + " " +
  		($vert[1]) +"

");
}
}

////////////////////////////////////////////////////////////////////////////////
// Proc : AddNormalToList
// Params : $x - x vector component
// $y - y vector component
// $z - z vector component
// Returns : the index of this normal
// Notes : adds the normal to the meshes normal list
////////////////////////////////////////////////////////////////////////////////
proc int AddNormalToList(float $x, float $y, float $z)
{
global float $g_NormalList;
int $i=0,$actual=0;
for($i=0;$i<size($g_NormalList);$i+=3,$actual++)
{
if( $x > $g_NormalList[$i ] - 0.001 && $x < $g_NormalList[$i ] + 0.001 &&
$y > $g_NormalList[$i+1] - 0.001 && $y < $g_NormalList[$i+1] + 0.001 &&
$z > $g_NormalList[$i+2] - 0.001 && $z < $g_NormalList[$i+2] + 0.001 )
{
return $actual;
}
}

$g_NormalList[$i ] = $x;
$g_NormalList[$i+1] = $y;
$g_NormalList[$i+2] = $z;

return $actual;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : NumNormals
// Params :
// Returns : the number of normals currently present
// Notes :
////////////////////////////////////////////////////////////////////////////////
proc int NumNormals()
{
global float $g_NormalList;
return size( $g_NormalList )/3;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : WriteNormalList
// Params : $fp - the file handle to output to
// Returns :
// Notes : Writes the polygon normals out to the requested file handle
////////////////////////////////////////////////////////////////////////////////
proc WriteNormalList(int $fp)
{
global float $g_NormalList;

fprint $fp ("
NORMALS “+ NumNormals +”
");

for($i=0;$i<size($g_NormalList);$i+=3)
{
fprint $fp (" “+$g_NormalList[$i ]+” “+$g_NormalList[$i+1]+” “+$g_NormalList[$i+2]+”
");
}
}

////////////////////////////////////////////////////////////////////////////////
// Proc : outputNormals
// Params : $fp - a handle to an open file
// $mesh - maya name of the mesh to output
// $bWorldSpace - does the mesh have to be transformed into
// world space before output
// Returns :
// Notes : builds and compresses a list of all the normals and their
// indices in the mesh and then writes them out.
////////////////////////////////////////////////////////////////////////////////

proc outputNormals( int $fp, string $mesh, int $bWorldSpace )
{
global float $g_NormalList;
global int $g_NormalIndices;

// initialise the two normal arrays
//
clear $g_NormalList;
clear $g_NormalIndices;

// list the parent transform(s) of this node
//
string $transform = listRelatives -p $mesh;

int $faceCount = polyEvaluate -f;

// query the matrix transform of this joint/transform
//
float $m = xform -q -ws -m $transform[0];

int $nCount = 0;

for( $i=0;$i<$faceCount[0];$i++)
{
// select this face and query which verts are part of it
//
select -r ( $transform[0]+“.f[”+$i+“]”);
string $vinds = polyInfo -fv;
string $split;
tokenize $vinds[0] $split;

  //	very hacky indeed, the normals are only the face
  //	normals cos Maya wont give the vertex normals in mel
  //	so this is a hack until I spend a bit of time sorting it properly.
  //
  for($j=4;$j<size($split);$j++)
  {
  	
  	//	select the vertex/face pair
  	//
  	select -r ($transform[0]+".vtxFace["+$split[2]+"]["+$i+"]");
  	

  	//	use polyNormalPerVertex to get the vertex normal values....
  	//
  	float $norm[] = `polyNormalPerVertex -q -xyz`;
  	

  	//	calculate in world space
  	//
  	if($bWorldSpace!=0)
  	{
  		$norm = `multMatrixNormal $m $norm`;
  	}
  	
  	
  	//	Store normal & index number
  	//
  	$g_NormalIndices[$nCount++] = `AddNormalToList $norm[0] $norm[1] $norm[2]`;
  	//	select the vertex/face pair
  	//
  	select -r ($transform[0]+".vtxFace["+$split[($j-1)]+"]["+$i+"]");
  	

  	//	use polyNormalPerVertex to get the vertex normal values....
  	//
  	$norm = `polyNormalPerVertex -q -xyz`;
  	
  	
  	//	calculate in world space
  	//
  	if($bWorldSpace!=0)
  	{
  		$norm = `multMatrixNormal $m $norm`;
  	}
  	

  	//	Store normal & index number
  	//
  	$g_NormalIndices[$nCount++] = `AddNormalToList $norm[0] $norm[1] $norm[2]`;
  	
  			

  	//	select the vertex/face pair
  	//
  	select -r ($transform[0]+".vtxFace["+$split[$j]+"]["+$i+"]");
  	


  	//	use polyNormalPerVertex to get the vertex normal values....
  	//
  	$norm = `polyNormalPerVertex -q -xyz`;
  	
  	
  	//	calculate in world space
  	//
  	if($bWorldSpace!=0)
  	{
  		$norm = `multMatrixNormal $m $norm`;
  	}
  	

  	//	Store normal & index number
  	//
  	$g_NormalIndices[$nCount++] = `AddNormalToList $norm[0] $norm[1] $norm[2]`;
  	
  }

}
WriteNormalList $fp;

// initialise the two normal arrays
//
clear $g_NormalList;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : outputFaces
// Params : $fp - a handle to an open file
// $mesh - maya name of the mesh to output
// Returns :
// Notes : outputs all normals for the current mesh in triangle order
////////////////////////////////////////////////////////////////////////////////

proc outputFaces( int $fp, string $mesh )
{
global float $g_NormalList;
global int $g_NormalIndices;

int $normIndexPosition = 0;

// list the parent transform(s) of this node
//
string $transform = listRelatives -p $mesh;

int $faceCount = polyEvaluate -f;

// process each face to get it’s vertex positions
//
for( $i=0;$i<$faceCount[0];$i++)
{
// select the current face
//
select -r ( $transform[0]+“.f[”+$i+“]”);

  //	query polyInfo to return an info string about the vertex indices
  //	of this face. We need to split the string so that we can get the
  //	individual vertex indices
  //
  string $vinds[] = `polyInfo -fv`;
  string $split[];
  tokenize $vinds[0] $split;
  	
  //	process each triangle in the face
  //
  for($j=4;$j<size($split);$j++)
  {
  	string $buffer[];
  	
  	//	query the vertex/face relationship to see which uv
  	//	it uses
  	//
  	string $tinds[] = `polyListComponentConversion -fvf -tuv ($transform[0]+".vtxFace["+$split[2]+"]["+$i+"]")`;
  	
  	//	split the string to get the [] at the end...
  	//
  	tokenize $tinds[0] "[]" $buffer;
  				
  	//	output the vertex co-ordinate
  	//
  	fprint $fp ("			" +
  			$split[2] + " " +
  			$buffer[1] + " " +
  			$g_NormalIndices[$normIndexPosition++] +"

");

  	//	query the vertex/face relationship to see which uv
  	//	it uses
  	//
  	$tinds = `polyListComponentConversion -fvf -tuv ($transform[0]+".vtxFace["+$split[$j-1]+"]["+$i+"]")`;
  	
  	//	split the string to get the [] at the end...
  	//
  	tokenize $tinds[0] "[]" $buffer;
  				
  	//	output the vertex co-ordinate
  	//
  	fprint $fp ("			" +
  			$split[$j-1] + " " +
  			$buffer[1] + " " +
  			$g_NormalIndices[$normIndexPosition++] +"

");

  	//	query the vertex/face relationship to see which uv
  	//	it uses
  	//
  	$tinds = `polyListComponentConversion -fvf -tuv ($transform[0]+".vtxFace["+$split[$j-2]+"]["+$i+"]")`;
  	
  	//	split the string to get the [] at the end...
  	//
  	tokenize $tinds[0] "[]" $buffer;
  				
  	//	output the vertex co-ordinate
  	//
  	fprint $fp ("			" +
  			$split[$j-2] + " " +
  			$buffer[1] + " " +
  			$g_NormalIndices[$normIndexPosition++] +"

");
}
}
clear $g_NormalIndices;
}

////////////////////////////////////////////////////////////////////////////////
// args : $skinCluster - the name of the skin cluster you want to output
// returns : data string
// notes :
////////////////////////////////////////////////////////////////////////////////

proc string getSkinClusterData( string $skinCluster )
{
string $returnValue;

// get influenced geometry
//
string $geometry = skinCluster -q -g $skinCluster;

// get a list of transforms that have an influence…
//
string $influenceObjects = skinCluster -q -wi $skinCluster;

$returnValue = " SKIN_CLUSTER " + $skinCluster +
"
{
Geom " + $geometry[0] +
"
Influences " + size($influenceObjects) + " ";

// output the influence transforms
//
for($i=0;$i<size($influenceObjects);$i++)
{
$returnValue += ($influenceObjects[$i] + " ");
}

if(nodeType $geometry[0] == “mesh”)
{
int $controlPointCount = polyEvaluate -v $geometry[0];

  $returnValue += ("
  ControlPointCount: "+$controlPointCount[0]+"

");

  //	output the vertex weights for a mesh
  //
  for($i=0;$i<$controlPointCount[0];$i++)
  {
  	$returnValue += "
  ";
  	for($j=0;$j<size($influenceObjects);$j++)
  	{
  		select -r ($geometry[0]+".vtx["+$i+"]");
  		$returnValue += (`skinPercent -t $influenceObjects[$j] -q $skinCluster`);
  		$returnValue += " ";
  	}
  }

}
else
if(nodeType $geometry[0] == “nurbsSurface”)
{
// create info Node.
//
string $infoNode = createNode surfaceInfo;

  string $outAttr = $geometry[0]+ ".ws[0]" ;
  string $inAttr = $infoNode + ".is" ;
  connectAttr $outAttr $inAttr ;

  int $degreeU = eval( "getAttr " + $geometry[0] + ".degreeU" );
  int $spansU  = eval( "getAttr " + $geometry[0]+ ".spansU"  );
  int $numCVsU = $spansU + $degreeU;

  int $degreeV = eval( "getAttr " + $geometry[0] + ".degreeV" );
  int $spansV  = eval( "getAttr " + $geometry[0]+ ".spansV"  );
  int $numCVsV = $spansV + $degreeV;

  delete $infoNode;
  
  
  $returnValue += ("
  ControlPointCount: "+($numCVsV*$numCVsU)+"

");

  //	output the weighting data for a nurbs surface in the same fashion
  //
  for($i=0;$i<$numCVsU;$i++)
  {
  	for($k=0;$k<$numCVsV;$k++)
  	{
  		$returnValue += "
  ";
  		for($j=0;$j<size($influenceObjects);$j++)
  		{
  			select -r ($geometry[0]+".cv["+$i+"]["+$k+"]");
  			$returnValue += ((`skinPercent -t $influenceObjects[$j] -q $skinCluster`) + " ");
  		}
  	}
  }

}

// close the data off a bit
//
$returnValue += "
}
";

// return stuff…
//
return $returnValue;
}

proc int fileBrowserCallbackFunc( string $filename, string $fileType )
{
global string $file ;

// copy the name that was selected into the global string to store it all…
$file = $filename;

// return 1 to destroy the file dialog box
return 1;
}

////////////////////////////////////////////////////////////////////////////////
// Proc : exportPolygonData
// Params : $filename - name of the output file
// Returns :
// Notes : outputs all meshes in the scene to a text file. All meshes will
// be triangulated, bit of a problem for the user, but makes the
// script a lot easier to write.
////////////////////////////////////////////////////////////////////////////////

proc exportPolygonData()
{
global string $transformsToWangInFile;
global string $file ;
global int $indent;

fileBrowser “fileBrowserCallbackFunc” “Output Filename” “” 1;

$fp = fopen $file "w";

if( !$fp )
{
print "Error opening file
";
return;
}

buildListOfTransforms;

// get the current playback range
float $startTime = playbackOptions -q -min, // might want -ast instead of -min
$endTime = playbackOptions -q -max; // might want -aet instead of -max

// build up a list of materials…
// all materials are derived from lambert so this shoul give me the
// stuff…
string $materials;
int $matCount = 0;

string $meshes = ls -type mesh;
int $meshUsed;

int $meshCount = 0;

// process each mesh
//
for($i=0;$i<size($meshes);$i++)
{
int $bFoundMat = 0;
$meshUsed[$i] = 0;
string $connections = listConnections -d true -s true $meshes[$i];

  //	determine if the mesh is attched to a shading group
  //
  for($j=0;$j<size($connections);$j++)
  {
  	if( `nodeType $connections[$j]` == "shadingEngine" && $bFoundMat == 0)
  	{
  		//	increment the count of meshes with assigned materials
  		//
  		$meshCount++;
  		
  		//	determine which material is used for this mesh
  		//
  		string $mats[] = `listConnections -t lambert $connections[$j]`;
  		
  		//	search the previously used materials
  		//
  		for($k=0;$k<size($materials);$k++)
  		{
  			if($materials[$k] == $mats[0])
  			{
  				$bFoundMat = 1;
  				$meshUsed[$i] = $k+1;						
  			}
  		}
  		
  		//	if a material hasn't been found, create a new one
  		//
  		if($bFoundMat == 0)
  		{
  			$bFoundMat = 1;
  			$materials[ size($materials) ] = $mats[0];
  			$meshUsed[$i] = size($materials);
  		}		
  	}
  }

}

// output the materials to the file
//
fprint $fp ("MATERIAL_COUNT “+size($materials)+”
{
");

// for each material…
//
for($i=0;$i<size($materials);$i++)
{
// get the ambient, diffuse and emission colours
//
float $ambient = getAttr ($materials[$i]+".ambientColor");
float $diffuse = getAttr ($materials[$i]+".color");
float $emission = getAttr ($materials[$i]+".incandescence");
float $specular;
for($j=0;$j<4;$j++)
{
$specular[$j] = 0;
}
float $shininess = 10.0;

  string $texture = "none";
  
  //	try and find a texture connected to the colour channel
  //
  string $possibleTextures[] = `listConnections -s true -d true ($materials[$i]+".color")`;
  
  //	trya and find a "file" node
  //
  for($j=0;$j<size($possibleTextures);$j++)
  {
  	if(`nodeType $possibleTextures[$j]` == "file")
  	{
  		$texture = `getAttr ($possibleTextures[$j]+".ftn")`;
  		$diffuse[0] = $diffuse[1] = $diffuse[2] = 0.5;
  	}
  }
  
  //	blag the specular and shininess values
  //
  if( `attributeExists "specularColor" $materials[$i]` == true)
  {
  	$specular = `getAttr ($materials[$i]+".specularColor")`;
  }
  if( `attributeExists "cosinePower" $materials[$i]` == true )
  {		
  	$shininess = `getAttr ($materials[$i]+".cosinePower")`;
  }
  if(`attributeExists "roughness" $materials[$i]` == true)
  {
  	$shininess = 10 + 118*(1-`getAttr ($materials[$i]+".roughness")`*
  							 `getAttr ($materials[$i]+".highlightSize")`);
  }
  if(`attributeExists "eccentricity" $materials[$i]` == true)
  {
  	$shininess = 10 + 118*(1-`getAttr ($materials[$i]+".eccentricity")` *
  						  `getAttr ($materials[$i]+".specularRollOff")`);
  }
  
  //	output the data
  //
  fprint $fp ("	MATERIAL "+$materials[$i]+"

{
“);
fprint $fp (” AMBIENT “+$ambient[0]+” “+$ambient[1]+” “+$ambient[2]+” “+$ambient[3]+”
“);
fprint $fp (” DIFFUSE “+$diffuse[0]+” “+$diffuse[1]+” “+$diffuse[2]+” “+$diffuse[3]+”
“);
fprint $fp (” SPECULAR “+$specular[0]+” “+$specular[1]+” “+$specular[2]+” “+$specular[3]+”
“);
fprint $fp (” EMISSION “+$emission[0]+” “+$emission[1]+” “+$emission[2]+” “+$emission[3]+”
“);
fprint $fp (” SHININESS “+$shininess+”
“);
fprint $fp (” TEXTURE “+$texture+”
}

“);
}
fprint $fp (”}

");

if($meshCount>0)
{
// output the number of meshes
//
fprint $fp ("MESH_COUNT “+$meshCount+”
{
");

  for( $i=0;$i<size($meshes);$i++)
  {
  	if( $meshUsed[$i]>0 )
  	{
  		select -r $meshes[$i];

  		int $triangleCount[] = `polyEvaluate -f`;

  		int $tC = 0;

  		//	use some very hacky methods to calculate the number of triangles within 
  		//	the mesh
  		//
  		for( $k=0;$k<$triangleCount[0];$k++)
  		{
  			//	select the current face
  			//
  			select -r ( $meshes[$i]+".f["+$i+"]");

  			//	query polyInfo to return an info string about the vertex indices
  			//	of this face. We need to split the string so that we can figure
  			//	out how many triangles there are
  			//
  			string $vinds[] = `polyInfo -fv`;
  			string $split[];
  			tokenize $vinds[0] $split;

  			//	calculate how many triangles this face will tessellate to 
  			//
  			$tC += size($split) - 4;
  		}

  		//	output mesh name and material used
  		//
  		fprint $fp ("	MESH "+$meshes[$i]+"

{
“);
fprint $fp (” USES_MATERIAL “+$materials[ ($meshUsed[$i]-1) ]+”
");

  		outputVertices        $fp $meshes[$i] 0;
  		outputNormals         $fp $meshes[$i] 0;
  		outputTexturingCoords $fp $meshes[$i];
  		fprint $fp ("
  TRIANGLES "+$tC+"

");
outputFaces $fp $meshes[$i];

  		fprint $fp ("	}

“);
}
}
fprint $fp (”}

");
}

exportNurbsData $fp;

// output the root transforms
//
if(size($transformsToWangInFile)>0)
{
fprint $fp ("NUMBER_OF_ROOT_JOINTS “+size($transformsToWangInFile)+”
{
");

  $indent++;
  for( $i=0; $i<size($transformsToWangInFile); $i++ )
  {
  	recursiveTransformOutput $transformsToWangInFile[$i] $startTime $endTime 1 $fp;
  	fprint $fp "

";
}
$indent–;
fprint $fp "}

";
}

// output the skin clusters
//
string $skinClusters = ls -type skinCluster;
if(size($skinClusters)>0)
{
fprint $fp ("NUMBER_OF_SKIN_CLUSTERS “+size($skinClusters)+”
{
");

  for($i=0;$i<size($skinClusters);$i++)
  {
  	fprint $fp `getSkinClusterData $skinClusters[$i]`;
  }
  fprint $fp "}

";
}

fclose $fp;

print "


!! Exported File OK !!


";

}

exportPolygonData;

The File Format Description

The file is split into a number of blocks in which each different data type is listed.
Each block will always appear in the same order although some blocks may not be present.
For example, if no NurbsSurfaces exist in the scene then there wont be a Nurbs Surface block

  1. The Material Block
    =====================

MATERIAL_COUNT <int: number of materials that are defined in the block>
{
MATERIAL <string: material name>
{
AMBIENT <float: red> <float: green> <float: blue> <float: alpha>
DIFFUSE <float: red> <float: green> <float: blue> <float: alpha>
SPECULAR <float: red> <float: green> <float: blue> <float: alpha>
EMISSION <float: red> <float: green> <float: blue> <float: alpha>
SHININESS <float: cosine shininess co-efficient>
TEXTURE <string: texture path>
}
}

The material block is always the first block in the file. It starts with the “MATERIAL_COUNT” flag
followed by an iteger representing how many materials are defined in the block.

Each Material is then defined with a string for the name and the data consists of :

RGBA values for ambient colour
RGBA values for diffuse colour
RGBA values for specular colour
RGBA values for emissive colour
Shininess Co-efficient Value
Texture path (or “none” if no texture is used)

  1. The Mesh Block
    =================

MESH_COUNT <int: number of meshes in the block>
{
MESH <string: mesh name>
{
USES_MATERIAL <string: name of the applied material>

	VERTS &lt;int: number of vertices in the following list&gt;
		&lt;float: vx&gt; &lt;float: vy&gt; &lt;float: vz&gt;
		&lt;float: vx&gt; &lt;float: vy&gt; &lt;float: vz&gt;
		.
		.
		.
		&lt;float: vx&gt; &lt;float: vy&gt; &lt;float: vz&gt;


	NORMALS &lt;int: number of normals in the following list&gt;
		&lt;float: nx&gt; &lt;float: ny&gt; &lt;float: nz&gt;
		&lt;float: nx&gt; &lt;float: ny&gt; &lt;float: nz&gt;
		.
		.
		.
		&lt;float: nx&gt; &lt;float: ny&gt; &lt;float: nz&gt;

	UVS &lt;int: number of texturing co-ords in the following list&gt;
		&lt;float: tu&gt; &lt;float: tv&gt;
		&lt;float: tu&gt; &lt;float: tv&gt;
		.
		.
		.
		&lt;float: tu&gt; &lt;float: tv&gt;

	TRIANGLES &lt;int: number of triangles in following list&gt;
		&lt;int: vertexIndex0&gt; &lt;int: texCoordIndex0&gt; &lt;int: normalIndex0&gt;
		&lt;int: vertexIndex1&gt; &lt;int: texCoordIndex1&gt; &lt;int: normalIndex1&gt;
		&lt;int: vertexIndex2&gt; &lt;int: texCoordIndex2&gt; &lt;int: normalIndex2&gt;
}

}

The mesh block starts with “MESH_COUNT” and a number detailing how many meshes will follow in the block

The USES_MATERIAL comes before the name of the material that is used on the mesh

The VERTS contains the list of vertices which are numbered from 0 to (VertexCount-1).
The NORMALS contains the list of normals which are numbered from 0 to (NormalCount-1).
The UVS contains the list of uv coords which are numbered from 0 to (UVCount-1).

The TRIANGLES chunk describes the number of triangles and their indices. Each triangle will consist of three
rows of three numbers, eg

	TRIANGLES 1
		0 0 0
		1 1 0
		2 2 0

This triangle list has one triangle in it, The first three numbers are indices to the corresponding
vertex/textureCoord/normal data lists that describe the first vertex of the triangle. This numbering
scheme is identical to the obj file format way of numbering faces except that triangles are the only
type of polygon used and that indicies start at zero rather than one.

  1. The Nurbs Surface Block
    ==========================

NURBS_SURFACE_COUNT: <int: surfaceCount>
{
NURBS_SURFACE: <string: surfaceName>
{
USES_MATERIAL <string: name of the material that is used on this surface>
U_Type: <int: type of curve in U-direction, 0=open,1=closed,2=periodic>
V_Type: <int: type of curve in V-direction, 0=open,1=closed,2=periodic>

	DegreeU: 	&lt;int:    Curve degree in u&gt;
	DegreeV: 	&lt;int:    Curve degree in v&gt;

	SpansU: 	&lt;int:    number of surface spans in u direction&gt;
	SpansV: 	&lt;int:    number of surface spans in v direction&gt;

	KnotsInU: 	&lt;int:    number of knots in u that will follow&gt;
			&lt;float:  knot0&gt;
			..
			..
			&lt;float:  knotLAST&gt;

	KnotsInV: 	&lt;int:    number of knots in v that will follow&gt;
			&lt;float:  knot0&gt;
			..
			..
			&lt;float:  knotLAST&gt;

	CV_in_U: &lt;int:  number of CV's in the u direction&gt;
	CV_in_V: &lt;int:  number of CV's in the v direction&gt;

	CVs:
	&lt;int: u-index&gt; &lt;int: v-index&gt;   &lt;float: x&gt; &lt;float: y&gt; &lt;float: z&gt; &lt;float: weight&gt;
	.
	.
	.

}

}

  1. The Transform Chunk
    ======================

NUMBER_OF_ROOT_JOINTS <int: number of root nodes that follow>
{
TRANSFORM <string: name of the transform>
{
Bind_Pose:
tx <float: TranslationX> ty <float: TranslationY> tz <float: TranslationZ> rx <float: RotateX> ry <float: RotateY> rz <float: RotateZ> sx <float: ScaleX> sy <float: ScaleY> sz <float: ScaleZ>

	Num_Keyframes: &lt;int: the number of keyframes that exists in this joint&gt;
		&lt;int: frameNum&gt; tx &lt;float: TranslationX&gt; ty &lt;float: TranslationY&gt; tz &lt;float: TranslationZ&gt; rx &lt;float: RotateX&gt; ry &lt;float: RotateY&gt; rz &lt;float: RotateZ&gt; sx &lt;float: ScaleX&gt; sy &lt;float: ScaleY&gt; sz &lt;float: ScaleZ&gt;
		&lt;int: frameNum&gt; tx &lt;float: TranslationX&gt; ty &lt;float: TranslationY&gt; tz &lt;float: TranslationZ&gt; rx &lt;float: RotateX&gt; ry &lt;float: RotateY&gt; rz &lt;float: RotateZ&gt; sx &lt;float: ScaleX&gt; sy &lt;float: ScaleY&gt; sz &lt;float: ScaleZ&gt;
		.
		.
		.
		&lt;int: frameNum&gt; tx &lt;float: TranslationX&gt; ty &lt;float: TranslationY&gt; tz &lt;float: TranslationZ&gt; rx &lt;float: RotateX&gt; ry &lt;float: RotateY&gt; rz &lt;float: RotateZ&gt; sx &lt;float: ScaleX&gt; sy &lt;float: ScaleY&gt; sz &lt;float: ScaleZ&gt;
	
	Num_Meshes: &lt;int: number of geometries parented under this mesh&gt;
		&lt;string: childGeom0&gt;
		.
		.
		.
		&lt;string: childGeomN&gt;
		
	Num_Children: 1
	TRANSFORM
	{
		.
		.
		.
	}
	.
	.
	.
}

}

The bindpose in the transform chunk describes the rotations and translations of the joint when the skin was bound
to the skeleton. The following flags are used to describe transformations…

tx - translation in x
ty - translation in y
tz - translation in z
rx - rotation in x
ry - rotation in y
rz - rotation in z
sx - scale in x
sy - scale in y
sz - scale in z

The Keyframes that are listed start with the frame number and then they detail the transformation component values
for that frame.

The Num_Meshes: field lists the geometries that are parented to this transform.

The Num_Children field lists each child as a TRANSFORM chunk in the file.

  1. The SkinCluster Chunk
    ========================

NUMBER_OF_SKIN_CLUSTERS <int: the number of skin clusters in the block>
{
SKIN_CLUSTER <string: the skin cluster name>
{
Geom <string: the mesh that this cluster affects - nurbs surface or mesh>
Influences <int: number of joint influences> <string: joint1> <string: joint2> … <string: jointn>
ControlPointCount: <int: number of control points/vertices in the geometry>

	&lt;float: joint1 weight&gt; &lt;float: joint2 weight&gt; ...... &lt;float: jointN weight&gt;
	&lt;float: joint1 weight&gt; &lt;float: joint2 weight&gt; ...... &lt;float: jointN weight&gt;
	.
	.
	.
	&lt;float: joint1 weight&gt; &lt;float: joint2 weight&gt; ...... &lt;float: jointN weight&gt;
}

}

Each skin cluster affects a single mesh or surface, the name of this surface should be listed correctly
after the “Geom” flag. The “Influences” field includes an integer that indicates how many joints affect
this piece of geometry. The names of those joints are then listed

The “ControlPointCount” indicate how many vertices or control points this skin cluster affects (this should
be equal to the number of vertices in the specific mesh or surface).

The final section is the skin weights themselves. Each line represents a single vertex/CV.
For each influence joint is listed a corresponding vertex weight. Each line of weights should sum to 1.

Try exporting a few simple objects using the script and you’ll soon see how it all works and should get an idea on how to load it…

very impresive… thank’s