Mesh.GetTriangles, applyBaseVextex parameter change anything

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

int[] integersTrue = mesh.GetTriangles(submeshIndex, true);
int[] integersFalse = mesh.GetTriangles(submeshIndex, false);

for (int i = 0; i < integersTrue.Length; i++)
    Debug.Log(integersTrue[i] + " " + integersFalse[i]);

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.

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: How To - Capturing Device Logs on iOS or this answer for Android: How To - Capturing Device Logs on Android

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:

“When in doubt, print it out!™” - Kurt Dekker (and many others)

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

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:

public static Mesh ExtractSubmesh(this Mesh mesh, int submeshIndex)
{
    int vertexCount = mesh.GetSubMesh(submeshIndex).vertexCount;

    int offset = GetVerticesOffset(submeshIndex);

    Mesh newMesh = new Mesh();

    Vector3[] vertices = mesh.vertices.Skip(offset).Take(vertexCount).ToArray();

    if (vertices.Length > oldVerticesLimit)
        newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

    newMesh.vertices = vertices;
    newMesh.triangles = OffsetTriangles(offset, mesh.GetTriangles(submeshIndex));
    newMesh.normals = mesh.normals.Skip(offset).Take(vertexCount).ToArray();
    newMesh.tangents = mesh.tangents.Skip(offset).Take(vertexCount).ToArray();
    newMesh.colors = mesh.colors.Skip(offset).Take(vertexCount).ToArray();
    CopyUVsChannel(mesh, newMesh, offset, vertexCount);

    newMesh.RecalculateBounds();
    newMesh.RecalculateTangents();
    newMesh.RecalculateNormals();
    newMesh.Optimize();

    return newMesh;

    int GetVerticesOffset(int submeshIndex)
    {
        int offset = 0;
        for (int i = 0; i < submeshIndex; i++)
            offset += mesh.GetSubMesh(i).vertexCount;
        return offset;
    }

    int[] OffsetTriangles(int offset, int[] list)
    {
        for (int i = 0; i < list.Length; i++)
            list[i] -= offset;
        return list;
    }
}

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.

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.

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.

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.

1 Like

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?

It really should Just Work™.

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://discussions.unity.com/t/896533/2

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

https://discussions.unity.com/t/832303/2

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://discussions.unity.com/t/839045/4

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

https://discussions.unity.com/t/841411/2

https://discussions.unity.com/t/852754/3

Probuilder and Probuilderize and Blender:

https://discussions.unity.com/t/659379/9

Some more potentially-useful info:

https://discussions.unity.com/t/877881/2

Updating Blender files without breaking your prefabs:

https://discussions.unity.com/t/915403/3

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

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?

I am following exactly the same rules except the following one:

Why it is so important?

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.

9350084--1307858--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.

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:

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.
2 Likes