extends Object class_name GeoPolyMesh var surface_array = [] var verts = PackedVector3Array() var uvs = PackedVector2Array() var normals = PackedVector3Array() var array_mesh = ArrayMesh.new() 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, 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) self._v_indexes = vector_indexes self.extrude_direction = extrude_direction if extrude_direction == DestructableWall.ExtrudeDirection.BACK: for point in vector_points: self._v_points.append(Vector3(point.x, point.y, 0)) depth_vector = Vector3.BACK * depth elif extrude_direction == DestructableWall.ExtrudeDirection.RIGHT: for point in vector_points: self._v_points.append(Vector3(0, point.y, point.x)) depth_vector = Vector3.LEFT * depth elif extrude_direction == DestructableWall.ExtrudeDirection.UP: for point in vector_points: self._v_points.append(Vector3(point.x, 0, 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 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_uvs4(v0, v1, v2, v3, n1) self.normals.append_array([n1, n1, n1, n1, n1, n1]) func _append_uvs4(v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, normal: Vector3): if normal == Vector3.BACK or normal == Vector3.FORWARD: self.uvs.append_array([Vector2(-v0.x, -v0.y), Vector2(-v1.x, -v1.y), Vector2(-v2.x, -v2.y), Vector2(-v1.x, -v1.y), Vector2(-v3.x, -v3.y), Vector2(-v2.x, -v2.y)]) return elif normal == Vector3.RIGHT or normal == Vector3.LEFT: self.uvs.append_array([Vector2(-v0.z, -v0.y), Vector2(-v1.z, -v1.y), Vector2(-v2.z, -v2.y), Vector2(-v1.z, -v1.y), Vector2(-v3.z, -v3.y), Vector2(-v2.z, -v2.y)]) return elif normal == Vector3.UP or normal == Vector3.DOWN: self.uvs.append_array([Vector2(-v0.x, -v0.z), Vector2(-v1.x, -v1.z), Vector2(-v2.x, -v2.z), Vector2(-v1.x, -v1.z), Vector2(-v3.x, -v3.z), Vector2(-v2.x, -v2.z)]) return self.uvs.append_array([Vector2(-v0.x, -v0.y), Vector2(-v1.x, -v1.y), Vector2(-v2.x, -v2.y), Vector2(-v1.x, -v1.y), Vector2(-v3.x, -v3.y), Vector2(-v2.x, -v2.y)]) func _append_uvs3(v0: Vector3, v1: Vector3, v2: Vector3, normal: Vector3): if normal == Vector3.BACK or normal == Vector3.FORWARD: self.uvs.append_array([Vector2(-v0.x, -v0.y), Vector2(-v1.x, -v1.y), Vector2(-v2.x, -v2.y)]) return elif normal == Vector3.RIGHT or normal == Vector3.LEFT: self.uvs.append_array([Vector2(-v0.z, -v0.y), Vector2(-v1.z, -v1.y), Vector2(-v2.z, -v2.y)]) return elif normal == Vector3.UP or normal == Vector3.DOWN: self.uvs.append_array([Vector2(-v0.x, -v0.z), Vector2(-v1.x, -v1.z), Vector2(-v2.x, -v2.z)]) return self.uvs.append_array([Vector2(-v0.x, -v0.y), Vector2(-v1.x, -v1.y), Vector2(-v2.x, -v2.y)]) # 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