Home Technical Talk

Maxscript model exporter troubles

polycounter lvl 19
Offline / Send Message
Rekmar polycounter lvl 19
hello there,
I'm working on a Maxscript model exporter for my game. it's actually based on someone else's code but I've had to modify it to suit the game and I now got a pretty good understanding of it.
however I'm having some problems with the uwv's. wherever there's a seam in the uwv's I get a weird result, and I can't seem to fix it.

here's a pic of what I'm getting: (in-game vs. max)
uwvseambugan6.th.jpg
you can see it works just fine where there are no seams. also it seems the model needs an Unwrap UWV modifier on top or else the exported uwvs are garbage.

and here's the code I'm using to export the uwv's:
for i=1 to obj.numfaces do
(
face = getFace obj i
for h=1 to 3 do 
(
    ... (here goes some code to export the vertexes) ...
 
    -- get and export vert uwvs
    vert = (getTVert obj face[h])
    -- 1-vert = we flip the uwv's in Y, the engine needs them that way
    verty = 1-vert.y
    vert2x = formattedPrint vert.x format:"#.6f"
    vert2y = formattedPrint verty format:"#.6f"
    format " % %" vert2x vert2y to:outFile 
    format "\n" to:outFile
)--end of for each face index
)-- end of for each face

as you can see the code loops through all faces and inside that loop it loops for all 3 verts of each face, gets and exports the verts (I skipped that part of the code here) and its uwvs

I use formattedPrint because too often I get way too many numbers resulting in "e-008" stuff, and so I can take those away limiting to 6 decimals (what the engine likes)

any ideas?
thanks

Replies

  • renderhjs
    Offline / Send Message
    renderhjs sublime tool
    I wrote once my own binary exporter also for custom engine. The code doesn´t care about modifier´s or whatever is on the stack, all that matters is the final state of the mesh. WHat it does is it takes a snapshot of the mesh/poly (converted to mesh) and read out that data.

    There was some hack around the UV extraction but I can´t remember anymore what - it had to do something with the order to access the data so that in the end I was forced to do it in a certain way. Anyway this code should work.

    may this be of help
    theObj = selection[1];--selected object
    
    tmesh = 	snapshotasmesh  theObj --snapshot the TriMesh of the object
    num_verts =	tmesh.numverts; --get the number of vertices
    num_faces = tmesh.numfaces;
    num_tverts = tmesh.numTVerts;
    
    filename = writeBinary.txt.text;
    tSize = texSize.text as Number;
    
    f = fopen filename "wb";
    WriteShort f num_verts;		--vertices amaunt
    WriteShort f num_faces;		--faces amount
    WriteShort f num_tverts;	--uv vertices amount
    	
    if (tSize != undefined)then
    	WriteShort f tSize;
    else(
    	tSize = 512;
    	WriteShort f tSize;
    	texSize.text = tSize as String;
    )
    -------------------		
    
    for v = 1 to num_verts do
    (
    	p = getVert tmesh v;
    	x = p.x as Integer;
    	y = p.y as Integer;
    	z = p.z as Integer;
    	if (chkPivot.checked == true) then(
    		x= x-theObj.pos[1];
    		y= y-theObj.pos[2];
    		z= z-theObj.pos[3];
    	)
    	WriteShort f x;
    	WriteShort f y;
    	WriteShort f z;
    )
    for v = 1 to num_faces do
    (
    	p = getFace tmesh v;
    	x = p.x as Integer -1;
    	y = p.y as Integer -1;
    	z = p.z as Integer -1;
    	
    	WriteShort f x;
    	WriteShort f y;
    	WriteShort f z;
    )
    --texture vertices
    for v = 1 to num_tverts do
    (
    	p = GetTVert tmesh v;
    	x = (p.x)*tSize as Integer;
    	y = -((p.y)*tSize as Integer)+tSize;
    	WriteShort f x;--0 -> 512
    	WriteShort f y;
    )
    --texture face ID´s
    for v = 1 to num_faces do
    (
    	p = GetTVFace tmesh v;
    	x = p.x as Integer -1;
    	y = p.y as Integer -1;
    	z = p.z as Integer -1;
    	
    	WriteShort f x;
    	WriteShort f y;
    	WriteShort f z;
    )
    fclose f;
    
  • Rekmar
    Offline / Send Message
    Rekmar polycounter lvl 19
    oh yes I forgot the part where I copy the mesh and take it as a snapshot.
    the code I posted is the function to output the mesh (function OutputMesh), but I also do that in another section of the code.

    the following code happens when the export button is pressed. loops through all objects (skipping hidden and non-mesh-kinds) and then does the following:
    	dump = undefined
    	dump = copy obj
    	dump.name = obj.name -- will receive a new number ! so we need to do this
    	snapshotasmesh dump
    	OutputMesh dump meshbase obj.material.name chkYZswap.checked chkReOrg.checked chkNormal.checked chkTangent.checked chkBinormal.checked false
    	delete dump
    
    you can see it defines a new var, copies the object, snapshots it as mesh, runs the OutputMesh function (which is the code on my previous post), and then deletes that new created mesh.

    the weird thing is, it does snapshot the object as mesh (old code used convertToMesh but I changed it to snapshotasmesh and got the same result) and the output does change if I don't add the unwrap uwv modifier (garbage uwv's) as if not adding an unwrap uwv modifier would mean the mesh has no uwv's or something


    in the code you posted it does things in a very similar way. differences are that you loop through verts, faces, texture verts and texture verts separately, while I need them in the same loop (the engine's mesh format uses verts (position, normals and uwv's) in the same line, and then makes a list of the faces using the created vert index. so long story short, I do need to loop through faces and for every face loop through its 3 verts (I know this will output redundant verts, which I need)

    the other significant difference is how you multiply the texture vertex position * the texture size, which is unnecessary in my code (my format's uwv coordinates go from 0 to 1 like in max, so no matter if I change the texture size it will still work)


    --- conclusion
    if I replace the part of my code where it exports uwv's and replace it with that part of yours (removing the unnecessary "* texture size" I'll get the same results, as the process really is the same

    I'm going to try a few more stuff, see if something else works, but I'm open as to anything that might make my code more max-idioty-proof :)
  • renderhjs
    Offline / Send Message
    renderhjs sublime tool
    I did that texture size stuff to compress the filesize- because it was for a online engine.

    That´s odd,-
    did you tried to merge the whole stack so that you only have the poly without any modifiers any more on it- and then run the code ?
    alternativly but just like you said yourself you could convert or copy it via maxscript yourself, e.g
    Try(ConvertTo Selection[1] Editable_Poly)Catch()
    
  • Rekmar
    Offline / Send Message
    Rekmar polycounter lvl 19
    ok in further investigation it seems the problem is caused by missing TVerts.
    it seems the amount of TVerts is set by how many verts you have in the uwv's (for example by breaking poly's on unwrap uwv you get more)
    now, by needing all vertices in the mesh including redundant ones (num tris * 3) instead of actual all-welded mesh vertices or unwrap-uwv-vertices, there are less TVerts than vertices so when a certain vert (why on-a-seam ones though?) has no TVert it outputs garbage (and why not crash? :))

    to fix this, my guess would be to have all tris broke apart in the uwv's, as if I selected all tris and used 'break' on them one by one.
    any idea on how to do this via maxscript?

    thanks again


    [edit] on your question, when I tried before I always had my stack collapsed before running the code and got garbage without the unwrap uwv modifier. now I tried adding the unwrap uwv modifier and *then* collapsing the stack again. I don't get garbage everywhere anymore (like when I didn't add unwrap uwv), but I still get garbage on the seams



    [edit2] further investigation. I manually broke all verts in an unwrap uwv modifier. the amount of TVerts I now get is the same as my all-full-and-redundant verts (which is numtris * 3). however I still get garbage where there were seams before, like the pic I posted on my first post

    however I noticed something. if on unwrap uwv I go to select -> select inverted faces, a number of faces is selected, and it seems it's in the boundaries of these where I'm getting the weirdness.
    so how do I invert them back to un-inverted?

    [edit3] meh I just took some of the faces from the neck bottom (the stump) which were mirrored when they shouldn't (forgot to fix that some time ago). so if I select the inverted faces that part doesn't get selected anymore. BUT in-game that part is still messed up.
    so I guess it's got nothing to do with uwv-inverted faces (could have been backfaces or something, who knows). my loop just decides to hate those certain polygons' uwvs





    [edit4] ok I might have figured out why.
    while doing tests with some simpler geometry (an 8-segment sphere) I was able to get the uwv's exported just fine if I took all faces and collapsed them from eachother (this way I would have all vertexes as unique). the exported uwv's are fine but of course my normals are as if I applied a 0-value smooth (since faces are actually apart now).

    the explanation: on seams, the same vertex appears in more than one position in the uwv's. so when the exporter calls such a vertex for its uwv, it gets its uwv position wherever it finds it first (without caring if it corresponds to the same vertex of the neighbor face, which happens to be somewhere else in the uwv), and so, messing the output uwv's wherever there's a seam

    the solution: I'll make yet another copy of the mesh, explode all its faces, and use it for uwv data; while using the first copy for vertex/face/normal data

    hopefully it will work, wish me luck!

    [edit5] god!!!!! I got it to work just fine on that 8-segment sphere, but my character gets pure garbage uwv's. damn this is getting annoying
  • Rekmar
    Offline / Send Message
    Rekmar polycounter lvl 19
    ok I'm trying a new approach now. what I'm trying to do is to get the verts and tris from the uwv's first, and then try to get their position in the world. this way I'll get the correct amount of tris+verts regarding the uwv's: wherever there's a seam on the uwv's there will be a seam (invisible, thanks to the normals) on the mesh.

    for now I got a WIP that kinda works except for vertex positioning. I'm using the vertex UWV positions for vertex world positions so I end up with a (correctly uwv'ed) flat mesh (imagine the texture flattened, that's the mesh).

    so what do I need now? to get a vert index from a TVert index.
    why? well the indexes are different. since there are seams on the uwvs I have more verts in there than in the mesh.
    so what I need is to get, from a TVert index, the corresponding vertex index.
    for example when you select a vert on the unwrap uwv dialog, the corresponding vertex is red-highlighted in the viewport mesh, which means the TVert actually knows the Vert index. I need to know that index from maxscript.

    with the corresponding vert index I'd be able to get the vert position, and my vengeance to the old broken code would be complete :)

    in my head it would work something like "getVert obj getTVert i" from my i loop. of course things don't really work the way they do in my head (or else I my game would already be complete :) )
    any ideas?

    thanks again
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    Could you use the ePoly script function which gets geometry verts based on a uv vert ID?
    That way you can just go through the entire set of UVW verts, get the related geometric vert for each one, and discard it if it already exists.

    Can't remember the exact command, I think it's in polyOp, or might even be an unwrapUVW function.
  • Rekmar
    Offline / Send Message
    Rekmar polycounter lvl 19
    I looked for it in polyOp but didn't find anything like that, so I went on to the unwrapUWV functions.
    one of the new functions in max2008 seems it could work. it's called "getVertexGeomIndexFromFace" but it says it's exposed via unwrap6 interface which I have no idea (and can't find) how to use
    same thing could go if I used the functions selectVertices and then getSelectedGeomVerts, but they work via unwrap6 interface as well

    I tried "obj.unwrap_uvw.unwrap6.getVertexGeomIndexFromFace 100 1" but it says -- Unknown property "getVertexGeomIndexFromFace" in <MixinInterface:unwrap6>
    it's the same way calling an unwrap or unwrap2 interface works though, it just doesn't seem to like interface 6
  • KikiAlex
    change :
    dump = undefined
    dump = copy obj
    dump.name = obj.name -- will receive a new number ! so we need to do this
    snapshotasmesh dump
    OutputMesh dump meshbase obj.material.name chkYZswap.checked chkReOrg.checked chkNormal.checked chkTangent.checked chkBinormal.checked false
    delete dump
    
    with :
    dump = undefined
    dump = copy obj
    dump.name = obj.name -- will receive a new number ! so we need to do this
    modx = (Turn_to_Mesh useInvisibleEdges:false )
    addModifier dump modx
    convertToMesh dump
    OutputMesh dump meshbase obj.material.name chkYZswap.checked chkReOrg.checked chkNormal.checked chkTangent.checked chkBinormal.checked false
    delete dump
    
Sign In or Register to comment.