Home Technical Talk

[3DSMAX] welding vertex normals

greentooth
Offline / Send Message
pixelb greentooth

I've been importing my models from Blender to Max as .fbx and I noticed that when they come in they have no smoothing groups applied and every single vertex normal is split, even though they're pointing in the same direction so the model appears to have smooth edges. It looks fine in editor but it's causing my vert count to be unnecessarily high. Is there a way to automatically weld overlapping vertex normals? I tried using unify in the edit normals modifier, but this resets the direction of the normal and I need to keep the custom normals I assigned in Blender.



Replies

  • EspiSensei
    Offline / Send Message
    EspiSensei polycounter lvl 7
    Maybe you can apply a standard vertex weld over every vertices with minimum distance. By this way you can weld all the vertices and maybe repair the vertex normal.
  • Mark Dygert
    Yep it sounds like your actual verts need to be welded or the smoothing groups need to be reset.

    Smoothing groups are an ancient way of dealing with vertex normals inside of 3dsmax, basically if you want all of your faces to be "smooth" then you put everything in one group. Any place you want break the smoothing, you put those two faces in different groups and max tweaks the normals behind the scenes.

    If the verts are un-welded then no combination of grouping will get them to smooth, you'll have to weld the verts and then you can assign the faces to the same smoothing group, if they aren't already.

    Careful, editing normals in max is a nightmare, be very careful what you do, collapsing the stack or adding a modifier to the stack can cause max to recalculate the normals and screw up any custom work you've done. 
  • pixelb
    Offline / Send Message
    pixelb greentooth
    An ordinary vertex weld does nothing. The verts are already welded, it's the normals I have too many of.

    It is possible to import the model with a single smoothing group applied, but doing so resets my custom normals.  I can also manually set everything to a single smoothing group but this doesn't fix the problem.

    The only workaround I can come up with is to make two copies of the mesh, one with my custom normals and one with the normals reset, and then use normalthief to transfer the first mesh's normals to the second. This works....okay? but it means losing ALL my hard edges and has to be repeated for every piece of the model, putting a major hink in my workflow.

    If the verts are un-welded then no combination of grouping will get them to smooth, you'll have to weld the verts and then you can assign the faces to the same smoothing group, if they aren't already.
    But you could also use the edit normals modifier to set all of a vert's normals to be pointing the same direction. Even if the adjoining faces are unwelded or in different smoothing groups the results will look smooth. I think this is effectively what's going on with my meshes.
    Careful, editing normals in max is a nightmare, be very careful what you do, collapsing the stack or adding a modifier to the stack can cause max to recalculate the normals and screw up any custom work you've done. 

    Boy, you don't have to tell me twice.  :(

  • Eric Chadwick
    Look into the export settings you are using from Blender, and at the import settings in Max. One or both are probably causing this. Could also be a crappy implementation of the FBX standard in Blender. Make sure both ends use the same version of FBX.

    For editing vertex normals in 3ds Max, I wrote some notes here, might help you.
    http://wiki.polycount.com/wiki/Vertex_normal#3ds_Max
  • pixelb
    Offline / Send Message
    pixelb greentooth
    From my coworker: "Fbx states that it will break the normals to insure they survive the export process." Though I don't observe the same issue with .fbxs coming from Maya, so you're probably right about the .fbx implementation in Blender. Anyway I looked into it some more and it seems the split normals are not actually increasing the vert count in engine, so I guess I'm safe for now.
     
    Thanks for the normal tips, they're dead useful.
  • mihail.lupu
    Offline / Send Message
    mihail.lupu polycounter lvl 11
    Try this trick. Sometimes it helps. Select your object, add a meshsmooth modifier on top, set the iterations to 0 and collapse the modifier  to poly. In this way you reset the object normals. Then you have to set the smoothing groups as you need.
  • pixelb
    Offline / Send Message
    pixelb greentooth
    @mihail.lupu  You're misunderstanding, my goal is to not reset the normals, just to weld the overlapping ones. Smoothing groups would not give me the shading I'm looking for.
  • monster
    Offline / Send Message
    monster polycounter
    It would be pretty easy to create a script that grabbed the first normal direction per vertex, reset it to one normal, then set the direction again.

    But sounds like it’s working out without that need.
  • Millenia
    Offline / Send Message
    Millenia polycount sponsor
    You could maybe write a script that stores the custom normals as vertex colour in Blender, allowing you to then recreate them in Max off that with another script. Bit involved but guaranteed to come through intact.

    This is of course assuming you're already not using that vertex colour data.
  • Noors
    Offline / Send Message
    Noors greentooth
    monster said:
    It would be pretty easy to create a script that grabbed the first normal direction per vertex, reset it to one normal, then set the direction again.

    But sounds like it’s working out without that need.
    You have to preserve hard edges too.

    I think i ran into this issue aswell with cad objects, and made a script that i can't find back, but i think unity is smarter than max indeed, and doesn't add extra vert if normals are the same.
  • Mark Dygert


    It won't fix your specific issue but this script is awesome at face weighting the normals. https://gumroad.com/l/auqXp



  • mihail.lupu
    Offline / Send Message
    mihail.lupu polycounter lvl 11
    Wow, i dont want to be offtopic, but what does the 'coplanar weight' from the option group?
    I have something similar here:

    thanks.
  • pixelb
    Offline / Send Message
    pixelb greentooth
    Noors said:
    monster said:
    It would be pretty easy to create a script that grabbed the first normal direction per vertex, reset it to one normal, then set the direction again.

    But sounds like it’s working out without that need.
    You have to preserve hard edges too.

    I think i ran into this issue aswell with cad objects, and made a script that i can't find back, but i think unity is smarter than max indeed, and doesn't add extra vert if normals are the same.
    I would love that script, if only to clean up the normals in my max files.

    Mark Dygert said:


    It won't fix your specific issue but this script is awesome at face weighting the normals. https://gumroad.com/l/auqXp



    Ooh! I need the blender version in my life, but this is pretty great too.
  • Noors
    Offline / Send Message
    Noors greentooth
    @pixelb
    Try this.
    It adds an edit normals modifier, that you may want to collapse (uncomment collapseStack obj)

    (<br>obj = selection[1]<br><br>if superclassof obj == GeometryClass then<br>(<br>&nbsp;&nbsp;&nbsp; max modify mode<br><br>&nbsp;&nbsp;&nbsp; mod_norm = Edit_Normals()<br>&nbsp;&nbsp;&nbsp; mod_norm.displayLength&nbsp; = 1<br><br>&nbsp;&nbsp;&nbsp; addModifier obj mod_norm<br><br>&nbsp;&nbsp;&nbsp; numVerts = mod_norm.GetNumVertices()<br><br>&nbsp;&nbsp;&nbsp; --for each geo vert<br>&nbsp;&nbsp;&nbsp; for i = 1 to numVerts do<br>&nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; normIDs = #{}<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sharedNorm = #()<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sharedNormIDs = #()<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --get its normal ids<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; mod_norm.ConvertVertexSelection #{i} normIDs<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --if several normal ids for 1 vert <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if normIDs.count > 1 do<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --for each normal id<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for id in normIDs&nbsp; do<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --get the normal value<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; norm = mod_norm.GetNormal id<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --did we already find this value <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; index = findItem sharedNorm norm<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --no, so add as new element<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if index == 0 then<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; append sharedNorm norm<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; append sharedNormIDs #(id)<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; -- yes so add shared normal id <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else append sharedNormIDs[index] id<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --for shared normal group<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for i = 1 to sharedNormIDs.count do<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if sharedNormIDs[i].count > 1 do<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --unify normals<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; mod_norm.Unify selection:(sharedNormIDs[i] as bitarray) toAverage:true<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; --collapseStack obj<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; )<br>)<br>else format "Please select a geometry object."<br>)<br><br>

  • pixelb
    Offline / Send Message
    pixelb greentooth
    Yes, that's perfect! Ahh, so much better. Thanks for digging it up for me @Noors!!
Sign In or Register to comment.