Urho3D/Source/Extras/OgreMaxscriptExport/ogre/lib/OgreSkeletonLib_meshfns.ms

715 lines
22 KiB
Plaintext

include "ogre/lib/ogreSkeletonLib_usefulfns.ms"
include "ogre/lib/ogrebipedlib.ms"
----------------------------------------------------------------------------------------
-- ----------------------------------- WRITE MESH ----------------------------------- --
----------------------------------------------------------------------------------------
-----------------------------------------------------------------
-- Global 'variables'
-- There is an array with vertices datas for each submesh
-- There is also an array made up of faces.
-----------------------------------------------------------------
verticesArrays=#() ;
facesArrays=#() ;
boneAssignments=#() ;
submeshesId=#() ;
materialName = "" ;
-- verticesArrays[i] will describe the subMesh number i and its elements will be ogreVertices where
-- ogreVert = #(x,y,z,nx,ny,nz,r,g,b,a,u1,v1,u2,v2....)
-- ----- -------- ------- ---------------
-- Pos Nmal RGBA UVs sets
-- RGBA being the vertex color when relevant (Optional)
-- A vertex can contain multiple UVs sets (Optional)
-- facesArrays[i] is an array of Point3 describing the subMesh i. Each Point3 contains vertices indices for a face that is gonna be exported
-- boneAssignments[i] describes the bones assignements for subMesh i. It is an array of triplets like #(vertexIndex,boneIndex,weight)
-- submeshesId is the list of material Ids
-- materialName is the name that Ogre will use
----------------------------------------------------------------
-- exploreMesh returns a string which is "OK" or an error message
-- if there are warnings, it displays message boxes.
-----------------------------------------------------------------
function exploreMesh pmesh exportUV exportColours=
(
local material, answer, m ;
answer = "" ;
m = snapShotAsMesh pmesh ;
-- first, is a material defined ?
material = pmesh.material ;
if (material == undefined) then
answer = "This mesh doesn't have any material, please apply one\n" ;
else
-- then, are UVW coords set up ?
if (exportUV and getNumTVerts m == 0) then
answer = "This mesh must have UVW coords in order to be exported" ;
if (answer == "") then
answer = "OK" ;
delete m ;
answer ;
)
----------------------------------------------------------------
-- returns the correct normal for the vertex
-- according to smoothing groups
-----------------------------------------------------------------
function getVertexNormalAccordingToSmoothingGroups selectedMesh faceIndex vertexIndex =
(
local normal;
local faceSmoothingGroup = getFaceSmoothGroup selectedMesh faceIndex
if faceSmoothingGroup == 0 then
(
-- if not smooth use face normal
normal = getFaceNormal selectedMesh faceIndex
)
else
(
local vertexIndexes = getFace selectedMesh faceIndex;
local vI = vertexIndexes[vertexIndex]
local n = [0, 0, 0] -- point3
for adjoiningFaceIndex in (meshop.getFacesUsingVert selectedMesh vI) do
(
sg = getFaceSmoothGroup selectedMesh adjoiningFaceIndex;
and_sg = bit.and sg faceSmoothingGroup ;
if (and_sg != 0) then
n += getFaceNormal selectedMesh adjoiningFaceIndex ;
)
normal = normalize n;
)
normal;
)
function tabEquals tab1 tab2 =
(
if (tab1.count != tab2.count) then
return false;
for i=1 to tab1.count do
if (tab1[i] != tab2[i]) then
return false;
return true;
)
function doesVertexExistAlready searchTable vertexIndex vertexNormal vertexColorIndex vertexAlphaIndex UVs exportUV exportColor =
(
local start_uvs;
vertex = #();
--format "vertex a tester % % \n" vertexIndex vertexNormal;
if (searchTable[vertexIndex]==undefined) then
return 0;
for vertex in searchTable[vertexIndex] do
(
if (vertex[2]!=vertexNormal) then
continue;
if (exportColor) then
(
if (vertex[3]!=vertexColorIndex) then
continue;
if (vertex[4]!=vertexAlphaIndex) then
continue;
start_uvs = 4;
)
else
(
start_uvs = 2;
)
if (exportUV) then
(
local equal = true;
for i=1 to UVs.count do
(
if (vertex[start_uvs+i]!=UVs[i]) then
(
equal = false;
exit;
)
)
if (not equal) then
continue;
)
return vertex[1] ;
)
return 0;
)
----------------------------------------------------------------------------
-- Retrieves al the datas which wil be used
-- tmesh is the mesh object
-- flipyz = true if you want coords to fit in OGRE.
-- flipNormal = true if you want to flip normals
-- scale : the scale factor
-- exportUV = true if you want to export texture
-- numUVsets : number of texture coordinates to export (if exportUV is true, the minimum is 1. if exportUV is false, this parameter is irrelevant)
-- exportColor = true if you want to export vertices colors
-- sk : the skin modifier (may be undefined)
-- phy : the physique modifier (may be undefined)
-- stores datas in verticesArrays and facesArrays.
----------------------------------------------------------------------------
function getDatas tmesh flipyz scale flipNormal exportUV numUVsets exportColours exportHelpers sk phy =
(
local face; --index of the current face
local localVertexIndex; --index of the current vertex (relative to the current face) ie : 1, 2 or 3
local vertexNormal; --normal of the current vertex (Point3)
local vertexPosition; --position of the current vertex (Point3)
local faceVerticesIndices; --indices of the vertex for the current face (Point3)
local vertexIndex; --index of the current vertex (in the mesh)
local matId; --material Id of the current face
local numFaces; --number of faces in the mesh
local faceVertexColorIndices; --indices of the vertices for the current face in the vertex color table of the mesh (Point3)
local vertexColorIndex; --index of the current vertex in the vertex color table of the mesh
local vertexColor; --vertex color for the current vertex (color)
local faceVertexAlphaIndices; --indices of the vertices for the current face in the vertex alpha table of the mesh (Point3)
local vertexAlpha; --vertex alpha of the current alpha
local vertexAlphaIndex; --index of the current vertex in the vertex alpha map channel (-2)
local ogreFace; --indices of the vertices for the current face (references the list of vertices that is gonna be exported, not the vertices of the original mesh)
local vertexWeightCount; --number of bones influencing the current vertex
local vertexWeight; --current weight
local searchTable ;
local k ;
local rootId ;
local UVcoords; -- will contain the texture coordinates for the current vertex. its size will be numUVsets*2 if exportUV is true.
-- searchTables will contain a searchTable for every subMesh.
-- searchTable will be the current table for the current subMesh.
-- Every vertex will be stored here to check for duplicates.
searchTable=#() ;
searchTables=#() ;
-- initialisation of the current ogre face as a vector
ogreFace=Point3 12 12 12 ;
-- Data arrays init.
verticesArrays=#() ;
facesArrays=#() ;
boneAssignments = #() ;
submeshesId = #() ;
UVcoords=#() ;
-- compute bones list for the model.
BonesList=#()
computeBonesList phy sk exportHelpers ;
numFaces = (getNumFaces tmesh);
-- For each face
for face = 1 to numFaces do -- LOOP on FACES --
(
OgreExportObject.exportProgress.value = (100.0*face/numFaces);
faceVerticesIndices = getFace tmesh face ;
matId = getFaceMatId tmesh face ;
-- Vertex Color Face
if (exportColours) then
(
faceVertexColorIndices = meshOp.getMapFace tmesh 0 face ; -- 0 is the vertex color channel
faceVertexAlphaIndices = meshOp.getMapFace tmesh -2 face ; -- -2 is the vertex alpha channel
)
else
(
faceVertexColorIndices = Point3 1 1 1 ;
faceVertexAlphaIndices = Point3 1 1 1 ;
)
-- For each vertex whose face is made up of.
for localVertexIndex=1 to 3 do -- LOOP on VERTICES --
(
vertexIndex = (int) (faceVerticesIndices[localVertexIndex]) ;
vertexColorIndex = (int) (faceVertexColorIndices[localVertexIndex]) ;
vertexAlphaIndex = (int) (faceVertexAlphaIndices[localVertexIndex]);
vertexNormal = getVertexNormalAccordingToSmoothingGroups tmesh face localVertexIndex;
-- flip normal capability
if (flipNormal) then
(
vertexNormal = vertexNormal * -1
)
-- we retrieve datas. it depends on options.
-- UV face
if (exportUV) then
(
UVcoords=#();
for ch=1 to numUVsets do
(
local vertInds = meshOp.getMapFace tmesh ch face ;
local UVW = meshOp.getMapVert tmesh ch vertInds[localVertexIndex] ; -- retrieve the UV for the corresponding channel.
append UVcoords UVW[1];
append UVcoords UVW[2]; -- don't care about the W coordinate
)
)
else
(
UVcoords=#();
)
-- we try to find the corresponding searchtable.
if (searchTables[matId] == undefined ) then
searchTables[matId]=#() ; -- we found a new subMesh, create the searchTable for it
searchTable = searchTables[matId] ; -- set the searchTable to the current subMesh
newVertex = 1 ;
ogreVertNum = 1;
-- Maybe this vertex has already been found.
-- So we use searchTable.
res = doesVertexExistAlready searchTable vertexIndex vertexNormal vertexColorIndex vertexAlphaIndex UVcoords exportUV exportColours;
if (res==0) then
(
newVertex = 1 ;
--format "nouveau vertex % % %\n" vertexIndex vertexNormal UVcoords;
)
else
(
newVertex = 0;
ogreVertNum = res;
)
if (newVertex == 1) then -- That is to say it has not been found.
(
-- Maybe the material found defines a new submesh...
if (verticesArrays[matId] == undefined) then
(
format "- Submesh detected: material ID = %\n" matId
verticesArrays[matId] = #() ;
boneAssignments[matId] = #() ;
append submeshesId matId ;
)
-- the vertex number for the current submesh must be updated
-- vertex number is increased
ogreVertNum = verticesArrays[matId].count + 1;
-- it is added to the searchTable
if (searchTable[vertexIndex]==undefined) then
(
searchTable[vertexIndex] = #() ;
)
local data = #();
append data ogreVertNum ;
n = copy vertexNormal ;
append data n ;
if (exportColours) then
(
append data VertexColorIndex ;
append data VertexAlphaIndex ;
)
if (exportUV) then
(
if (UVcoords.count > 0) then
(
for uv=1 to UVcoords.count do
append data UVcoords[uv];
)
)
append searchTable[vertexIndex] data ;
-- we retrieve data
vertexPosition = getVert tmesh faceVerticesIndices[localVertexIndex] ;
vertexColor = Point3 0 0 0;
vertexAlpha = 255;
if (exportColours) then
(
vertexColor = (meshOp.getMapVert tmesh 0 vertexColorIndex);
vertexAlpha = (meshOp.getMapVert tmesh -2 vertexAlphaIndex)[1];
)
-- change scale
vertexPosition = vertexPosition * scale ;
-- flip axes
if (flipyz) then
(
vertTmp = copy vertexPosition ;
vertexPosition[2] = vertTmp[3] ;
vertexPosition[3] = -vertTmp[2] ;
nmalTmp = copy vertexNormal ;
vertexNormal[2] = nmalTmp[3] ;
vertexNormal[3] = -nmalTmp[2] ;
)
-- store the vertex in verticesArrays
vertexData = #(vertexPosition[1],vertexPosition[2],vertexPosition[3],vertexNormal[1],vertexNormal[2],vertexNormal[3],vertexColor[1],vertexColor[2],vertexColor[3],vertexAlpha) ;
if (exportUV) then
(
for ch=1 to numUVsets do
(
append vertexData UVcoords[1+(ch-1)*2];
append vertexData UVcoords[2+(ch-1)*2];
)
)
append verticesArrays[matId] vertexData ; -- Vertex is added to datas
-- And now, bone assignments. (if a skin modifier is present)
-- It seems that there are issues when just few vertices have bone assignments.
-- So there is at least the root assignment.
if (sk != undefined) then
(
vertexWeightCount = skinOps.getVertexWeightCount sk vertexIndex ;
if (vertexWeightCount > 4) then
(
if (not g_MAX) then
(
format "*** vertex % has more than 4 bones assigned...\n" vertexIndex;
)
)
for k=1 to vertexWeightCount do
(
bid = skinOps.getVertexWeightBoneID sk vertexIndex k ;
bname = skinOps.getBoneName sk bid 1 ;
bname = replaceSpaces bname;
vertexWeight = skinOps.getVertexWeight sk vertexIndex k ;
id_bone = findItem BonesList bname;
if (id_bone != 0) then
append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,vertexWeight) ;
)
-- assignment to the root bone.
if (vertexWeightCount==0) then
(
-- gets the root Id:
rootId=getRootsId sk
rootname = skinOps.getBoneName sk rootId[1] 1 ;
id_bone = findItem BonesList rootname ;
if (id_bone != 0) then
append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,1) ;
)
)
-- same thing with physique modifier if defined
if (phy != undefined) then
(
vertexWeightCount = physiqueOps.getVertexBoneCount $ vertexIndex ;
if (vertexWeightCount > 4) then
(
if (not g_MAX) then
(
format "*** vertex % has more than 4 bones assigned...\n" vertexIndex;
)
)
for k=1 to vertexWeightCount do
(
bone = physiqueOps.getVertexBone $ vertexIndex k
vertexWeight = physiqueOps.getVertexWeight $ vertexIndex k
-- search the bone number
bname = replaceSpaces bone.name;
id_bone = findItem BonesList bname ;
if (id_bone!=0) then
append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,vertexWeight) ;
)
-- assignment to the first bone if the vertex was not assigned.
if (vertexWeightCount==0) then
(
-- gets the root Id:
append boneAssignments[matId] #(ogreVertNum-1,0,1) ;
)
)
)
ogreFace[localVertexIndex] = ogreVertNum - 1;
)
-- flip normal capability
if (flipNormal) then
(
faceTmp = copy ogreFace ;
ogreFace[2] = faceTmp[3] ;
ogreFace[3] = faceTmp[2] ;
)
if (facesArrays[matId] == undefined) then
facesArrays[matId] = #() ;
append facesArrays[matId] #(ogreFace[1],ogreFace[2],ogreFace[3]) ; -- Face is added to datas
)
)
-------------------------------------------------
-- writes in the mesh.xml file
-- outName : filename
-- exportUV = true if you want to export texture
-- numUVsets : number of UVs sets per vertex to be exported (only relevant if exportUV = true)
-- exportColor = true if you want to export vertices colors
-- material : material used by the mesh
-- Uses the arrays verticesArrays and facesArrays
-------------------------------------------------
function writeM exportUV numUVsets exportColours material outName =
(
local a,v,f,submatname,hasSkeleton,outFile,hasColours,matId ;
hasSkeleton = false ;
texCoordString = "" ;
if (exportUV) then
(
texCoordString = "texture_coords=\"" + (numUVsets as string) + "\" " ;
for num=1 to numUVsets do
(
texCoordString = texCoordString + "texture_coords_dimensions_" + ((num-1) as string) + "=\"2\" "; -- I really don't care about the W coordinates
)
)
hasColours = "false" ;
if (exportColours) then
hasColours = "true" ;
-- the final file is created
if (g_MAX) then
(
ClearListener();
if (g_MAX_use_listener) then
format("<ogrestartfile>%</ogrestartfile><ogrestartdata>\n") (outName + ".mesh.xml");
outFile = listener;
)
else
(
outFile = createfile (outName + ".mesh.xml") ;
)
-- writes the header
format("<mesh>\n") to:outFile ;
-- submeshes start
format("\t<submeshes>\n") to:outFile ;
-- for each submesh
for matId in submeshesId do
(
-- Do we need 32-bit indexes?
use32bitindexes = "false";
if arrayLength verticesArrays[matId] > 65535 then
use32bitindexes = "true";
-- get the name of the sub material if needed.
submatname = replacespaces material.name ;
if (classof material == MultiMaterial) then
(
if (material.materialList[matId]==undefined) then
(
msg = "";
format "You are using in your mesh a material Id (%) that does not exist in your MultiMaterial (%)\nMaterial information won't be properly exported." matId submatname to:msg ;
messageBox msg;
)
else
(
submatname += "/" + replacespaces material.materiallist[matId].name ;
)
)
-- HELLO ! --
---------------------------------------------------------------------------------
-- IF YOU COME HERE BECAUSE YOUR OBJECT FAILED EXPORTING, MAYBE THAT'S BECAUSE --
-- YOU USE MATERIAL ID IN YOUR MESH THAT DOESN'T EXIST IN YOUR MULTIMATERIAL --
---------------------------------------------------------------------------------
format("\t\t<submesh material = \"%\" usesharedvertices=\"false\" use32bitindexes=\"%\">\n") submatname use32bitindexes to:outFile ;
if (not g_MAX) then
format "- writing faces...\n"
format("\t\t\t<faces count=\"%\">\n") (arraylength facesArrays[matId]) to:outFile;
-- for each face
for f in facesArrays[matId] do
(
format("\t\t\t\t<face ") to:outFile ;
format("v1=\"%\" v2=\"%\" v3=\"%\" />\n") ((int)f[1]) ((int)f[2]) ((int)f[3]) to:outFile ;
)
format("\t\t\t</faces>\n") to:outFile ;
if (not g_MAX) then
format "- writing vertices...\n"
format("\t\t\t<geometry vertexcount=\"%\">\n") (arrayLength verticesArrays[matId] ) to:outFile;
format("\t\t\t\t<vertexbuffer positions=\"true\" normals=\"true\" colours_diffuse=\"%\" %>\n") hasColours TexCoordString to:outFile ;
-- for each vertex
for v in verticesArrays[matId] do
(
format("\t\t\t\t\t<vertex>\n") to:outFile ;
format("\t\t\t\t\t\t<position x=\"%\" y=\"%\" z=\"%\" />\n") v[1] v[2] v[3] to:outFile ;
format("\t\t\t\t\t\t<normal x=\"%\" y=\"%\" z=\"%\" />\n") v[4] v[5] v[6] to:outFile ;
if (exportUV) then
(
for ch=1 to numUVsets do
format("\t\t\t\t\t\t<texcoord u=\"%\" v=\"%\" />\n") v[11+((ch-1)*2)] (1 - v[12+((ch-1)*2)]) to:outFile ;
)
if (exportColours) then
(
color_string = (v[7] as string) + " " + (v[8] as string) + " " + (v[9] as string) + " " +(v[10] as string);
format("\t\t\t\t\t\t<colour_diffuse value=\"%\" />\n") color_string to:outFile ;
)
format("\t\t\t\t\t</vertex>\n") to:outFile ;
)
format("\t\t\t\t</vertexbuffer>\n") to:outFile ;
format("\t\t\t</geometry>\n") to:outFile ;
-- and now bone assignments (and skeleton), if there is at least one element in boneAssignments array.
if ((arrayLength boneAssignments[matId]) != 0) then
(
hasSkeleton = true ;
if (not g_MAX) then
format "- writing bone assignments...\n"
format("\t\t\t<boneassignments>\n") to:outFile ;
for a in boneAssignments[matId] do
(
format("\t\t\t\t<vertexboneassignment vertexindex=\"%\" boneindex=\"%\" weight=\"%\" />\n") a[1] a[2] a[3] to:outFile ;
)
format("\t\t\t</boneassignments>\n") to:outFile ;
)
-- submesh end
format("\t\t</submesh>\n") to:outFile ;
)
-- submeshes end
format("\t</submeshes>\n") to:outFile ;
-- Skeleton link if there is at least one bone assignement.
if (hasSkeleton) then
(
t = filterstring outName "\\" ;
format ("\t<skeletonlink name=\"%\"/>\n") (t[arrayLength t] + ".skeleton") to:outFile ;
)
format("</mesh>\n") to: outFile ;
if (not g_MAX) then
(
close outFile ;
)
else
(
if (g_MAX_use_listener) then
format("</ogrestartdata>\n") to: outFile;
)
)
---------------------------------
-- writes the mesh: main function
---------------------------------
function writeMesh pmesh exportOptions out_name =
(
local m,sk,outFile,message,phy ;
m = snapshotAsMesh pmesh ;
-- tries to find errors
message = exploreMesh pmesh exportOptions.exportUV exportOptions.exportColours;
if (message != "OK") then
(
MessageBox ("\n There is a problem with your mesh:\n" + message + "\n\nOperation aborted") ;
delete m ;
return false ;
)
else
(
format "\n\n"
format "------------------------------------------\n"
format "------- OGRE Mesh Exporter Log -------\n"
format "----- -----\n"
-- get the skin modifier ( may be undefined )
-- and physique modifier
phy = getPhysique pmesh ;
sk = getSkin pmesh;
if (sk != undefined) then
format "Skin modifier detected.\n"
if (phy != undefined) then
format "Physique modifier detected.\n"
-- if not undefined, skin modifier is selected in modifier tab. Or there will be an error.
if (sk != undefined) then
(
-- in order to perform, skin should be opened
max modify mode ;
modPanel.setCurrentObject pmesh.modifiers[#Skin] ;
)
-- physique
if (phy != undefined) then
(
-- in order to perform, skin should be opened
max modify mode ;
modPanel.setCurrentObject pmesh.modifiers[#Physique] ;
--physiqueOps.setInitialPose pmesh true ;
)
OgreExportObject.exportProgress.value = 0;
-- retieving material
if (pmesh.material != undefined) then (
materialName = pmesh.material.name ;
replaceSpaces materialName ;
)
else materialName = pmesh.name + "Material" ;
format "Material name exported : \n- %/*** \n" materialName ;
-- retrieving all datas
format "Retrieving vertices and faces data : \n" ;
getDatas m exportOptions.flipyz exportOptions.scale exportOptions.flipNormal exportOptions.exportUV exportOptions.UVchannels exportOptions.exportColours exportOptions.exportHelpers sk phy;
-- writing in the file
format "Writing in file %.mesh.xml : \n" out_name ;
WriteM exportOptions.exportUV exportOptions.UVchannels exportOptions.exportColours pmesh.material out_name ;
if (not g_MAX) then
format "Export successful.\n"
delete m ;
if (not g_MAX) then
(
format "----- -----\n"
format "---------- END ---------\n"
format "------------------------------------------\n"
)
--MessageBox ("Exporting mesh successful !") ;
OgreExportObject.exportProgress.value = 100;
)
return true ;
)