- Home /
How do i avoid shared vertices?
Hello,
i made a subdivided Icosahedron in Blender and split it at all edges so that i was left with zero shared vertices. I triple checked that.
Now, i imported that into Unity and am creating "continents" by assigning UV-coordinates to the vertices. I do that by going through each triangle in the triangles-array, find the three corresponding vertices, and assign three equal UV-values to them. That combined with some Perlin-Noise leaves me with the desired effect.
However, i noticed some strange behaviour at the "edges" of the continents, resulting in gradients that should not be there. When checking the UV-coordinates and vertex-indices of the triangles at runtime, i got the following result:
At the top, the selected triangle (with the white border) consists out of the vertex-indices
P0(4210)
P1(4211)
P2(1251)
The one at the bottom out of
P0(1250)
P1(4210)
P2(1251)
with two vertices (4210 and 1251)and thus their UV-coordinates (0.5, 0.8) being shared, resulting in the intended water-triangle having two vertices with green UV-coordinates, which is not what i want.
So my question is, how do i avoid my icosphere having shared vertices? I checked again in Blender, but it is all just how i want it there, with no vertices shared. Is this a problem with Unity altering (optimizing) the mesh when importing, or what did i do wrong to not have the mesh imported with no shared vertices?
Thanks in advance
Answer by DMGregory · May 07, 2014 at 03:08 PM
I think the answer may be Mesh.Optimize:
For imported models you should never call this as the import pipeline already does it for you.
I suspect that Unity is automatically merging identical vertices when you import the mesh.
Here's one way to hack around it...
int[] sourceIndices = sourceMesh.GetTriangles(0);
Vector3[] sourceVerts = sourceMesh.vertices;
Vector2[] sourceUVs = sourceMesh.uv;
int[] newIndices = new int[sourceIndices.Length];
Vector3[] newVertices = new Vector3[sourceIndices.Length];
Vector2[] newUVs = new Vector2[sourceIndices.Length];
// Create a unique vertex for every index in the original Mesh:
for(int i = 0; i < sourceIndices.Length; i++)
{
newIndices[i] = i;
newVertices[i] = sourceVertices[sourceIndices[i]];
newUVs[i] = sourceUVs[sourceIndices[i]];
}
Mesh unsharedVertexMesh = new Mesh();
unsharedVertexMesh.vertices = newVertices;
usharedVertexMesh.uv = newUVs;
unsharedVertexMesh.SetTriangles(newIndices, 0);
What this does is create a new mesh using the same triangle indices as the original, but with unique copies of every vertex. As long as you don't call Optimize() on it, Unity should leave this the way you want it.
(Note that the code above assumes the mesh contains only one submesh)
Thanks a lot man.
This worked perfectly. Interesting to see that you see$$anonymous$$gly cant stop Unity from optimizing the mesh on import though. (even if you uncheck "Optimize $$anonymous$$esh")
Cheers!
Answer by HsinChien · Apr 02, 2016 at 06:11 PM
enhanced code that supports sub-meshes
mesh=GetComponent<MeshFilter>().mesh;
// unshare verts
int subMeshCnt=mesh.subMeshCount;
int[] tris=mesh.triangles;
int triCnt=mesh.triangles.Length;
int[] newTris=new int[triCnt];
Vector3[] sourceVerts = mesh.vertices;
Vector3[] sourceNorms = mesh.normals;
Vector2[] sourceUVs = mesh.uv;
Vector3[] newVertices = new Vector3[triCnt];
Vector3[] newNorms = new Vector3[triCnt];
Vector2[] newUVs = new Vector2[triCnt];
int offsetVal=0;
for (int k=0; k<subMeshCnt; k++)
{
int[] sourceIndices = mesh.GetTriangles(k);
int[] newIndices = new int[sourceIndices.Length];
// Create a unique vertex for every index in the original Mesh:
for(int i = 0; i < sourceIndices.Length; i++)
{
int newIndex=sourceIndices[i];
int iOffset=i+offsetVal;
newIndices[i] = iOffset;
newVertices[iOffset] = sourceVerts[newIndex];
newNorms[iOffset]=sourceNorms[newIndex];
newUVs[iOffset] = sourceUVs[newIndex];
}
offsetVal+=sourceIndices.Length;
mesh.vertices = newVertices;
mesh.normals=newNorms;
mesh.uv = newUVs;
mesh.SetTriangles(newIndices, k);
}
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.Optimize();
Answer by _dns_ · May 07, 2014 at 03:13 PM
Hi, I think you need to have submeshes to have different UV for the same vertex. Unity mesh has 1 UV for each vertex (and UV2 but that's something different). Check the documentation about submeshes, GetTopology etc... This is basically a mesh composed of multiple meshes. The interesting part is that each submesh can have its own material and then it's own set of UV, but some vertices will be duplicated (shared vertices won't be anymore between multiple submeshes)
In Blender, you have to assign multiple materials to your mesh so that Unity imports multiple materials and creates submeshes. This involve marking "seam" in the UV editing, I did this long time ago and don't remember exactly how, you can find tutorials about assigning materials on youtube.
Yep, i wanted to avoid submeshes though for a few reasons, mainly because i did not want additional draw calls and also because changing UVs is quick and easy.
You're confusing $$anonymous$$aterials and texCoords. $$anonymous$$ultiple materials require submeshes. $$anonymous$$aking every single face into a submesh would work, but would cost a lot of draw calls.
As you note, when two faces share a vert, they can't each assign a different tex-coord to it. Verts get UVs, not faces, and they only get one per unwrap. So, the trick is, you split the vertex (either click "Split" or add a seam. A seam says "split these later.") Now each face can assign a different UV coord to "its" vert.
hummm, ok, I should have read the question one more time, submeshes is not what you needed, my mistake.
Your answer
![](https://koobas.hobune.stream/wayback/20220613144447im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Mesh Import Transform Problems 0 Answers
mesh from blender twinkle on unity 0 Answers
Object Colliders 2 Answers