diff --git a/proto2/characters/generate_maps2.gd b/proto2/characters/generate_maps2.gd new file mode 100644 index 0000000..81e80e9 --- /dev/null +++ b/proto2/characters/generate_maps2.gd @@ -0,0 +1,365 @@ +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() diff --git a/proto2/characters/generate_maps2.tscn b/proto2/characters/generate_maps2.tscn new file mode 100644 index 0000000..578be11 --- /dev/null +++ b/proto2/characters/generate_maps2.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://characters/generate_maps2.gd" type="Script" id=2] + +[node name="generate_maps2" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": true +} + +[node name="gen" type="Viewport" parent="."] +size = Vector2( 512, 512 ) +disable_3d = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="drawable" type="ColorRect" parent="gen"] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="gen_maps" type="VBoxContainer" parent="."] +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +margin_top = -16.0 +margin_bottom = 16.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="gen_maps"] +margin_right = 1024.0 +margin_bottom = 14.0 +text = "Generating maps..." + +[node name="ProgressBar" type="ProgressBar" parent="gen_maps"] +margin_top = 18.0 +margin_right = 1024.0 +margin_bottom = 32.0