Select Alternating Polygons?


#1

I have a very specific problem which I suspect can be solved using Max Scripts, but I’m not certain, so I’d like some help.

I’m converting some models from Rips that I’ve made with the Ninja Ripper tool (1.5.2), and Ninja ripper has a knack of inverting normals for seemingly no reason.
If ALL of the normals were inverted, this would of course not be a problem, but the normals usually end up looking like a checker-pattern, which makes me think a max script can be used to select alternating polygons, and then the Flip command can be used to flip only those normals, without going through the long process of manually selecting those polygons.

Here’s a common example of what I’m talking about: https://i.imgur.com/nLEEtTF.png

So as you can see, the shape is complex, which prevents me from using something like Dot Loop, but it’s very clear that there’s a pattern to how the normals are oriented.

I mainly work with .OBJ files, and I suspect that we can achieve the desired result by writing a custom .OBJ importer script, which would flip every other normal as it is being imported. (I’m not sure if 3dx max preserves the order that the polygons are imported in, so this may be the only option)

Any input would be greatly appreciated.


#2

To illustrate what I mean with the .OBJ importer script, this is a notepad view of the .OBJ file which is in the viewport of the 1st picture.

You can clearly see when the normals are being flipped.

Oh, and I forgot to mention earlier, but the “Unify” command in 3DS max doesn’t work in this case. it changes the normals to be out of pattern, but still not unified.

It’s not a terribly big problem for low-poly models, but I recently did a higher-poly model with this problem and it took near an hour just to solve this normals problem…

https://i.imgur.com/s5r46EN.png


#3

what happens when you convert to editable mesh and select all faces and press unify ? (ok just read the second bit)

I don’t think the normals are to be blamed here as they are discarded by max anyway and recomputed… it’s probably face vert order issue some faces are cw and some ccw (so when max recomputes the normals they are reversed)

can you post a sample file ?


#4

Probably won’t work, as you mention in your second post, but just to know.

Without having an object to test it is hard to know if there is a pattern, but you could try:

Add an Edit Mesh modifier
Select all verts and weld them
Add a Normal modifier and check Unify Normals
Convert back to Poly

See if Flip Normals needs to be on or off.


#5

Yeah, I’ve tried using the proximity based auto-weld feature and then using Unify, but it was more or less the same result (as Unify without weld)
Doing a manual weld would probably work, but it would be just as inefficient as manually flipping normals (at best).

Here’s the sample files. I know the UV is also messed up, but that part is much easier to fix manually.

https://pastebin.com/raw/71hcF4LD
https://orig00.deviantart.net/e608/f/2018/164/2/3/sample_by_itchydani3l-dceb3wt.png

Another thing which I just thought of, is maybe we could edit the MaxScript which is used to import the .RIP files… That way the normals are imported without being flipped.
Here’s the text of the .RIP importer:

https://pastebin.com/raw/JXAVmpPZ

And because I know someone will ask for it, this is the .RIP file which is intended to be used with the .MS script:

https://drive.google.com/open?id=1A8Tz3xbKzFUzxOG-5DfG0OLWajGGS3mk

@Klvnk I think you’re right about the vert order.
I think what the importer does, is it “keeps” vertices any time it can, that way it only loads 2 new vertices into memory if the current triangle shares a vertex with the previous one.
The side effect of this efficiency would be that the vertex order (ccw vs cw) would alternate for each adjacent triangle.

If we can force the .MS script to read all 3 vertices in the correct order for each new triangle, I think that will give us the result we want.


#6

Not automatic, but if I import the test model as a Mesh (not Poly), with this little script it took me 5 seconds to fix the flipped faces.
Just click on Unify Normals and then select the flipped elements and flip those faces. Not sure if it will work with other models.


(
    try destroydialog ::RO_QUICK_NORMAL_FLIP catch()
    rollout RO_QUICK_NORMAL_FLIP "" width:152 height:104
    (
        button btn1 "Unify Normals" pos:[8,8] width:136 height:40
        button btn2 "Flip Faces" pos:[8,56] width:136 height:40
        
        on btn1 pressed do
        (
            max modify mode
            
            if iskindof $ editable_mesh do
            (
                meshop.unifynormals $ #all
                subobjectlevel = 5
                
                setfaceselection $ #{}
                
                xviewchecker.setactivecheckerid 5
                xviewchecker.on = true
            )
        )
        
        on btn2 pressed do
        (
            if iskindof $ editable_mesh do
            (
                meshop.flipNormals $ #selection
                setfaceselection $ #{}
            )
        )
        
    )
    createdialog RO_QUICK_NORMAL_FLIP
)

EDIT: Just checked the UV’s and they are a complete mess.


#7

Yes the UV’s are a bit ugly because I didn’t touch them up. I believe that’s because of the perspective mutation that the models go through when they get rendered, and then I extracted after the mutation.

I see what you mean with the script, but it took me about the same amount of time to use Element and Flip Faces in your script as it would normally take using Flip Normals Mode for Edit Mesh.

I really think Klvnk is correct when he says the Vertex order is the core cause of the issue. If we can solve that mystery, I think the normals will be imported correctly, potentially saving many hours of normal flipping.


#8

yeah, if you import the obj with normals from file checked then the normals are correct for a completely “faceted” model (so they are for all intents and purposes junk) and all the normals are then set to explicit (max will not recompute them) There is an issue with face vert orders so because normals are explicit Unify makes the model look odd. Uncheck normals from file on import (use auto) and then Unify will work correctly and as above I think the normal data is useless junk anyway, (looking at it with the editnormals mod)


#9

Yes, pretty much the same, if you first do:

  • Import the model as mesh
  • Unify the normals
  • Turn on the XView Checker to quikly identify the flipped faces

But you previously said:
“Oh, and I forgot to mention earlier, but the “Unify” command in 3DS max doesn’t work in this case.”

Can you upload that model that took you near an hour to fix?


#10

DING DING DING! Looks like we’ve solved the mystery!

Even works with the more complex models! This is amazing, thank you so much!
I’m going to have to share this with some other rippers, because literally every tutorial for Ninja Ripper on youtube or otherwise just uses the Flip Normals Mode.

Oh, and PolyTools3D, Here’s one of the more complex models. This was actually ripped using 3D Ripper DX, so it doesn’t have the same pattern, but Klvnk’s method above works for this as well…

https://pastebin.com/raw/9zDCWSwS
https://orig00.deviantart.net/4580/f/2018/165/f/8/guard1_by_itchydani3l-dcedev8.png

3D Ripper DX may seem to be better than Ninja Ripper because it doesn’t mess up the UV’s, but it generally has lower compatibility because it’s not being updated any more. It can only do DirectX9 and earlier. Also, it doesn’t have the checker pattern with the UV’s.


#11

I’ve got some really stubborn models now, which are refusing to Unify, even with the method we used for previous files.

Here’s the samples:
https://pastebin.com/raw/iVaKF401
https://orig00.deviantart.net/328f/f/2018/171/7/0/uhulk_by_itchydani3l-dceyg6b.png

Here’s a list of things I’ve tried: (none of them worked)
-Importing normals from file and Unifying
-Using Auto-normals and Unifying
-Welding vertices first, and then Unifying
-Welding vertices, exporting, importing with auto-normals, and then unifying

And, there’s no pattern in the normals like the previous files.
So I’ve really got NO idea if there’s any way to fix this one.


#12

what do you want to do - fix normals after import or make a correct import?

what is the files you posted links to? what does them make? what is an original data?

how do you import these data to the max?


#13

The sample files are .OBJ and PNG
Import using 3DS Max Import function.

Normals need to be flipped after import, because this sample doesn’t have a .RIP file.


#14

the problem you have is due to the way the model has been made, instead of using say a double sided material/rendering the modeller has cloned the faces in situ and flipped then so you have two faces in the same position in all sorts of orientation so Unify has no chance of working. Need a way of finding all the duplicated faces then delete/detaching them which at first looks like a non trivial operation

looking at the mesh it’s two meshes in the same place as each face is exported twice probably something to do with a “double sided” tag it has in the original source

this will separate the 2 meshes (though they still need work welding an unifying)


    fn splitmesh msh faces =
    (
        detfaces = for f = 1 to faces.count by 2 collect faces[f];
        newmesh = meshop.detachFaces msh detfaces    delete:true asMesh:true
        update msh;
        othermesh = Editable_mesh();
        othermesh.mesh = newmesh --assign the detached faces to the new mesh
        update othermesh
    )
    
    
    splitmesh $ (#{1..$.numfaces} as array)


#15

Dude, you saved the day again.

In retrospect, I probably should have realized that there were double faces because these models had unusually high poly counts.

Thanks for everything, I owe you one.


#16

the mesh originally has duplicated faces because of probably “double-side” export feature, as Klvnk pointed…
but “checker - order” duplication might be a specific coincidence.

here is a more universal solution:


fn fixWeirdMesh obj = 
( 
   hash_faces = for k=1 to obj.numfaces collect
   (
      x = (length (meshop.getfacecenter obj k) * 100) as integer
      y = (meshop.getfacearea obj k * 100) as integer

      [x,y]
   )

   hash_unique = makeuniquearray hash_faces
   unique_faces = for i in hash_unique collect (finditem hash_faces i)


   meshop.deletefaces obj unique_faces
   meshop.weldVertsByThreshold obj #all 0.0001
   meshop.unifyNormals obj #all
   meshop.autoSmooth obj #all 45
   update obj
)
/*
fixWeirdMesh $
*/

it might need a code optimization, more accurate hashing, and a parameter tweaking…