Welding vertices at runtime

I took a look at this post Welding vertices at runtime - Questions & Answers - Unity Discussions to weld vertices.

I took a look at @imaxus_1 code and it works but there is a problem with normals or lighting

public static Mesh WeldVertices(Mesh aMesh, float aMaxDelta = 0.01f) {
                var verts = aMesh.vertices;
                var normals = aMesh.normals;
                var uvs = aMesh.uv;
                Dictionary<Vector3, int> duplicateHashTable = new Dictionary<Vector3, int>();
                List<int> newVerts = new List<int>();
                int[] map = new int[verts.Length];
 
                //create mapping and find duplicates, dictionaries are like hashtables, mean fast
                for (int i = 0; i < verts.Length; i++) {
                    if (!duplicateHashTable.ContainsKey(verts[i])) {
                        duplicateHashTable.Add(verts[i], newVerts.Count);
                        map[i] = newVerts.Count;
                        newVerts.Add(i);
                    }
                    else {
                        map[i] = duplicateHashTable[verts[i]];
                    }
                }
 
                // create new vertices
                var verts2 = new Vector3[newVerts.Count];
                var normals2 = new Vector3[newVerts.Count];
                var uvs2 = new Vector2[newVerts.Count];
                for (int i = 0; i < newVerts.Count; i++) {
                    int a = newVerts[i];
                    verts2[i] = verts[a];
                    normals2[i] = normals[a];
                    uvs2[i] = uvs[a];
                }
                // map the triangle to the new vertices
                var tris = aMesh.triangles;
                for (int i = 0; i < tris.Length; i++) {
                    tris[i] = map[tris[i]];
                }
                aMesh.triangles = tris;
                aMesh.vertices = verts2;
                aMesh.normals = normals2;
                aMesh.uv = uvs2;
 
                aMesh.RecalculateBounds();
                aMesh.RecalculateNormals();
 
                return aMesh;
            }

As you can see that there is a issue with normals or lighting. How to fix this?

How to fix this issues???

Ask yourself, why would the default cube have 3x more Vertices than “needed”?

The short answer is that it doesnt. Distinct normals require distinct vertices to be stored. So for every Tri ending on said vertex (which is 3), there is one normal vertex stored at that location. Otherwise you are reducing the available normal informations, which in turn messes with things like lighting.

What is it you are actually trying to do?

2 Likes

That is not an “issue.” That is exactly what happens when one vertex tries to share many normals, as @Yoreki posted above. Totally normal, completely expected. In fact, if that dull spherical lighting did NOT happen, you could also be confident that your merging the vertices had in fact failed.

You can see more about it in a tiny little scene in my MakeGeo project.

Look for the SharedvsNonSharedVertices scene.

MakeGeo is presently hosted at these locations:

https://bitbucket.org/kurtdekker/makegeo

https://github.com/kurtdekker/makegeo

https://gitlab.com/kurtdekker/makegeo

https://sourceforge.net/p/makegeo

1 Like

I know there are 24 vertices on the each side of the cube. and 72 triangles.

I draw 200,000 -300,000 objects and all these objects make total14 million vertices. And I get 30-40 FPS because of these 14 million vertices. I could to reduce from 14 million vertices to 800,000 vertices but there is an issue as you can see in the picture. I don’t instantiate objects, I draw objects. If you ask me what does this object look. Simply floor and wall object.

And I want to remove duplicated vertices, normals an uvs. Simply merge vertices, normals and uvs. And I found a way how to merge vertices, normals and uvs but there is an issue with lighting. Is there any way to fix that lighting issue or not?

What you call a “lighting issue” is to do with normals. You merged vertices that in fact did NOT share normals.

So… “no” is the basic answer. In the Unity cube, 100% of all vertices are unique in some way, either in position, UV, or normal.

1 Like

I though that this caused because of lighting. Oh, ok.

Hmm, I merged vertices, normals and uvs too. I think that there is solution there. Now need I to fix normals, or how can I share normals?

No, My cube is not a Unity cube. I make objects in blender and then I export from blender to unity. I used blender cube which you can see in the above picture. I use blender objects. So, will it fix if I do not merge normals or need I change or add something in the normals section? How to share normals?

You can ALWAYS share normals that are identical.

Your normals are not identical.

If they were, then you would not see the lighting issue.

There is no way anyone here can express this any clearer to you, so you either get it or you do not.

1 Like

If I can share normals then it will solve this problem, ok then its great.
So is there not even a little example about how to share normals? Also I own will take a look but I wanted to know is there a little example about how to share normals. thanks

you can do this but not at edges and corners. the cube has 24 vertices because it has 24 normals (each corner has 3 directions). without this extra information the lighting will never work. you can optimise meshes by welding vertices with the same normal. like if a flat surface is cut in half, you might have 3 pairs of vertices with the same normals, but there will be 4 vertices that must not change. what you do is generally smoothing. if you did this on the sides of an octagon based column, you will make it look like a smooth cilinder

2 Likes

I welded vertices and normals, but I do not know how to weld vertices with the same normals. This is a problem. Can you provide a code example to figure it out??? It would be so nice if you can provide a code example about weld vertices with the same normals. I wanna see as code even if there is an example in 2D mesh to understand well. I need a code to figure it out, so if you can?

every vertice has a normal and a tangent.
from your mesh when you find the same vertices, check the normals on the same index.
if the are same, you can weld the vertices and leave the normal unchanged.
if the surface is not completely flat you can calculate an average normal by adding them and then normalise the outcome

Have you considered trying to merge vertices in Blender before exporting?

1 Like

Now I can understand a little. So correct me if I am wrong, I can not weld vertices if their normals are different. Just I can weld that vertices if their normals are same. Yes, am I right?

So if I am right then what do you mean by the normals need to be the same values? Do you mean that normals values need to be same as vertex value to weld?

So I can weld when the normal x , y and z value is the same as vertex x , y , and z?

You seem to miss the point here. The normals are what are required for the lighting. The normal of a vertex defines which direction a triangle faces. As all here tried to explain to you. You have 6 flat faces, each face has 2 triangles. Each face requires 4 vertices. The normal vectors of the 4 vertices of one face have to point in the same direction in order to get a flat shaded lighting. Therefore you need 4 distinct vertices per face. Since we have 6 faces we get 24 vertices in total. It’s not possible to get away with fewer vertices (at least not if you want to use any standard shader).

If your target hardware supports geometry shader, it would be possible to essentially construct a cube from a single point in the original mesh (though that cube will also have 24 unique vertices). There’s another way by using a custom shader that uses the partial derivative ddx and ddy to essentially calculate the normal of the face in the fragment shader. However this also requires a fairly new hardware that supports the partial derivative functions, it of course has processing overhead and in certain extreme cases it might cause visual artifacts.

What exactly are you doing? 200k to 300k objects won’t give you any reasonable performance, no matter if your objects have 24 vertices or 8. Are you shooting for a minecraft clone? If so you should look up how to create minecraft terrain and why MC actually creates chunks / chunk sections that are 16x16x16 cubes in size.

Note that Minecraft does also use 24 vertices per cube. However when doing chunk meshing you always want to get rid if the internal faces that are next to solid blocks which will actually reduce the vertex and triangle counts heavily.

2 Likes

I merged at distance my mesh in the blender before export the unity. It does not make a scene merge or not merge mesh in the blender? Because the unity add extra vertices normals and triangles inside unity. So do you mean like I said? Or you found another way?

We really need more information on what you are trying to do. I am pretty sure there is going to be a better way to optimise your game than this.

1 Like

Ok. I will explain detailed today later. Now I am the work.

no, the 2 vertices you are welding have to have the same normal vector. i even gave example.

lets say vertice1 is at vector (3, 0, 1) and has a normal (0, 0, 1)

if vertice2 is at vector (3, 0, 1) and has a normal (0, 0, 1) you can weld them
but if vertice2 is at vector (3, 0, 1) and has a normal (0, 1, 0) you can’t weld them
I don’t know how to explain even more

Oh ok, now I get it. If vertex 1 and vertex 2 have same normal values and then I can weld these vertices. If vertex 1 and vertex 2 have different normal values then I can not weld these vertices. So easy now. Now I want to know that: if vertex 1 and vertex 2 have same normals then can I also weld their normals too or not?

I understood you very well. thanks, but here in these answers you calculated normals for shared vertices. But I Am confused now. Some one tells that it can be solved and some one tells that it can not be.

My game looks like a minecraft but it is not with cubes.

https://answers.unity.com/questions/1293825/how-to-calculate-normal-direction-for-shared-verte.html