Godot Version
4.2.2
Question
Hello all! I am making a game that involves editing the meshes of objects by flipping them along an axis and skewing them. However, when an objects is flipped like this along an axis, its normals get flipped, too. The backfaces are the ones that render, not the front ones, and the physics is inverted. How can I fix this?
Here is my code:
func edit_mesh(cam):
var editmesh = ArrayMesh.new()
var norm = cam.global_basis.z;
var mdt = MeshDataTool.new();
editmesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,mesh.surface_get_arrays(0))
mdt.create_from_surface(editmesh,0);
for i in range(mdt.get_vertex_count()):
var vtx = to_global(mdt.get_vertex(i))
var dir = (vtx-cam.global_position).normalized()
var k = (global_position-vtx).dot(norm)/(dir.dot(norm));
vtx = vtx + 2*dir*k;
mdt.set_vertex(i,to_local(vtx));
editmesh.clear_surfaces()
mdt.commit_to_surface(editmesh)
mesh = editmesh
mesh.regen_normal_maps()
mesh.emit_changed()
for n in get_children():
remove_child(n)
n.queue_free()
create_trimesh_collision()
The script is connected to a MeshInstance3D with a child StaticBody3D that has a CollisionShape3D as a child of the staticbody. It gets run once when an input is pressed. I have tried changing the face normal data and the vertex order, but to no avail.
Ok, I’ve figured it out:
- Face vertices are not stored in the order I thought. I had assumed that the MeshDataTool stored the vertices for each triangle in order – e.g. vertices 0, 1, and 2 formed a triangle, vertices 3, 4, 5 formed another one, etc. – but this is not the case. MDT don’t need to do this. It can connect any 3 vertices. Luckily, in the default cube mesh the vertices are already separated, and they are unique to a square face (not a triangle face). It’s not that bad to change the vertex order:
func normalflip(m):
#ONLY GUARANTEED TO WORK FOR DEFAULT CUBE MESH
var editmesh = ArrayMesh.new()
var mdt = MeshDataTool.new();
editmesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,m.surface_get_arrays(0));
var ph;
#Redo normals
var l = editmesh.surface_get_arrays(0);
for i in range(len(l[ArrayMesh.ARRAY_NORMAL])):
pass
l[ArrayMesh.ARRAY_NORMAL][i] = -l[ArrayMesh.ARRAY_NORMAL][i];
editmesh.clear_surfaces();
editmesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,l);
mdt.create_from_surface(editmesh,0);
var i1;
var i2;
var i3;
var usedvx = [];
for i in range(mdt.get_face_count()):
#Get the 3 corners for each face
i1 = (mdt.get_face_vertex(i,0));
i2 = (mdt.get_face_vertex(i,1));
i3 = (mdt.get_face_vertex(i,2));
#Only flip the vxs that share a face.
# 0 ----- 2
# |\ |
# | \ |
# | \ |
# | \|
# 4 ----- 6
#Swapping anything other than vxs #0 and #6 would mzake weird triangles.
if len(mdt.get_vertex_faces(i1)) < 2:
if i3 in usedvx:
continue
i1 = i3;
elif len(mdt.get_vertex_faces(i2)) < 2:
if i3 in usedvx:
continue
i2 = i3;
else:
if i1 in usedvx:
continue
ph = mdt.get_vertex(i1);
mdt.set_vertex(i1,mdt.get_vertex(i2));
mdt.set_vertex(i2,ph);
usedvx.append(i1);
usedvx.append(i2);
editmesh.clear_surfaces();
mdt.commit_to_surface(editmesh);
return editmesh;