extends Control var common = [] var common_path = "characters/common" var min_point = Vector3() var max_point = Vector3() var min_normal = Vector3() var max_normal = Vector3() const TEX_SIZE: int = 512 var maps = {} var vert_indices = {} onready var _characters = [load("res://characters/female_2018.escn"), load("res://characters/male_2018.escn")] func find_same_verts(): for chdata in range(_characters.size()): var ch_scene = _characters[chdata].instance() var bmesh = get_mesh(ch_scene, "body") if !vert_indices.has(chdata): vert_indices[chdata] = {} for surface in range(bmesh.get_surface_count()): var arrays: Array = bmesh.surface_get_arrays(surface).duplicate(true) for index1 in range(arrays[ArrayMesh.ARRAY_VERTEX].size()): var v1: Vector3 = arrays[ArrayMesh.ARRAY_VERTEX][index1] var ok = false for rk in vert_indices[chdata].keys(): if (v1 - rk).length() < 0.001: ok = true vert_indices[chdata][rk].push_back(index1) if !ok: vert_indices[chdata][v1] = [index1] func load_data(): var fd = File.new() fd.open("characters/common/data.json", File.READ) var json = fd.get_as_text() var json_result = JSON.parse(json) var json_data = json_result.result fd.close() for e in json_data.files: var load_path = "res://" + e var item = load(load_path) assert item common.push_back(item) func get_mesh(base: Node, mesh_name: String) -> ArrayMesh: var queue = [base] var mesh: ArrayMesh while queue.size() > 0: var item = queue[0] queue.pop_front() if item is MeshInstance && item.name == mesh_name: mesh = item.mesh break for c in item.get_children(): queue.push_back(c) return mesh func find_min_max(mesh: ArrayMesh): var shape_arrays = mesh.surface_get_blend_shape_arrays(0) var surf_arrays = mesh.surface_get_arrays(0) if min_point.length() == 0.0: min_point = shape_arrays[0][ArrayMesh.ARRAY_VERTEX][0] - surf_arrays[ArrayMesh.ARRAY_VERTEX][0] if min_normal.length() == 0.0: min_normal = shape_arrays[0][ArrayMesh.ARRAY_NORMAL][0] - surf_arrays[ArrayMesh.ARRAY_NORMAL][0] if max_point.length() == 0.0: max_point = shape_arrays[0][ArrayMesh.ARRAY_VERTEX][0] - surf_arrays[ArrayMesh.ARRAY_VERTEX][0] if max_normal.length() == 0.0: max_point = shape_arrays[0][ArrayMesh.ARRAY_NORMAL][0] - surf_arrays[ArrayMesh.ARRAY_NORMAL][0] for sc in range(mesh.get_surface_count()): var bshapes: Array = mesh.surface_get_blend_shape_arrays(sc).duplicate(true) var arrays: Array = mesh.surface_get_arrays(sc).duplicate(true) for src in bshapes: for index in range(arrays[ArrayMesh.ARRAY_VERTEX].size()): var v: Vector3 = src[ArrayMesh.ARRAY_VERTEX][index] - arrays[ArrayMesh.ARRAY_VERTEX][index] var n: Vector3 = src[ArrayMesh.ARRAY_NORMAL][index] - arrays[ArrayMesh.ARRAY_NORMAL][index] for ipos in range(3): if min_point[ipos] > v[ipos]: min_point[ipos] = v[ipos] if max_point[ipos] < v[ipos]: max_point[ipos] = v[ipos] if min_normal[ipos] > n[ipos]: min_normal[ipos] = n[ipos] if max_normal[ipos] < n[ipos]: max_normal[ipos] = n[ipos] print("min: ", min_point, "max: ", max_point) static func check_triangle(verts: Array, vs: Array, ns: Array) -> bool: var uv1 = verts[0] var uv2 = verts[1] var uv3 = verts[2] var v1 = uv1 - uv3 var v2 = uv1 - uv3 if v1.length() * TEX_SIZE < 1.2: return false if v2.length() * TEX_SIZE < 1.2: return false var sumdata = Vector3() for k in vs + ns: sumdata += k if sumdata.length() < 0.001: return false return true func compress_points(v: PoolVector3Array, vmin: Vector3, vmax: Vector3) -> PoolVector3Array: var cd = vmax - vmin var ret: PoolVector3Array = v for e in range(v.size()): ret[e] = v[e] - vmin for h in range(3): ret[e][h] = ret[e][h] / cd[h] return ret func build_triangles(mesh: ArrayMesh, diffmap: Dictionary): assert mesh assert max_point != min_point var cd = max_point - min_point var ncd = max_normal - min_normal for sc in range(mesh.get_surface_count()): var shape_arrays = mesh.surface_get_blend_shape_arrays(sc) var surf_arrays = mesh.surface_get_arrays(sc) for bshape in range(shape_arrays.size()): var bs_name = mesh.get_blend_shape_name(bshape) if !diffmap.has(bs_name): diffmap[bs_name] = {} diffmap[bs_name].base_v = [] diffmap[bs_name].shape_v = [] diffmap[bs_name].triangles = [] diffmap[bs_name].triangles_uv = [] diffmap[bs_name].triangles_v = PoolVector3Array() diffmap[bs_name].triangles_n = PoolVector3Array() for vid in range(0, surf_arrays[ArrayMesh.ARRAY_INDEX].size(), 3): var p1_index = surf_arrays[ArrayMesh.ARRAY_INDEX][vid + 0] var p2_index = surf_arrays[ArrayMesh.ARRAY_INDEX][vid + 1] var p3_index = surf_arrays[ArrayMesh.ARRAY_INDEX][vid + 2] var p1 = surf_arrays[ArrayMesh.ARRAY_TEX_UV][p1_index] var p2 = surf_arrays[ArrayMesh.ARRAY_TEX_UV][p2_index] var p3 = surf_arrays[ArrayMesh.ARRAY_TEX_UV][p3_index] var base_v1 = surf_arrays[ArrayMesh.ARRAY_VERTEX][p1_index] var base_v2 = surf_arrays[ArrayMesh.ARRAY_VERTEX][p2_index] var base_v3 = surf_arrays[ArrayMesh.ARRAY_VERTEX][p3_index] var shape_v1 = shape_arrays[bshape][ArrayMesh.ARRAY_VERTEX][p1_index] var shape_v2 = shape_arrays[bshape][ArrayMesh.ARRAY_VERTEX][p2_index] var shape_v3 = shape_arrays[bshape][ArrayMesh.ARRAY_VERTEX][p3_index] var d1 = shape_v1 - base_v1 var d2 = shape_v2 - base_v2 var d3 = shape_v3 - base_v3 var base_n1 = surf_arrays[ArrayMesh.ARRAY_NORMAL][p1_index] var base_n2 = surf_arrays[ArrayMesh.ARRAY_NORMAL][p2_index] var base_n3 = surf_arrays[ArrayMesh.ARRAY_NORMAL][p3_index] var shape_n1 = shape_arrays[bshape][ArrayMesh.ARRAY_NORMAL][p1_index] var shape_n2 = shape_arrays[bshape][ArrayMesh.ARRAY_NORMAL][p2_index] var shape_n3 = shape_arrays[bshape][ArrayMesh.ARRAY_NORMAL][p3_index] var nd1 = shape_n1 - base_n1 var nd2 = shape_n2 - base_n2 var nd3 = shape_n3 - base_n3 var triangle = [p1_index, p2_index, p3_index] var triangle_uv = [p1, p2, p3] # var triangle_v = compress_points([d1, d2, d3], min_point, max_point) # var triangle_n = compress_points([nd1, nd2, nd3], min_normal, max_normal) var triangle_v = PoolVector3Array([d1, d2, d3]) var triangle_n = PoolVector3Array([nd1, nd2, nd3]) if check_triangle(triangle_uv, triangle_v, triangle_n): diffmap[bs_name].triangles += triangle diffmap[bs_name].base_v += [base_v1, base_v2, base_v3] diffmap[bs_name].shape_v += [shape_v1, shape_v2, shape_v3] diffmap[bs_name].triangles_uv += triangle_uv diffmap[bs_name].triangles_v += triangle_v diffmap[bs_name].triangles_n += triangle_n # print_debug("surface: ", sc, " shape: ", bs_name, "/", bshape, # " triangle: ", diffmap[bs_name].triangles_uv.size() / 3) func convert_triangles(base: Dictionary, helper: Dictionary): pass enum {STATE_DRAW, STATE_CHECK, STATE_FINISH} var draw_queue = [] func create_queue(diffmap: Dictionary): for k in diffmap.keys(): var mesh_name:String = k var prefix = "" if mesh_name.ends_with("_helper"): prefix = mesh_name.replace("_helper", "_") for map_name in diffmap[k]: var map_key = prefix + map_name var data = {} data.map = map_key data.normals = false data.triangles_uv = diffmap[k][map_name].triangles_uv data.triangles_v = diffmap[k][map_name].triangles_v data.rect = diffmap[k][map_name].rect draw_queue.push_back(data) data = {} data.map = map_key data.normals = true data.triangles_uv = diffmap[k][map_name].triangles_uv data.triangles_v = diffmap[k][map_name].triangles_n data.rect = diffmap[k][map_name].rect draw_queue.push_back(data) func _ready(): load_data() var base_mesh = "base" var helper_meshes = ["robe_helper", "tights_helper", "skirt_helper"] var diffmap = {} for c in common: for mesh_name in [base_mesh] + helper_meshes: var obj = c.instance() var mesh = get_mesh(obj, mesh_name) find_min_max(mesh) for c in common: var obj = c.instance() if !diffmap.has(base_mesh): diffmap[base_mesh] = {} var mesh = get_mesh(obj, base_mesh) build_triangles(mesh, diffmap[base_mesh]) print("scene: ", c, "mesh: ", base_mesh, " done") for mesh_name in helper_meshes: var helper_mesh = get_mesh(obj, mesh_name) if !diffmap.has(mesh_name): diffmap[mesh_name] = {} build_triangles(helper_mesh, diffmap[mesh_name]) convert_triangles(diffmap[base_mesh], diffmap[mesh_name]) print("scene: ", c, "mesh: ", mesh_name, " done") print("scene: ", c, " done") for e in diffmap.keys(): for k in diffmap[e].keys(): diffmap[e][k].triangles_v = compress_points(diffmap[e][k].triangles_v, min_point, max_point) diffmap[e][k].triangles_n = compress_points(diffmap[e][k].triangles_n, min_point, max_point) print_debug("mesh:", e, "shape: ", k, " triangle: ", diffmap[e][k].triangles_uv.size() / 3) if diffmap[e][k].triangles_uv.size() > 0: diffmap[e][k].rect = Rect2(diffmap[e][k].triangles_uv[0], Vector2()) else: diffmap[e][k].rect = Rect2() for m in diffmap[e][k].triangles_uv: diffmap[e][k].rect = diffmap[e][k].rect.expand(m) for e in diffmap.keys(): for h in diffmap[e].keys(): print(e, ": ", h) create_queue(diffmap) print("prep done, ", draw_queue.size()) $gen/drawable.connect("draw", self, "draw_viewport") total_count = draw_queue.size() var total_count : = 0 func save_viewport(shape_name: String, rect: Rect2, draw_normals: bool): var viewport: Viewport = $gen viewport.set_clear_mode(Viewport.CLEAR_MODE_ONLY_NEXT_FRAME) yield(get_tree(), "idle_frame") yield(get_tree(), "idle_frame") var vtex : = viewport.get_texture() var tex_img : = vtex.get_data() var fn = "" if !maps.has(shape_name): maps[shape_name] = {} maps[shape_name].width = tex_img.get_width() maps[shape_name].height = tex_img.get_height() maps[shape_name].format = tex_img.get_format() var byte_data = tex_img.duplicate(true).get_data() var image_size = byte_data.size() if draw_normals: maps[shape_name].image_normal_data = byte_data.compress(File.COMPRESSION_FASTLZ) maps[shape_name].image_normal_size = image_size else: maps[shape_name].image_data = byte_data.compress(File.COMPRESSION_FASTLZ) maps[shape_name].rect = rect.grow(0.003) maps[shape_name].image_size = image_size func draw_viewport(): var draw_obj = $gen/drawable if draw_queue.size() == 0: return var item = draw_queue[0] var default_color = Color(0.5, 0.5, 0.5, 1.0) var _min_point: Vector3 var _max_point: Vector3 if item.normals: _min_point = min_normal _max_point = max_normal else: _min_point = min_point _max_point = max_point default_color.r = range_lerp(0, _min_point.x, _max_point.x, 0.0, 1.0) default_color.g = range_lerp(0, _min_point.y, _max_point.y, 0.0, 1.0) default_color.b = range_lerp(0, _min_point.z, _max_point.z, 0.0, 1.0) draw_obj.draw_rect(Rect2(0, 0, TEX_SIZE, TEX_SIZE), default_color, true) print("draw: ", item.triangles_uv.size()) for t in range(0, item.triangles_uv.size(), 3): var colors = [] var uvs = [] var p1 = item.triangles_uv[t + 0] var p2 = item.triangles_uv[t + 1] var p3 = item.triangles_uv[t + 2] var sum = p1 + p2 + p3 var midp = sum / 3.0 for k in range(3): # print(k.shape) # print(k.uv) var v = item.triangles_v[t + k] colors.push_back(Color(v.x, v.y, v.z, 1)) var uv = item.triangles_uv[t + k] var pt = (uv - midp).normalized() * 3.5 uvs.push_back(uv * TEX_SIZE + pt) draw_obj.draw_polygon(PoolVector2Array(uvs), PoolColorArray(colors)) var _state = STATE_DRAW var draw_delay: float = 0.1 var save_pngs : = false func save_images(): for k in maps.keys(): for e in ["diffuse", "normal"]: var fn = "res://characters/common/" + k + "_" + e + ".png" var data: PoolByteArray var size: int if e == "diffuse": data = maps[k].image_data size = maps[k].image_size elif e == "normal": data = maps[k].image_normal_data size = maps[k].image_normal_size var image_data = data.decompress(size, File.COMPRESSION_FASTLZ) var img = Image.new() img.create_from_data(maps[k].width, maps[k].height, false, maps[k].format, image_data) print("saving ", fn) img.save_png(fn) func _process(delta): match(_state): STATE_CHECK: if draw_delay > 0.0: draw_delay -= delta elif draw_queue.size() > 0: save_viewport(draw_queue[0].map, draw_queue[0].rect, draw_queue[0].normals) print("drawing complete: ", draw_queue.size()) draw_queue.pop_front() _state = STATE_DRAW else: _state = STATE_FINISH STATE_DRAW: $gen/drawable.update() draw_delay = 0.05 _state = STATE_CHECK STATE_FINISH: print("generating same vert indices...") find_same_verts() var fd = File.new() fd.open("res://characters/common/config.bin", File.WRITE) fd.store_var(min_point) fd.store_var(max_point) fd.store_var(min_normal) fd.store_var(max_normal) fd.store_var(maps) fd.store_var(vert_indices) fd.close() if save_pngs: save_images() get_tree().quit()