PDA

View Full Version : Mesh importer examples?


Anubis
11-01-2011, 08:35 AM
I am trying to make a mesh importer for a modding community in my spare time. Never really done this before.

The mesh format is something like this:

joints, parenting
every vertex - position, normal, vertex color, UV coords, joint influences, joint weights
triangulation data in three vert lines

Is there a good way to build a mesh vert by vert setting these as you go? Or do I need to make the mesh then iterate through the indices setting these?

CE

Anubis
11-01-2011, 01:07 PM
For example, if possible to generate a mesh from an ordered list of points, with metadata, like normal, UVs, etc, all in one go.

zoharl
11-02-2011, 01:26 AM
I don't understand, are you looking for a secret way that do this, which autodesk hides, and thus is not written in the api doc? :rolleyes:

Anyhow:

MFnMesh:create - create mesh vertices / faces
MFnMesh:setNormals - ...
MFnMesh:setUvs - ...

Each of them takes an array.

If you want I can write a function that takes all your params and call these functions ;)

Anubis
11-02-2011, 01:56 AM
Yeah, I had been looking for a way to do it in mel or python commands, but I suppose I should check OpenMaya API.. just not too experienced there.

Thanks,

Anubis
11-05-2011, 04:35 PM
I am just trying to make a single triangle.. the lack of documentation and examples online for the openMaya python API makes things a bit daunting..

It just seems to say 'failure', which is not too useful:
# Error: (kFailure): Unexpected Internal Failure


import maya.OpenMaya as om

vertexArray = om.MFloatPointArray()
uArray = om.MFloatArray()
vArray = om.MFloatArray()

numVertices = 1
numPolygons = 3
vertices = [(0,0,0), (0,0,1.01), (0,1.12,1)]
uvs = [(0,0), (0,1), (1,1)]
conns = [1,2,3]

pCounts = om.MIntArray()
for i in vertices: pCounts.append(3)
pConnects = om.MIntArray()
for c in conns: pConnects.append(c)

for i in range(0, len(vertices)):
#Store the points
pt = om.MFloatPoint(vertices[i][0],vertices[i][1], vertices[i][2])
vertexArray.append(pt)
uArray.append(uvs[i][0])
vArray.append(uvs[i][1])

#Now create the mesh
#build components
mesh = om.MFnMesh()
meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, uArray, vArray)

zoharl
11-05-2011, 05:52 PM
The API hardly works with C++, you expect it to work with a bridged python?!

Anyway I made a few changes, and tried my own luck:

import maya.OpenMaya as om

vertexArray = om.MFloatPointArray()
uArray = om.MFloatArray()
vArray = om.MFloatArray()

numVertices = 3
numPolygons = 1
vertices = [(0,0,0), (0,0,1.01), (0,1.12,1)]
uvs = [(0,0), (0,1), (1,1)]

pCounts = om.MIntArray()
pCounts.append(3)
#pCounts = (3,3,3)
pConnects = om.MIntArray()
#pConnects = (1,2,3)
pConnects.append(1)
pConnects.append(2)
pConnects.append(3)

for i in range(0, len(vertices)):
pt = om.MPoint()
pt = vertices[i]
vertexArray.append(pt[0],pt[1],pt[2])
uArray.append(uvs[i][0])
vArray.append(uvs[i][1])

#parent = om.MObject()
parent = om.MObject.kNullObj
status = om.MStatus()
mesh = om.MFnMesh()
print numVertices
print numPolygons
print vertexArray
print pCounts
print pConnects
print parent
print status
outmesh = om.MObject()
#meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, uArray, vArray, parent, status)
meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, parent, status)
meshName = om.MFnDependencyNode(meshMObj).name()





But I faced the same problem: 'Wrong number of parameters', while I specifically give it what it wants

There's a sample code here for python, and the guy said it worked. Maybe you should give it a try:

http://forums.cgsociety.org/showthread.php?f=89&t=644997

Anubis
11-05-2011, 06:29 PM
Since that thread's closed, here's the code nicely formatted:
http://pastebin.com/JGXxvXgz

It does work, but doesn't look too different than what we're doing.

I will take a look.

WesHowe
11-05-2011, 09:16 PM
Not a python expert at all. But is would appear you are building a loop base on len(vertices), which I think is 9 (floats) not 3, as in point array.

Here is a working C++ example of making a mesh from an array of data loaded previously into structs :


verts.clear();
for(i=0; i<GL->VertexCount; ++i) {
verts.append((double)GL->VertPool[i].verts[0],
(double)GL->VertPool[i].verts[1],
(double)GL->VertPool[i].verts[2]);
}
uArray.clear();
vArray.clear();
for(i=0; i<GL->UVCount; ++i) {
uArray.append(GL->UVs[i][0]);
vArray.append(GL->UVs[i][1]);
}

polyCounts.clear();
polyConnects.clear();

for(i=0; i<GL->numFaces; ++i) {
polyCounts.append(GL->PolyPool[i].fpcount);
for(j=0; j<GL->PolyPool[i].fpcount; ++j) {
polyConnects.append(GL->PolyPool[i].vindex[j]);
} // for(j)
} // for(i)

meshTransform=meshFn.create(GL->VertexCount, GL->numFaces, verts, polyCounts, polyConnects,
uArray, vArray, MObject::kNullObj, &stat);
if(stat!=MS::kSuccess) {return(StatusString(stat, "Could not create meshFn: "));}


In this code, all of the data pointed to by GL was derived from some different code that read a file and populated the structure with arrays of vertex positions, uvs, normals and other stuff. One part that may be different is that this code will manage other than triangle face point counts, which was saved as "GL->PolyPool[i].fpcount". For a simple triangles-only app, just use a constant 3 instead.

Normals get added later, in another call, and the skin weights are done after that. Get this part working and then if you need more, we can build from there.

<* Wes *>

zoharl
11-05-2011, 09:37 PM
I have a C++ working code, that's not the problem. I might have a problem with the numbers I put in the arrays, I didn't check them through. We still face a basic error:

# Error: NotImplementedError: Wrong number of arguments for overloaded function 'MFnMesh_create'.
Possible C/C++ prototypes are:
create(int,int,MFloatPointArray const &,MIntArray const &,MIntArray const &,MObject,MStatus *)
create(int,int,MPointArray const &,MIntArray const &,MIntArray const &,MObject,MStatus *)
create(int,int,MFloatPointArray const &,MIntArray const &,MIntArray const &,MFloatArray const &,MFloatArray const &,MObject,MStatus *)
create(int,int,MPointArray const &,MIntArray const &,MIntArray const &,MFloatArray const &,MFloatArray const &,MObject,MStatus *) #


Which says that we are calling the function itself in a wrong way.

Anubis
11-05-2011, 10:45 PM
cedricB on tech-artists.org got this working, with some comments:
http://pastebin.com/FcrXhMzL

good stuff.

zoharl
11-05-2011, 11:30 PM
First, give a nice one to Cedric! I'm curios, where's the discussion / post?

Second, the only difference is to declare a group as a parent, and not to use MStatus variable (as opposed to the claimed prototype). LAME! I'm mean, WTF, is this a guessing game, and if it is, what are these lame hints?!

I'm not sure about your pastebin, so for future reference:

## From cedricB

import maya.OpenMaya as om
import maya.cmds as cmds

def get_mobject(node):
selectionList = om.MSelectionList()
selectionList.add(node)
oNode = om.MObject()
selectionList.getDependNode(0, oNode)
return oNode

vertexArray = om.MFloatPointArray()
uArray = om.MFloatArray()
vArray = om.MFloatArray()

numVertices = 3
numPolygons = 1

vertices = [(0,0,0), (0,0,1.01), (0,1.12,1)]
uvs = [(0,0), (0,1), (1,1)]
conns = [0,1,2]
pConnects = om.MIntArray()
for c in conns: pConnects.append(c)

pCounts = om.MIntArray()

for o in range(numPolygons):
pCounts.append(3)# one triagle so add 3 vertices
uvCounts = om.MIntArray()
uvIds = om.MIntArray()

for i in range(0, len(vertices)):
pt = om.MFloatPoint(vertices[i][0],vertices[i][1], vertices[i][2])
vertexArray.append(pt)
uArray.append(uvs[i][0])
vArray.append(uvs[i][1])
uvIds.append(i)


# normally to fill uVcounts with only 1 UV set , the faceVertId are the same as face vert connection array : here 3 vertices/UV
uvCounts = pCounts

mesh = om.MFnMesh()

ShapeMesh = cmds.group(em=True) # <-- we create an empty group/ trnasform node that will receive the mesh node as a sibling
parentOwner = get_mobject( ShapeMesh )


meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, uArray, vArray ,parentOwner ) #<-- don't forget to add a parent owner
cmds.sets( ShapeMesh, e=True,forceElement='initialShadingGroup') # <--assign the defaut lambert shader

defaultUVSetName = ''
defaultUVSetName = mesh.currentUVSetName(-1)
mesh.assignUVs( uvCounts,uvIds, defaultUVSetName) #< even if uv a created you must assign them

WesHowe
11-06-2011, 01:11 AM
I'm curios, where's the discussion / post?

It's on this board: http://tech-artists.org/forum/ (http://tech-artists.org/forum/)

You might like to look around there, it is primarily technical artists (not all Maya, a lot of Max threads, too).

As for some of the other issues you guys are facing, those are exactly the reason I do not program in python. I'm just an old dog that knows only some old tricks.

<* Wes *>

Anubis
11-06-2011, 01:39 AM
I almost have my script working on a real dataset, but I just get an internal openMaya crash:

# Error: (kFailure): Unexpected Internal Failure # Traceback (most recent call last):
# File "<maya console>", line 177, in <module>
# File "<maya console>", line 166, in buildMesh
# File "c:\buildforge\Maya_2012_Win64_Build\build\wrk\optim\runTime\Python\Lib\site-packages\maya\OpenMaya.py", line 4736, in create
# RuntimeError: (kFailure): Unexpected Internal Failure #

This path isn't even from my PC.. I don't know what buildforge is.. why is this stuff so convoluted?

WesHowe
11-06-2011, 01:31 AM
kFailure is a pretty generic error. In my C source, the last parameter to the meshFn.create() call is &stat, which is a pointer to an MStatus variable. I check that in the following line, if it is not kSuccess then I bail.

However, most of the time when developing that code the call fails because you are passing something inconsistent.

* The number of vertices should equal the number of three-value items in your vertices MPointArray.
* The number of elements in pCounts should equal the number of polygons.
* The sum of the all the elements in your pCounts should be the same as the size of your pConnects array. If you are working with all triangles, then they should all be 3, and the size of the array times 3 must equal the number of triangles.
* The values you place in pConnects should be the indices of valid vertices, so the values must range between 0 and numVertices-1.

You never said what you are using for the source data, but if you are pulling stuff in from something like a .obj file, .obj files number vertices from 1, so you must subtract 1 from each value.

I would guess that if you coded each of those checks to a print() statement, and comment out your actual call to meshFn.create(), you should catch what is going wrong pretty quickly.

<* Wes *>

zoharl
11-06-2011, 05:51 AM
Wes, look at my comment earlier, I don't support the python idea either. From my point of view we are playing a game here...

A few more tips:

1. Use the create() that just construct a basic mesh first, without the uv-s an other stuff.

2. First step construct a mesh only with vertices and no faces - should work fine.
Second step add only the first triangle.
Add more triangles until you find the problem.

3. I hope that you pinpointed the problem to MFnMesh:Create() of course.


Maya is a harsh mistress...

Anubis
11-06-2011, 09:16 AM
Here's some printf debugging before I run the create:

print numVertices, vertexArrayLen, len(uArray), len(vArray), numPolygons, len(pCounts), vertexArray, parentOwner

2094 2094 2094 2094 3352 3352 <maya.OpenMaya.MFloatPointArray; proxy of <Swig Object of type 'MFloatPointArray *' at 0x15814040> > <maya.OpenMaya.MObject; proxy of <Swig Object of type 'MObject *' at 0x15813680> >

I created an om.MStatus() and passed it at the end, it then gives: Error: Wrong number of arguments

zoharl
11-06-2011, 10:40 AM
I think I specifically noted not to put mstatus. Here is a working variant of your code for creating a triangle: Just copy paste into the script editor.


import maya.OpenMaya as om
import maya.cmds as cmds

def get_mobject(node):
selectionList = om.MSelectionList()
selectionList.add(node)
oNode = om.MObject()
selectionList.getDependNode(0, oNode)
return oNode

vertexArray = om.MFloatPointArray()
uArray = om.MFloatArray()
vArray = om.MFloatArray()

numVertices = 3
numPolygons = 1
vertices = [(0,0,0), (0,0,1.01), (0,1.12,1)]
uvs = [(0,0), (0,1), (1,1)]

pCounts = om.MIntArray()
pCounts.append(3)
pConnects = om.MIntArray()
pConnects.append(0)
pConnects.append(1)
pConnects.append(2)

for i in xrange(len(vertices)):
pt = om.MPoint()
pt = vertices[i]
vertexArray.append(pt[0],pt[1],pt[2])
uArray.append(uvs[i][0])
vArray.append(uvs[i][1])

#parent = om.MObject()
parent = om.MObject.kNullObj
status = om.MStatus()
mesh = om.MFnMesh()
ShapeMesh = cmds.group(em=True)
parentOwner = get_mobject( ShapeMesh )
#meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, uArray, vArray, parentOwner, status)
meshMObj = mesh.create(numVertices, numPolygons, vertexArray, pCounts, pConnects, parentOwner)

meshName = om.MFnDependencyNode(meshMObj).name()

WesHowe
11-06-2011, 03:05 PM
It is a finely balanced set of teacups. Once you have the issues resolved getting a visible result, then you can add to it a bit at a time.

As far as python goes, it works well on some other applications (like Blender) as a scripting language. But the interface to Maya's existing API seems like trying to marry a pig and a cow... they are both useful, but hardly compatible.

<* Wes *>

Anubis
11-07-2011, 09:57 PM
Here's some printf debugging before I run the create:

print numVertices, vertexArrayLen, len(uArray), len(vArray), numPolygons, len(pCounts), vertexArray, parentOwner

2094 2094 2094 2094 3352 3352 <maya.OpenMaya.MFloatPointArray; proxy of <Swig Object of type 'MFloatPointArray *' at 0x15814040> > <maya.OpenMaya.MObject; proxy of <Swig Object of type 'MObject *' at 0x15813680> >

I created an om.MStatus() and passed it at the end, it then gives: Error: Wrong number of arguments

Ok guys, I now have complex meshes loading. Maya gives you basically no error feedback, but through trial and error I saw the stupid error.

I had one polygon less than I should have in my pConnects because I iterated over the 'numFaces', not 'numFaces + 1'.

WesHowe
11-07-2011, 11:09 PM
Good. There is more that I did not show for connecting the UVs to the vertices, adding the normals and creating joints and adding skin weights. Every one of those has some quirks (unrelated to python) that are not apparent from the docs.

BTW the Maya 2012 API docs have some additional clarification on what is supposed to be in some of those arrays... some are indices of faces and some are indices of the vertices, and the 2012 docs describe that a little better. I don't think the API actually changed (at least not for MFnMesh), just a better description of the function call parameters.

<* Wes *>

Anubis
11-08-2011, 12:22 AM
Heh, yeah I went onto UVs, then decided to do skinning first. At least skinning has feedback, the API stuff has terrible error feedback.

I am trudging through skinning and I will do UVs, normals, textures and shading next.

Robert Bateman
11-08-2011, 10:54 AM
Ok guys, I now have complex meshes loading. Maya gives you basically no error feedback, but through trial and error I saw the stupid error.

It gives you an MStatus for every single API call which, when cross referenced with the API docs, gives plenty of error feedback.

zoharl
11-08-2011, 02:34 PM
Robert:

First, give a nice one to Cedric! I'm curios, where's the discussion / post?

Second, the only difference is to declare a group as a parent, and not to use MStatus variable (as opposed to the claimed prototype). LAME! I'm mean, WTF, is this a guessing game, and if it is, what are these lame hints?!
:argh:

And even for C++, try to pass wrong indices... An immediate crash, or 'an internal error' code hardly qualify as feedback.

Anubis
11-08-2011, 02:56 PM
Robert, in the above we stopped passing in an MStatus because it wasn't working. Could you edit the code example to show a working MStatus that gives useful feedback showing the problem?

WesHowe
11-08-2011, 03:44 PM
Chris:

cedricB posted a docs reference I read (over at TechArtistsOnline) that shows MStatus is removed from all of the python API calls. The information provided by the MStatus return is piped to the exception process for python. By adding try: and except: to you code, you can get as much information about an API call failure/success as in C++.

Which is not often very detailed. You can just about use random numbers in some of the arrays, as long as there are the correct number of them and you range check them (like the short list I made for you).

Since you are just getting this project off the ground, this would be a good time to get that incorportaed into your project. Look at the Maya API docs for the page "Exceptions versus MStatus" (I was going to post to a link, but it is my off-line copy and I know you will be unable to access MY harddisk) and there is an example of an API call using try/except/else to catch and handle errors.

<* Wes *>

Anubis
11-12-2011, 12:41 AM
So the data I was importing was ascii files from dxRipper and other game rippers. Only things left are importing the geometry normals correctly, and some weird UV offsets. Other than that, everything imports fine just like below:

http://www.chrisevans3d.com/temp/forums/importer.jpg
http://http://chrisevans3d.com/temp/forums/maya_importer.png

zoharl
11-14-2011, 09:48 AM
Cool ............. :cool:

CGTalk Moderation
11-14-2011, 09:48 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.