Sign in to follow this  
Kuraitou

MaxScript UV Coordinates

Recommended Posts

Kuraitou    250
Not sure if this is the right section for this, but here goes. For the last 2 or so weeks I have been trying to get a simple static-object MaxScript to work. It generates the correct geometry, but the UV coordinates are messed up. There's not much documentation on the subject and the little that exists is very hard to understand. It seems that there have been a few topics on this in the past on GDNet but the ~5 or 6 of the ones that I could find were not very helpful at all. Here is my Maxscript export function:
fn Export filename uvexport =
(
	fStream = fopen filename "wb"
	
	for obj in $ do
	(
		print "NumVerts="
		print obj.numverts
		
		print "NumFaces="
		print obj.numfaces
		
		writeLong fStream obj.numfaces
		
		for f = 1 to obj.numfaces do
		(
			face = getFace obj f
			
			vertx = getVert obj face.x
			verty = getVert obj face.y
			vertz = getVert obj face.z
			
			if (uvexport == true) do
			(
				tFace = meshOp.getMapFace obj 1 f -- getTVFace obj f
				
				uvwVertX = meshOp.getMapVert obj 1 tFace.x
				uvwVertY = meshOp.getMapVert obj 1 tFace.y
				uvwVertZ = meshOp.getMapVert obj 1 tFace.z
			)
			
			writeFloat fStream vertx.x
			writeFloat fStream vertx.y
			writeFloat fStream vertx.z
			if (uvexport == true) do
			(
				writeFloat fStream uvwVertX.x
				writeFloat fStream uvwVertX.y
			)
			
			writeFloat fStream verty.x
			writeFloat fStream verty.y
			writeFloat fStream verty.z
			if (uvexport == true) do
			(
				writeFloat fStream uvwVertY.x
				writeFloat fStream uvwVertY.y
			)
			
			writeFloat fStream vertz.x
			writeFloat fStream vertz.y
			writeFloat fStream vertz.z
			if (uvexport == true) do
			(
				writeFloat fStream uvwVertZ.x
				writeFloat fStream uvwVertZ.y
			)
		)
	)

	fflush fStream
	fclose fStream
	
	return true
)
And my C++ function to load it (some hardcoded stuff for now):
struct Vertex
{
	float x, y, z;
	float u, v;
};
struct Mesh
{
	int faceCount;
	int vertCount;
	Vertex *pVertices;
};

Mesh testmesh;

bool LoadMesh(const char *filename)
{
	std::ifstream file(filename, std::ios::binary);

	if (file.is_open())
	{
		file.read((char*)&testmesh.faceCount, 4);
		testmesh.vertCount = testmesh.faceCount * 3;

		testmesh.pVertices = new Vertex[testmesh.vertCount];

		for (int i = 0; i < testmesh.vertCount; i++)
		{
			file.read((char*)&testmesh.pVertices[i], sizeof(Vertex));
		}
	}
	else 
	{
		file.close();
		return false;
	}

	file.close();
	return true;
}
I am 110% sure that I am loading and displaying the mesh properly, and that Max's difficult UV system is to blame. Can anyone help me figure out how to properly associate the textured vertices with geometry vertices, or perhaps show me a very simple script for this? Thanks in advance.

Share this post


Link to post
Share on other sites
Gumgo    968
I recently did this and uv coords are a pain. What I did was create an array of vertices 3x the number of triangles, then get all the vertices' properties (position, normals, uv coords) using the functions that map those properties to the faces, then got rid of duplicates at the end. For uv coords you can't match a uv vertex with a vertex on the model because there may be multiple uv coords for that one vertex. You have to get the uv coords using the uv face functions because the faces in the uv map are the same as the ones on the model. When I get on my computer later today (iPhone right now) I can help you more with the specific functions needed. It took me forever to figure out and it is really annoying.

EDIT: Okay, so here's how I got it working.

First I defined a struct called vertex and allocated an array of vertices (3x the number of faces):

struct vertex
(
pos,
norm,
tex
)

smesh = snapshotAsMesh pickmmesh.object
tricount = smesh.numfaces
vertcount = tricount * 3

vert = #()
for a = 1 to vertcount do
vert[a] = vertex

Then to fill in the vertices' properties I did this:

for i = 0 to tricount-1 do -- for each triangle
(
vtx = getFace smesh (i+1) -- vtx = a point3 containing 3 vertex indices
vert[i*3+1].pos = getVert smesh vtx.x -- copy to new vertex list
vert[i*3+2].pos = getVert smesh vtx.y
vert[i*3+3].pos = getVert smesh vtx.z

nrm = meshop.getFaceRNormals smesh (i+1) -- nrm = an array of render normals
vert[i*3+1].norm = copy nrm[1] -- copy to new vertex list
vert[i*3+2].norm = copy nrm[2]
vert[i*3+3].norm = copy nrm[3]

tex = meshop.getMapFace smesh 1 (i+1) -- tex = an array of uv vertex indices
vert[i*3+1].tex = [(meshop.getMapVert smesh 1 tex.x).x, (meshop.getMapVert smesh 1 tex.x).y] -- copy to new vertex list
vert[i*3+2].tex = [(meshop.getMapVert smesh 1 tex.y).x, (meshop.getMapVert smesh 1 tex.y).y]
vert[i*3+3].tex = [(meshop.getMapVert smesh 1 tex.z).x, (meshop.getMapVert smesh 1 tex.z).y]
)

Then you can write to a file! What I actually did is instead of just writing the vertices, I removed duplicate vertices and wrote the list of remaining vertices followed by the list of triangle vertex indices. But that's something different.

[Edited by - Gumgo on August 11, 2008 11:36:32 AM]

Share this post


Link to post
Share on other sites
CarlML    215
One thing to keep in mind is that 0.0 in the y axis for max uv coords is at the bottom and 1.0 is at the top.

Like Gungo said, only the faces are the same for the mesh faces and texture faces. If there is a uv seam then there will be two (or more) texture vertices for a geometry vertex. The first geometry vertex on a face corresponds to the first texture vertex on a uv face, the second geometry vertex on the face cooresponds to the second uv vertex on the uv face and so on.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this