extends Object class_name GeoPolyMesh var surface_array = [] var verts = PackedVector3Array() var uvs = PackedVector2Array() var normals = PackedVector3Array() var array_mesh = ArrayMesh.new() var original_face_data: Faces var _v_indexes = [] var _v_points = [] var edges = {} var depth_vector: Vector3 var extrude_direction: DestructableWall.ExtrudeDirection func _init(vector_indexes: PackedInt32Array, vector_points: PackedVector2Array, extrude_direction: DestructableWall.ExtrudeDirection, original_vectors: PackedVector3Array, original_uvs: PackedVector2Array, original_normals: PackedVector3Array, depth: float = -0.1): assert(len(vector_indexes) % 3 == 0 && len(vector_indexes) != 0, "Number of vertex points is not divisible by 3, invalid triangle verticies") surface_array.resize(Mesh.ARRAY_MAX) original_face_data = Faces.new(original_vectors, original_uvs, original_normals) self._v_indexes = vector_indexes self.extrude_direction = extrude_direction if extrude_direction == DestructableWall.ExtrudeDirection.BACK: depth_vector = Vector3.BACK * depth for point in vector_points: self._v_points.append(Vector3(point.x, point.y, -depth/2)) elif extrude_direction == DestructableWall.ExtrudeDirection.RIGHT: depth_vector = Vector3.LEFT * depth for point in vector_points: self._v_points.append(Vector3(depth/2, point.y, point.x)) elif extrude_direction == DestructableWall.ExtrudeDirection.UP: for point in vector_points: self._v_points.append(Vector3(point.x, depth/2, point.y)) depth_vector = Vector3.DOWN * depth self._pre_process_edges() self._draw_mesh() self._extrude_mesh() self._draw_sides() func calculate_area(mesh_vertices: PackedVector2Array) -> float: var result := 0.0 var num_vertices := mesh_vertices.size() for q in range(num_vertices): var p = (q - 1 + num_vertices) % num_vertices result += mesh_vertices[q].cross(mesh_vertices[p]) return result * 0.5 # edges are any verticies that share only on triangle func _pre_process_edges(): var faces = UTIL.chunk_array(self._v_indexes, 3) for vertices in faces: for v_inx in range(len(vertices)): var vertexA = vertices[v_inx] var vertexB = vertices[(v_inx+1) % 3] var min_index = min(vertexA, vertexB) var max_index = max(vertexA, vertexB) var edge = self.edges.get([min_index, max_index]) if !edge: self.edges[[min_index, max_index]] = 1 else: self.edges[[min_index, max_index]] += 1 func in_triag(u, v, w): return u >= 0 and u <= 1 and v >= 0 and v <= 1 and w >= 0 and w <= 1 func _reduce_significance(value: float): return snapped(value, 0.0001) func _new_interpolated_uv_point(new_vector: Vector3, normal: Vector3) -> Vector2: # get faces that have the same normal e.g faces that the point can fall into var faces = self.original_face_data.get_faces() var possible_faces: Array[Face] = [] for f in faces: if normal.dot(f.normal) > 0.99: possible_faces.append(f) for ps in possible_faces: var ps_face_verts = ps.vectors var b_points = Geometry3D.get_triangle_barycentric_coords(new_vector, ps_face_verts[0], ps_face_verts[1], ps_face_verts[2]) var u = self._reduce_significance(b_points[0]) var v = self._reduce_significance(b_points[1]) var w = self._reduce_significance(b_points[2]) var uv_coords = ps.uvs if in_triag(u, v, w): return (uv_coords[0] * u) + (uv_coords[1] * v) + (uv_coords[2] * w) # for destructable walls, if we couldn't interpolate a uv, this is fine return Vector2.ZERO func get_loops(): var unvisted_edges = self.get_outline_edge() var loops = [] while len(unvisted_edges) != 0: var loop = [] loop.append_array(unvisted_edges.pop_back()) var v_next = loop.back() while loop[0] != v_next: for ue_ind in range(len(unvisted_edges)): var v1 = unvisted_edges[ue_ind][0] var v2 = unvisted_edges[ue_ind][1] if v_next == v1: loop.append(v2) unvisted_edges.pop_at(ue_ind) v_next = loop.back() break elif v_next == v2: loop.append(v1) unvisted_edges.pop_at(ue_ind) v_next = loop.back() break loops.append(loop) var vector2_loops = [] for loop in loops: var vector2_loop = [] for ind in loop: var point = self._v_points[ind] if extrude_direction == DestructableWall.ExtrudeDirection.BACK: vector2_loop.append(Vector2(point.x, point.y)) elif extrude_direction == DestructableWall.ExtrudeDirection.RIGHT: vector2_loop.append(Vector2(point.z, point.y)) elif extrude_direction == DestructableWall.ExtrudeDirection.UP: vector2_loop.append(Vector2(point.x, point.z)) vector2_loops.append(vector2_loop) var area = [] for vector2_loop in vector2_loops: var result = self.calculate_area(vector2_loop) area.append(result) # reorder the loops where outer boundary is the first one var index = 0 var index_value = area[0] for ind in range(len(area)): var val = abs(area[ind]) if val > index_value: index = ind index_value = val var bloop = loops.pop_at(index) var barea = area.pop_at(index) loops.push_front(bloop) area.push_front(barea) # check for CW or CCW if area[0] > 0: # Outer boundary should be CW, if area is <0 then it is CCW loops[0].reverse() for area_index in range(1, len(area)): var a = area[area_index] if a < 0: # all inside loops need to rendered in CCW, if + then it is CW loops[area_index].reverse() return loops func get_outline_edge(): var outline_edges = [] for e in self.edges: var value = self.edges[e] if value == 1: outline_edges.append(e) return outline_edges func _calc_triangle_normal(a: Vector3, b: Vector3, c: Vector3): return ((b-a).cross(c-a)).normalized() func _draw_sides(): var loops = get_loops() for l in loops: var outline_edges_ordered = l for outline_vector_ind in range(len(outline_edges_ordered) - 1): var v0 = self._v_points[outline_edges_ordered[outline_vector_ind]] var v1 = self._v_points[outline_edges_ordered[outline_vector_ind + 1]] var v2 = self._v_points[outline_edges_ordered[outline_vector_ind]] + depth_vector var v3 = self._v_points[outline_edges_ordered[outline_vector_ind + 1]] + depth_vector #print("v0: ", v0, " v1: ", v1, " v2: ", v2, " v3: ", v3) var n1 = self._calc_triangle_normal(v2, v1, v0) self.verts.append_array([v0, v1, v2, v1, v3, v2]) _append_uvs3(v0, v1, v2, n1) _append_uvs3(v1, v3, v2, n1) self.normals.append_array([n1, n1, n1, n1, n1, n1]) func _append_uvs3(v0: Vector3, v1: Vector3, v2: Vector3, normal: Vector3): var uv0 = self._new_interpolated_uv_point(v0, normal) var uv1 = self._new_interpolated_uv_point(v1, normal) var uv2 = self._new_interpolated_uv_point(v2, normal) self.uvs.append_array([uv0, uv1, uv2]) # front face func _draw_mesh(): var vector3A = self._v_points[self._v_indexes[0]] var vector3B = self._v_points[self._v_indexes[1]] var vector3C = self._v_points[self._v_indexes[2]] var normal = self._calc_triangle_normal(vector3C, vector3B, vector3A) self.verts.append_array([vector3A, vector3B, vector3C]) _append_uvs3(vector3A, vector3B, vector3C, normal) self.normals.append_array([normal, normal, normal]) # insert each front face into the mesh "clockwise" for index in range(3, len(self._v_indexes) - 1, 3): vector3A = self._v_points[self._v_indexes[index]] vector3B = self._v_points[self._v_indexes[index+1]] vector3C = self._v_points[self._v_indexes[index+2]] self.verts.append_array([vector3A, vector3B, vector3C]) _append_uvs3(vector3A, vector3B, vector3C, normal) self.normals.append_array([normal, normal, normal]) # ## back face func _extrude_mesh(): var vector3A = self._v_points[self._v_indexes[len(self._v_indexes) - 1]] var vector3B = self._v_points[self._v_indexes[len(self._v_indexes) - 2]] var vector3C = self._v_points[self._v_indexes[len(self._v_indexes) - 3]] var normal = self._calc_triangle_normal(vector3C, vector3B, vector3A) vector3A = self._v_points[self._v_indexes[len(self._v_indexes) - 1]] + depth_vector vector3B = self._v_points[self._v_indexes[len(self._v_indexes) - 2]] + depth_vector vector3C = self._v_points[self._v_indexes[len(self._v_indexes) - 3]] + depth_vector self.verts.append_array([vector3A, vector3B, vector3C]) _append_uvs3(vector3A, vector3B, vector3C, normal) self.normals.append_array([normal, normal, normal]) # insert each back face into the mesh "counter-clockwise" extruded for index in range(len(self._v_indexes) - 4, -1, -3): vector3A = self._v_points[self._v_indexes[index]] + depth_vector vector3B = self._v_points[self._v_indexes[index-1]] + depth_vector vector3C = self._v_points[self._v_indexes[index-2]] + depth_vector self.verts.append_array([vector3A, vector3B, vector3C]) _append_uvs3(vector3A, vector3B, vector3C, normal) self.normals.append_array([normal, normal, normal]) func commit_mesh(mat) -> Mesh: surface_array[Mesh.ARRAY_VERTEX] = verts surface_array[Mesh.ARRAY_NORMAL] = normals surface_array[Mesh.ARRAY_TEX_UV] = uvs #print("VERTS: ", self.verts) array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) array_mesh.surface_set_material(0, mat) return array_mesh