PDA

View Full Version : Very odd normals


CyberSlag5k
03-19-2005, 03:15 AM
My exporter is writing out some weird values for my normals and my material components. I get the normals and then multiply by the inverse of the scene translation as what I'm exporting is a single model (and thus I don't care where it's positioned in max). The code is fairly straightforward:


fn exportMaterial tempMat file =
(
if(classof tempMat == material) then
(
amb = tempMat.ambient
dif = tempMat.diffuse
spe = tempMat.specular

WriteFloat file (amb.r / 255.0)
WriteFloat file (amb.g / 255.0)
WriteFloat file (amb.b / 255.0)
WriteFloat file 0

WriteFloat file (dif.r / 255.0)
WriteFloat file (dif.g / 255.0)
WriteFloat file (dif.b / 255.0)
WriteFloat file 1

WriteFloat file (spe.r / 255.0)
WriteFloat file (spe.g / 255.0)
WriteFloat file (spe.b / 255.0)
WriteFloat file 1

WriteFloat file tempMat.glossiness
)
)

theObj = pickObject()
if superclassof theObj == GeometryClass do
(
tmesh = snapshotasmesh theObj
file = fopen "C:\\stuff2.dat" "wb"
num_verts = tmesh.numverts

WriteLong file num_verts
invTran = inverse theObj.transform
for v = 1 to num_verts do
(
tempVert = (getVert tmesh v) * invTran
WriteFloat file tempVert.x
WriteFloat file tempVert.y
WriteFloat file tempVert.z

tempNorm = (getNormal tmesh v) * invTran
WriteFloat file tempNorm.x
WriteFloat file tempNorm.y
WriteFloat file tempNorm.z
)

num_faces = tmesh.numfaces
WriteLong file num_faces
for f = 1 to num_faces do
(
tempFace = getFace tmesh f
WriteLong file (tempFace.x - 1) #unsigned
WriteLong file (tempFace.y - 1) #unsigned
WriteLong file (tempFace.z - 1) #unsigned
matID = getFaceMatId tmesh f
WriteLong file matID
)

tempMat = theObj.material
if classof tempMat == MultiMaterial then
(
WriteShort file tempMat.numsubs
for m = 1 to tempMat.numsubs do
exportMaterial tempMat[m] file
)
else
(
WriteShort file 1
exportMaterial tempMat file
)
fclose file
)


Pretty standard stuff. I read in the vertices and the normals in the same structure, in the same pass, and the object's shape is just fine, so I'm fairly confident the reader is not at fault for those guys. Anyway, some values I get for the normals are:


46.724743, -19.943460, -0.830547
47.048332, -20.267553, -0.691861
47.176949, -20.277395, -0.682462
47.570374, -19.913221, -0.813893
46.386112, -19.565418, -0.681445
46.767960, -19.852251, -0.886327
47.440182, -19.859411, -0.894221


Those are some pretty crazy numbers for normals, especially ones that are supposed to be normalized.

Here are 2 of the materials (ambient, diffuse, specular):


-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000
-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000
-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000

-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000
-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000
-431602080.000000, -431602080.000000, -431602080.000000, -431602080.000000



As you can see, the two materials are identical and completely bogus.

The importer is really really basic. It just calls a function that reads in the number of whatevers times the structer's size in bytes. I'm like 99% sure that's fine. So I'm obviously doing something really wrong here. Can anybody see what it is?

Thanks in advance!

magicm
03-19-2005, 01:26 PM
Have you tried printing tempNorm to the listener? If values come out wrong here as well, you at least know it's not caused by the importer.

- Martijn

ofer_z
03-19-2005, 04:49 PM
it might be a bit order problem (big/small endian) since you are using a binary format.
make sure you read the values the same as you write them.

hOpe this helps,
o

CyberSlag5k
03-19-2005, 06:25 PM
Have you tried printing tempNorm to the listener? If values come out wrong here as well, you at least know it's not caused by the importer.

- Martijn

Good idea, Martjin. In doing so I found out I was attempting to write tempNorm, not tempNormal (as the temporary variable is named). That was silly. You'd think it would have given me some sort of error or something. I guess, though, that since it's a script and not something compiled it did everything else it could, huh. oddly enough, though, that once I fixed the error and had it print tempNorm, the values were this (as printed in max):


[46.7247,-19.9435,-0.830547]

[47.0483,-20.2676,-0.691861]

[47.1769,-20.2774,-0.682462]

[47.5704,-19.9132,-0.813893]

[46.3861,-19.5654,-0.681445]

[46.768,-19.8523,-0.886327]

[47.4402,-19.8594,-0.894221]

[47.6585,-19.6641,-0.833306]

[46.5645,-19.2389,-0.773151]

[46.5146,-19.6378,-0.792603]


Do I perhaps need to re-normalize them after multiplying by the inverse of the transformation? I mean I suppose those values could be correct, but they're definitely not normalized.

Also, I fixed a typo in my materials so now they're outputting properly (I think, my visual studio project is ilke completely dead for some reason so I can't check right now, but that's a story for another thread), but this is what gets output:


(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0

(color 149.94 149.94 149.94)

(color 149.94 149.94 149.94)

(color 229.5 229.5 229.5)

10.0



The single float printed there is the glossiness.

It's weird that A) all of the materials are the same and B) they appear to be the default values. Something is still messed up :(.

CyberSlag5k
03-19-2005, 08:52 PM
A bit of an update, I've found that tempMat.numsubs is returning 10, which is I've learned is the default number of materials if none are specified. In actuality there are only about 7 materials used in the model. Can't max figure out that the multimaterial only has 7 submaterials defined and as such set numbsubs to seven? Or does this number need to be specified somewhere?

Thanks!

Bobo
03-19-2005, 10:02 PM
Dude, terribly sorry, it was my mistake!

Here is the deal:

When you are transforming vertices from world to local space, you WANT the inverse of the transformation matrix to contain both orientation, scale AND position, since the vertices have to be moved around.

When doing the same with the normals, you DON'T want the position to change, just the orientation. You can visualize the normal vector as a point on a sphere. The sphere has a center at the world origin and a radius of 1.0. ANY point on this sphere is defining a normal vector - the vector with start at [0,0,0], end at the Point3 value on the sphere and length of 1.0 == radius of the sphere!

Now when you take an existing normal in world space, it is pointing in world coordinates, but even when it is associated with a vertex that is thousands of units away from the world origin, the normal vector is still expressed as having its start at [0,0,0]. So when you multiply by the inverse of the node's transform, you are also shifting this normal in world space, changing its length!

The right way would be to first take the node transformation matrix and stuff it into a user variable:

theTM = theObject.transform

Then translate the matrix to the world origin - note that the ORIENTATION of the matrix does not change, only the translation which is stored in the 4th row in the case of Max (4th column in OGL)

theTM.row4 = [0,0,0]

Now you can take the inverse of this matrix and multiply your normals (for the vertices, use the full original node transform!).

theInvTM = inverse theTM

Multiplying vertex normals by this matrix will transform their orientation into local space, but not affect them by translating them away from the world origin.

Sorry you had to bump into this the hard way, I should have thought a bit more before letting you multiply vertex normals by the full inversed node transform...

Bobo
03-19-2005, 10:12 PM
A bit of an update, I've found that tempMat.numsubs is returning 10, which is I've learned is the default number of materials if none are specified. In actuality there are only about 7 materials used in the model. Can't max figure out that the multimaterial only has 7 submaterials defined and as such set numbsubs to seven? Or does this number need to be specified somewhere?

Thanks!


Max does not care how many material IDs are on the model, as you can have the SAME multi/sub material with 10 sub-materials assigned to thousands of objects, each of them having different number of MatIDs. As I mentioned before, the materials are assigned to the MatIDs using the MatIDs array and the modulo of the MatID:

If an object has only one MatID assigned to all its faces, the corresponding sub-material is used on them all. The other sub-materials still exist in the multi/sub material - it would be a disaster if Max would "fugure out" and remove the rest, because you might want to change the IDs later or even animate the MatIDs in the object using a procedural selection and the Material modifier, and you would like to keep the sub-materials as you defined them. Remember, the material is just assigned to the object, but is on itself an Object in OOP meaning and a pretty independent system from the scene geometry...

If an object has MatIDs that do not have a corresponding sub-material, the modulo calculation is performed to find one. So if you have a face MatID 7 with only sub-materials 1 to 6, the face will use sub-material 1...

If there is still no matching sub-material, the faces render back with no material at all.

When exporting, you should take care of these correspondences...
(still, Max is smarter than you think ;))

CyberSlag5k
03-21-2005, 03:00 AM
Thank you for your responses, Bilbo. No worries on the normal transformation matrix thing. I appreciate all the help you give me and it was a simple oversight anyone would make. I understand how that would be wreaing havoc on my normals, and it's good to know that max stores things in row-major order, rather than column major. I just atlered the exporter and the normals are normalized now :).

And as things stand, I realized it is of little consequence to me whether each of the 10 standard submaterials are defined or not because I only apply each material as a face needs it. While only 7 materials are defined in this particular model, the other 3 sub-materials don't ever get used (as they have no faces assigned to them).

Still, it worries me that garbage is being read in for the remaining 3. Wouldn't it make sense for max to store define them as the default upon export? I'm reading in the values such as these:

Material 7:
Ambient: -431602080.000000, -431602080.000000, -431602080.000000 -431602080.000000
Diffuse: -431602080.000000, -431602080.000000, -431602080.000000 -431602080.000000
Specular: -431602080.000000, -431602080.000000, -431602080.000000 -431602080.000000
Glossiness: -431602080.000000

and it worries me where they are coming from. If no numbers are actually being output for these values, then it suggests the program is reading in whatever is next in the file. That could be quite dangerous. Is max actually writing anything out for these values? Is it writing garbage of its own?

Also, I'm still a little confused as to why the materials that are being used are still set to the default:

Material 0:
Ambient: 0.588000, 0.588000, 0.588000 0.000000
Diffuse: 0.588000, 0.588000, 0.588000 1.000000
Specular: 0.900000, 0.900000, 0.900000 1.000000
Glossiness: 10.000000

The first 7 materials are all identical to that. Am I not pulling the information from the right place?

Thanks!

Bobo
03-21-2005, 03:12 AM
Dude, you are the one exporting the materials, how should I know what your Multi/Sub Material looks like? :scream:

Once again - the MESH in Max has no knowledge of the material except for a pointer to the root material and index to a sub-material for each face. The Mesh does not care what the material looks like or even if there is a material assigned at all - if there isn't, Max is using the .wirecolor property and drawing / rendering with that and some default settings...

If the material is NOT of class MultiMaterial, the face indeces are ignored and all faces use whatever is assigned.

If the material IS a MultiMaterial, the indices are resolved as I explained previously.
If you would process the mesh BEFORE processing the material, you could have knowledge of what face Material IDs are actually used and export only as many sub-materials as are really necessary for your application. But the way you are doing it now is easier and should not be a problem.

By default, a Multi/Sub Material has 10 sub-materials. I would URGE you to learn more about how Max works on UI level, open the Material Editor and see for yourself what you are exporting. I troubles me that you are handling this as a Black Box and only looking at the output without knowing where the data comes from...

I have written some exporters (see BFF (http://www.scriptspot.com/bobo/darkmoon/bff)) and even co-wrote a bridge to a 3rd party renderer (http://software.franticfilms.com/index.aspx?page=amaretto) lately, but it took me 9 years to learn all I know about Max. Don't expect everything to work after 9 days ;)

Oh, an I am too tall to be a hobbit!

CyberSlag5k
03-21-2005, 07:06 AM
Dude, you are the one exporting the materials, how should I know what your Multi/Sub Material looks like? :scream:

I'm sorry, I suppose I did word that a little funny. What I meant to say was, the materials that I am trying to export are defined. They were chosen by the artist, there are three of them, and they are not the default color. One is 243, 153, 236, the second is 219, 220 173, and the third is 219, 220, 173. I'm sure you don't care what they're set to, I"m just saying they aren't the default values, which is what ends up being exported.


By default, a Multi/Sub Material has 10 sub-materials. I would URGE you to learn more about how Max works on UI level, open the Material Editor and see for yourself what you are exporting.


Looking at the materials explorer, I see the values I'm looking for but they appear to be on the fourth material set, I'm not sure what the other three are.


I troubles me that you are handling this as a Black Box and only looking at the output without knowing where the data comes from...


*sigh* You're right. I'm starting to see now that I'm not going to be able to do this on the fly. From a coding standpoint this stuff is relatively trivial, it's just basic file output. However it's knowing what to export that I get hung up on. I hate programming like this, too, guessing alot and relying on others for when I get stuck.

So ok, I give in. It's time to hit the books. That's normally how I handle a project, read a ton, try it out, and ask as I get stuck. What's different this time around is that the documentation is geared more towards using max to create the object, and using maxscript to modify the object. I guess I just don't know what exactly to read in the SDK that will jut tell me how everything is structured and set up.

Man, I know better than this, though. Search my gamedev (the forum I'm indigenius to) posts and you'll often see me reply to the "What's the first step in learning how to program an FPS" posts with only the word "Pong." I know you have to walk, hell crawl, before you can run. I know you can't expect everything to come all at once. I guess I'm just kind of attempting to push it as I'm just getting really behind with this project. I had hoped to have the materials done a few days ago and could dedicate this week to textures and animation. A bit too ambitious a goal for a fledgling maxscript coder, I suppose. Lesson learned.

So ok, time to bite the bullet and hit the docs. Hell, in filtering through the SDK I'll probably pick up a working knowledge of max, a few pointers on how 3D graphics are created, and hopefully even some 3D graphics theory that will aid me in my programming.

So thanks for aiding me during this headfirst foray into the maxscripting world, bilbo. I'll just get off the highway, slap on the training wheels for a few days, and I'll be lifting the x-wing out of the swamps of Dagobah in no time, eh? It ought to do much to alleviate the frustrations on both our ends, I"m sure.


Oh, an I am too tall to be a hobbit!

Heh, I'm sorry man. I swear that was an accident. I've been sick all week and have been on a sudafed/nyquil dependency that's left me lightheaded and at experiencing thoughts of a euphoric, fear and loathing in las vegas state of un-mind. My humblest appologies.

You're very much humbled padawan learner,

Mike

CGTalk Moderation
03-21-2005, 07:06 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.