+1 vote

For initial generation of mesh using SurfaceTool (and adding smoothing group above addvertex calls, and adding 'generatenormals' after adding the verts / indices works quite nicely.

However, if I make adjustments to the mesh using MeshDataTool, then use SurfaceTool to commit that (arraymesh) to the object being updated, the normals no longer seem to work even when calling 'generate_normals' again on the surfacetool.

Has anyone else seen this issue -- could very well be an issue with my code. I'll paste it here later on today if this doesn't sound familiar to anyone as to why this may occur. Any thoughts?

in Engine by (29 points)

So, I took a lot at SurfaceTool source, and it appears at the end of "SurfaceTool::generate_normals", there's a call to clear the smooth groups

if (was_indexed) {
    index();
    smooth_groups.clear();
}

Not sure why this is cleared here, but sure there's some reason. If I add the call to " back before calling generate_normals, it doesn't seem to help though, so not sure this is my issue...

My update code is basically this this:

func update_mesh(delta):
      if _result_mesh == null:
            _result_mesh = self.mesh     
      _mesh_data_tool.create_from_surface(_result_mesh, 0)
     for i in range(_mesh_data_tool.get_vertex_count()):
          _vertex = _mesh_data_tool.get_vertex(i)

            #... some code to perform vertex adjustment and call _mesh_data_tool.set_vertex

      _result_mesh.surface_remove(0)
      _mesh_data_tool.commit_to_surface(_result_mesh)
      _surface_tool.create_from(_result_mesh, 0)
      #_surface_tool.add_smooth_group(true)       # gave this a try - didn't work
      _surface_tool.generate_normals(true)
      _result_mesh = _surface_tool.commit()
      self.mesh = _result_mesh

  The initial programmatic mesh looks smooth, but as soon as the first update to it runs, the shading is no longer smooth.  Anyone happen to have any thoughts or suggestions? 

1 Answer

0 votes

I had the same issue when using the MeshDataTool to modify a mesh.

The problem is that the MeshDataTool does not generate the corresponding ArrayMesh.ARRAY_NORMAL when creating the ArrayMesh.

The workaround I found is to recreate the mesh using the MeshDataTool faces and setting the normal for each vertex accordingly.

For example:

var vertices = PoolVector3Array()
var normals = PoolVector3Array()
var uvs = PoolVector2Array()

for face in meshData.get_face_count():
    var normal = meshData.get_face_normal(face)
    for vertex in range(0, 3):
        var faceVertex = meshData.get_face_vertex(face, vertex)
        vertices.push_back(meshData.get_vertex(faceVertex))
        uvs.push_back(meshData.get_vertex_uv(faceVertex))
        normals.push_back(normal)

var arrays = []
arrays.resize(ArrayMesh.ARRAY_MAX)
arrays[ArrayMesh.ARRAY_VERTEX] = vertices
arrays[ArrayMesh.ARRAY_NORMAL] = normals
arrays[ArrayMesh.ARRAY_TEX_UV] = uvs
var arr_mesh := ArrayMesh.new()
arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)

self.mesh = arr_mesh

As you can see, the problem with this solution is that you need to re-create everything else the MeshDataTool preserves, such as the UVs.

Before:
Mesh commited from mesh data tool
After:
Using face normals to shade each triangle

Be aware that Mesh.PRIMITIVE_TRIANGLES and Mesh.PRIMITIVE_TRIANGLE_STRIP behave different, since vertices (and their normals) are shared between faces for the latter. So make sure you're using the correct approach for your base mesh.

Another option would be to call set_vertex_normal for each vertex in your MeshDataTool, but you'd have to figure out which normal to use if your base mesh uses PRIMITIVE_TRIANGLE_STRIP as the primitive type, or you could get some weird results, like this:

for face in meshData.get_face_count():
            # Set the face's normal as the normal for one of its points
    var vertex = meshData.get_face_vertex(face, 0)
    var normal = meshData.get_face_normal(face)
    meshData.set_vertex_normal(vertex, normal)

Which results in:

Normals per vertex

by (60 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.