Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Mesh.GetTriangles, applyBaseVextex parameter change anything

Discussion in 'Scripting' started by Magnilum, Sep 20, 2023.

  1. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    Hello, I have done a little script able to combine meshes in Unity.

    I am extracting each submesh of a mesh to combine them all together with the right material.

    In my script, I am using the method Mesh.GetTriangles:
    https://docs.unity3d.com/ScriptReference/Mesh.GetTriangles.html


    I did a quick exemple to see the difference between them but it seems that nothing happen

    Code (CSharp):
    1.  
    2. int[] integersTrue = mesh.GetTriangles(submeshIndex, true);
    3. int[] integersFalse = mesh.GetTriangles(submeshIndex, false);
    4.  
    5. for (int i = 0; i < integersTrue.Length; i++)
    6.     Debug.Log(integersTrue[i] + " " + integersFalse[i]);
    7.  
    May be I miss understood the bool parameter of this function, I am thinking that it apply an offset in the values to get the corresponding vertex from 0.

    I am using Unity 2022.3.6f1.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Sounds like you wrote a bug, or else something isn't the mesh you're thinking it is.

    For one, if the first collection is zero length, you ignore the size of the second collection, so you'd never see anything come out no matter how much was in the second collection.

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
  3. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    The length of both arrays is the same, I checked it before writing the for loop.
    I know that an issue could occur but it was only for make the demonstration.

    Before writting this post, I have done almost everything you wrote to be sure of the existance of this topic.

    Here is the full method:

    Code (CSharp):
    1. public static Mesh ExtractSubmesh(this Mesh mesh, int submeshIndex)
    2. {
    3.     int vertexCount = mesh.GetSubMesh(submeshIndex).vertexCount;
    4.  
    5.     int offset = GetVerticesOffset(submeshIndex);
    6.  
    7.     Mesh newMesh = new Mesh();
    8.  
    9.     Vector3[] vertices = mesh.vertices.Skip(offset).Take(vertexCount).ToArray();
    10.  
    11.     if (vertices.Length > oldVerticesLimit)
    12.         newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
    13.  
    14.     newMesh.vertices = vertices;
    15.     newMesh.triangles = OffsetTriangles(offset, mesh.GetTriangles(submeshIndex));
    16.     newMesh.normals = mesh.normals.Skip(offset).Take(vertexCount).ToArray();
    17.     newMesh.tangents = mesh.tangents.Skip(offset).Take(vertexCount).ToArray();
    18.     newMesh.colors = mesh.colors.Skip(offset).Take(vertexCount).ToArray();
    19.     CopyUVsChannel(mesh, newMesh, offset, vertexCount);
    20.  
    21.     newMesh.RecalculateBounds();
    22.     newMesh.RecalculateTangents();
    23.     newMesh.RecalculateNormals();
    24.     newMesh.Optimize();
    25.  
    26.     return newMesh;
    27.  
    28.     int GetVerticesOffset(int submeshIndex)
    29.     {
    30.         int offset = 0;
    31.         for (int i = 0; i < submeshIndex; i++)
    32.             offset += mesh.GetSubMesh(i).vertexCount;
    33.         return offset;
    34.     }
    35.  
    36.     int[] OffsetTriangles(int offset, int[] list)
    37.     {
    38.         for (int i = 0; i < list.Length; i++)
    39.             list[i] -= offset;
    40.         return list;
    41.     }
    42. }
    There is not reason why it does not work except if I miss understood the purpose of the bool parameter in the method.

    May be by taking a look at the method you would see something I miss.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Correction: there IS a reason it does not work.

    If there was no reason then it would work.

    You don't know this reason.

    I don't know this reason.

    That's why I posted the "Time to start debugging!" steps above.

    That's how you find the reason in software engineering.
     
  5. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    I miss express myself, of course there is a reason but it could also come from Unity.

    And this is what I wanted to point. If not, I definitly have a problem in my code but since it is a very simple code, everything is inside and does not depend on another code so that is why I am saying I don't see my mistake so may be it is from Unity.

    I am not rejecting the fault on Unity in any way, some times Unity has bugs so I just want to be sure that is not the case here.
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Well, have you actually checked if the sub meshes have a base vertex offset? Try Mesh.GetBaseVertex which returns the offset for a given submesh index. Maybe all submeshes have an offset of 0? You only get a base vertex when you actually specify one when you SetTriangles.

    The idea of a base vertex is, that you essentially just use a sub part of the vertex array for a particular submesh. That way the submesh can still use a 16 bit index buffer, even though the vertices array is greater than 64k as long as each submesh only requires a "window" into the vertex buffer. The base vertex specifies the beginning of that window.

    However if the individual submeshes do not have separated vertex sections inside the vertex buffer, most if not all would probably have a base vertex index of 0 which would be the default.
     
    Magnilum likes this.
  7. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    You are right, when I debug the Mesh.GetBaseVertex, I get 0 for each of the submesh of the object I have made in Blender.

    Do you have any idea to set up this correctly in blender?
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    It really should Just Work(tm).

    Fire up Blender3D, delete the Camera, delete the Light, save the Default Cube and import it.

    When you see that work, then add a new Material and assign half the faces to it.

    Now you'll have two submeshes.

    Here's more random Blender3D notes:

    Costs of Blender vs FBX:

    https://forum.unity.com/threads/any-cons-to-keeping-models-as-blend-files.1345850/#post-8497010

    Unity imports Blender3D objects as FBX via a little Python script:

    https://forum.unity.com/threads/from-blender-to-unity-problem.1073381/#post-6925811

    The Python script that Unity uses (substitute your Unity version number or search) to import:

    ./Hub/Editor/2020.2.1f1/Unity.app/Contents/Tools/Unity-BlenderToFBX.py


    More on fixing it:

    https://forum.unity.com/threads/all-my-mesh-folder-content-is-gone.1102144/#post-7094962

    Blender3D objects used as trees / detail in Unity3D terrain (See the second half of this response)

    https://forum.unity.com/threads/ter...trees-made-with-blender.1112119/#post-7155631

    https://forum.unity.com/threads/all...nging-parent-in-blender.1159283/#post-7442123

    Probuilder and Probuilderize and Blender:

    https://forum.unity.com/threads/probuilder-vs-blender.462719/#post-8060462

    Some more potentially-useful info:

    https://forum.unity.com/threads/orientation-problem.1265834/#post-8037734

    Updating Blender files without breaking your prefabs:

    https://forum.unity.com/threads/is-it-possible-to-edit-a-prefab-in-blender.1426326/#post-8954421

    When I work in Blender3D for Unity3D use, I follow these organizational rules:

    - use Empty Blender Objects as folders: they come out as an extra GameObject

    - ALWAYS parent everything to a single Empty, even a single object

    - put as few objects in a given .blend file as possible, combining them in Unity into a prefab

    - set good names for your Blender3D objects and NEVER RENAME them after Unity sees them

    - don't even think about Materials or Textures in Blender, just do it in Unity
     
  9. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    I'm not an artist and do not do any modelling. However submeshes can actually share vertices so they use the same vertex array. As I said the "basevertex" offset only makes sense when you have submeshes which are separate meshes and should be combined into one mesh. In that case you usually don't have overlaps / sharing of the vertices between submeshes. I don't know if Unity would actually apply an offset for submeshes during import. Vertices usually not required to have a certain layout or order inside the vertices array. The triangle / index buffer simply references vertices by their index.

    If the total number of vertices is below 64k, the whole concept of the base offset is kinda irrelevant since a 16 bit index buffer can still cover the whole list anyways. Though as I said I don't know if Unity actually applies an offset for submeshes. It may be difficult depending on how the data is actually laid out.

    Can you give us some details about that meshes you imported? How many vertices do we talk about? Are the submeshes in the imported mesh actually separate parts or do they actually share vertices?
     
  10. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    I am following exactly the same rules except the following one:

    Why it is so important?
     
  11. Magnilum

    Magnilum

    Joined:
    Jul 1, 2019
    Posts:
    154
    For sure, we don't talk about many vertices here cause it was just a simple object to see if my tool works or not.

    upload_2023-9-21_9-12-42.png

    The object has 82 vertices, and 140 triangles and no vertex is shared. They are separated parts.
     
  12. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Because if you have one object and decide to add a second, all your links to the first object will break.

    If you go from:

    Cube
    <-- unity will assign this an identifier and know it as "Cube"

    Now you have this:

    Cube
    Cube2


    Unity won't see that. Unity will instead see it as:

    TransientGameObject/Cube
    TransientGameObject/Cube2


    Now Unity will assign two new identifiers, including the full path.

    Everything that used to refer to
    Cube
    will now go missing.

    If you make a parent to start with, then as you add more, the existing ones do not change, as long as you never rename them.
     
    Bunny83 and spiney199 like this.