Added C++ DNA class version

This commit is contained in:
Segey Lapin
2019-08-25 17:19:35 +03:00
parent 8e70ba69bd
commit a78670739d

View File

@@ -0,0 +1,309 @@
extends Reference
class_name DNAcpp
var min_point: Vector3 = Vector3()
var max_point: Vector3 = Vector3()
var min_normal: Vector3 = Vector3()
var max_normal: Vector3 = Vector3()
var maps : = {}
var vert_indices : = {}
#var orig_body_mesh: ArrayMesh
var meshes : = {}
var clothes : = {}
var dna_ = DNA_.new()
#var uv_to_uv2: Dictionary
func get_modifier_list() -> Array:
return Array(dna_.get_modifier_list())
func add_mesh(part_name: String, mesh: ArrayMesh, v_indices: Dictionary):
dna_.add_mesh(part_name, mesh, v_indices)
meshes[part_name] = {
"orig_mesh": mesh,
"same_indices": v_indices,
}
#func triangulate_uv(v0: Vector3, vs: PoolVector3Array, uvs: PoolVector2Array) -> Vector2:
# assert vs.size() == 3
# var d1: float = v0.distance_to(vs[0])
# var d2: float = v0.distance_to(vs[1])
# var d3: float = v0.distance_to(vs[2])
# var ln = max(d1, max(d2, d3))
# var v = Vector3(d1/ln, d2/ln, d3/ln)
# var midp : Vector2 = (uvs[0] + uvs[1] + uvs[2]) * 1.0 / 3.0
# var uv: Vector2 = midp.linear_interpolate(uvs[0], v.x) + midp.linear_interpolate(uvs[1], v.y) + midp.linear_interpolate(uvs[2], v.z)
# uv /= 3.0
# return uv
#func _prepare_cloth(body_mesh: ArrayMesh, cloth_mesh: ArrayMesh) -> ArrayMesh:
# var arrays_cloth: Array = cloth_mesh.surface_get_arrays(0)
# dna_.ensure_uv2(arrays_cloth)
# assert arrays_cloth[ArrayMesh.ARRAY_TEX_UV2] != null
## if arrays_cloth[ArrayMesh.ARRAY_TEX_UV2] == null:
## var d: PoolVector2Array = PoolVector2Array()
## d.resize(arrays_cloth[ArrayMesh.ARRAY_VERTEX].size())
## assert d.size() > 0
## arrays_cloth[ArrayMesh.ARRAY_TEX_UV2] = d
# var arrays_body: Array = body_mesh.surface_get_arrays(0)
# var tmp: Dictionary = dna_.find_body_points(body_mesh, cloth_mesh)
## for vcloth in range(arrays_cloth[ArrayMesh.ARRAY_VERTEX].size()):
## for vbody in range(arrays_body[ArrayMesh.ARRAY_VERTEX].size()):
## var vc: Vector3 = arrays_cloth[ArrayMesh.ARRAY_VERTEX][vcloth]
## var vb: Vector3 = arrays_body[ArrayMesh.ARRAY_VERTEX][vbody]
## if vc.distance_to(vb) < 0.02:
## if tmp.has(vcloth):
## tmp[vcloth].push_back(vbody)
## else:
## tmp[vcloth] = [vbody]
# for k in tmp.keys():
# var vc: Vector3 = arrays_cloth[ArrayMesh.ARRAY_VERTEX][k]
# var res: PoolIntArray = dna_.get_closest_points(vc, arrays_body[ArrayMesh.ARRAY_VERTEX], PoolIntArray(tmp[k]), 3)
## for v in tmp[k]:
### var vb: Vector3 = arrays_body[ArrayMesh.ARRAY_VERTEX][v]
### var d1 = vc.distance_squared_to(vb)
## if res.size() >= 3:
## var mv = dna_.get_replace_point_id(arrays_body[ArrayMesh.ARRAY_VERTEX], vc, v, PoolIntArray(res))
## if mv >= 0:
## res[mv] = v
### for mv in range(res.size()):
### var vb1: Vector3 = arrays_body[ArrayMesh.ARRAY_VERTEX][res[mv]]
### var d2 = vc.distance_squared_to(vb1)
### if d1 < d2 && !v in res:
### res[mv] = v
## else:
## if ! v in res:
## res.push_back(v)
## tmp[k] = res
# if res.size() == 3:
## var vtx: Vector3 = arrays_cloth[ArrayMesh.ARRAY_VERTEX][k]
# arrays_cloth[ArrayMesh.ARRAY_TEX_UV2][k] = dna_.triangulate_uv_arrays(vc, ArrayMesh.ARRAY_TEX_UV, arrays_body, PoolIntArray(res))
## var bverts = PoolVector3Array()
## var buvs = PoolVector2Array()
## for e in res:
## var vb: Vector3 = arrays_body[ArrayMesh.ARRAY_VERTEX][e]
## var ub: Vector2 = arrays_body[ArrayMesh.ARRAY_TEX_UV][e]
## bverts.push_back(vb)
## buvs.push_back(ub)
## arrays_cloth[ArrayMesh.ARRAY_TEX_UV2][k] = dna_.triangulate_uv(vtx, bverts, buvs)
# var new_mesh : = ArrayMesh.new()
# new_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_cloth)
# return new_mesh
func add_cloth_mesh(cloth_name: String, cloth_helper: String, mesh: ArrayMesh):
dna_.add_cloth_mesh(cloth_name, cloth_helper, mesh)
var new_mesh = dna_._prepare_cloth(meshes.body.orig_mesh, mesh)
print("new mesh: ", meshes.body.orig_mesh, " ", new_mesh)
add_mesh(cloth_name, new_mesh, {})
clothes[cloth_name] = {}
clothes[cloth_name].helper = cloth_helper
return new_mesh
func add_body_mesh(mesh: ArrayMesh, same_indices: Dictionary):
dna_.add_body_mesh(mesh, same_indices)
add_mesh("body", mesh, same_indices)
func build_mesh_cache(orig_mesh: ArrayMesh) -> Dictionary:
var ret : = {}
for k in maps.keys():
maps[k].image.lock()
maps[k].image_normal.lock()
for surface in range(orig_mesh.get_surface_count()):
if !ret.has(surface):
ret[surface] = {}
var arrays: Array = orig_mesh.surface_get_arrays(surface)
var uv_index: int = ArrayMesh.ARRAY_TEX_UV
if arrays[ArrayMesh.ARRAY_TEX_UV2] && arrays[ArrayMesh.ARRAY_TEX_UV2].size() > 0:
uv_index = ArrayMesh.ARRAY_TEX_UV2
ret[surface].uv_index = uv_index
for index in range(arrays[ArrayMesh.ARRAY_VERTEX].size()):
var v: Vector3 = arrays[ArrayMesh.ARRAY_VERTEX][index]
var n: Vector3 = arrays[ArrayMesh.ARRAY_NORMAL][index]
var uv: Vector2 = arrays[uv_index][index]
var diff : = Vector3()
var diffn : = Vector3()
if !ret[surface].has("data"):
ret[surface].data = {}
if !ret[surface].data.has(index):
ret[surface].data[index] = {}
ret[surface].data[index].v = v
ret[surface].data[index].n = n
ret[surface].data[index].uv = uv
for k in maps.keys():
var pos: Vector2 = Vector2(uv.x * maps[k].width, uv.y * maps[k].height)
var offset: Color = maps[k].image.get_pixelv(pos)
var offsetn: Color = maps[k].image_normal.get_pixelv(pos)
var pdiff: Vector3 = Vector3(offset.r, offset.g, offset.b)
var ndiff: Vector3 = Vector3(offsetn.r, offsetn.g, offsetn.b)
for u in range(3):
diff[u] = range_lerp(pdiff[u], 0.0, 1.0, min_point[u], max_point[u])
diffn[u] = range_lerp(ndiff[u], 0.0, 1.0, min_normal[u], max_normal[u])
if abs(diff[u]) < 0.0001:
diff[u] = 0
if !ret[surface].data[index].has("d"):
ret[surface].data[index].d = {}
ret[surface].data[index].d[k] = {
"v": diff,
"n": diffn
}
for k in maps.keys():
maps[k].image.unlock()
maps[k].image_normal.unlock()
return ret
func modify_mesh_cached(orig_mesh: ArrayMesh, v_indices: Dictionary, cache: Dictionary) -> ArrayMesh:
var mod_mesh = ArrayMesh.new()
var mrect: Rect2
var start_time = OS.get_unix_time()
for k in maps.keys():
if maps[k].value > 0.0001:
if mrect:
mrect = mrect.merge(maps[k].rect)
else:
mrect = maps[k].rect
for surface in cache.keys():
var arrays: Array = orig_mesh.surface_get_arrays(surface)
var uv_index: int = cache[surface].uv_index
# if arrays[ArrayMesh.ARRAY_TEX_UV2] && arrays[ArrayMesh.ARRAY_TEX_UV2].size() > 0:
# uv_index = ArrayMesh.ARRAY_TEX_UV2
var modify_time = 0
var modify_start = 0
for index in cache[surface].data.keys():
modify_start = OS.get_unix_time()
var v: Vector3 = cache[surface].data[index].v
var n: Vector3 = cache[surface].data[index].n
var uv: Vector2 = cache[surface].data[index].uv
if !mrect.has_point(uv):
continue
for k in cache[surface].data[index].d.keys():
var diff = cache[surface].data[index].d[k].v * maps[k].value
var diffn = cache[surface].data[index].d[k].n * maps[k].value
v -= diff
n -= diffn
arrays[ArrayMesh.ARRAY_VERTEX][index] = v
arrays[ArrayMesh.ARRAY_NORMAL][index] = n.normalized()
modify_time = OS.get_unix_time() - modify_start
print("elapsed modify: ", modify_time)
var update_time = OS.get_unix_time() - start_time
print("elapsed update: ", update_time)
for v in v_indices.keys():
if v_indices[v].size() <= 1:
continue
var vx: Vector3 = arrays[ArrayMesh.ARRAY_VERTEX][v_indices[v][0]]
for idx in range(1, v_indices[v].size()):
vx = vx.linear_interpolate(arrays[ArrayMesh.ARRAY_VERTEX][v_indices[v][idx]], 0.5)
for idx in v_indices[v]:
arrays[ArrayMesh.ARRAY_VERTEX][idx] = vx
var surface_time = OS.get_unix_time() - start_time
print("elapsed surface: ", surface_time)
mod_mesh.add_surface_from_arrays(ArrayMesh.PRIMITIVE_TRIANGLES, arrays)
if orig_mesh.surface_get_material(surface):
mod_mesh.surface_set_material(surface, orig_mesh.surface_get_material(surface).duplicate(true))
var total_time = OS.get_unix_time() - start_time
print("elapsed: ", total_time)
return mod_mesh
var mod_cache : = []
var data_mutex = Mutex.new()
func modify_mesh(orig_mesh: ArrayMesh, v_indices: Dictionary) -> ArrayMesh:
for k in maps.keys():
maps[k].image.lock()
maps[k].image_normal.lock()
var surf : = 0
var mod_mesh = ArrayMesh.new()
var mrect: Rect2
for k in maps.keys():
if maps[k].value > 0.0001:
if mrect:
mrect = mrect.merge(maps[k].rect)
else:
mrect = maps[k].rect
for surface in range(orig_mesh.get_surface_count()):
var arrays: Array = orig_mesh.surface_get_arrays(surface)
var uv_index: int = ArrayMesh.ARRAY_TEX_UV
if arrays[ArrayMesh.ARRAY_TEX_UV2] && arrays[ArrayMesh.ARRAY_TEX_UV2].size() > 0:
uv_index = ArrayMesh.ARRAY_TEX_UV2
mod_cache.resize(arrays[ArrayMesh.ARRAY_VERTEX].size())
var n: Vector3
var v: Vector3
var uv: Vector2
var diff: Vector3
var diffn: Vector3
for index in range(arrays[ArrayMesh.ARRAY_VERTEX].size()):
v = arrays[ArrayMesh.ARRAY_VERTEX][index]
n = arrays[ArrayMesh.ARRAY_NORMAL][index]
uv = arrays[uv_index][index]
if !mrect.has_point(uv):
continue
if !mod_cache[index]:
mod_cache[index] = {}
for k in maps.keys():
if !maps[k].rect.has_point(uv) || abs(maps[k].value) < 0.0001:
continue
if mod_cache[index].has(k):
diff = mod_cache[index][k][0]
diffn = mod_cache[index][k][1]
else:
diff = Vector3.ZERO
diffn = Vector3.ZERO
var pos: Vector2 = Vector2(uv.x * maps[k].width, uv.y * maps[k].height)
var offset: Color = maps[k].image.get_pixelv(pos)
var offsetn: Color = maps[k].image_normal.get_pixelv(pos)
var pdiff: Vector3 = Vector3(offset.r, offset.g, offset.b)
var ndiff: Vector3 = Vector3(offsetn.r, offsetn.g, offsetn.b)
for u in range(3):
diff[u] = range_lerp(pdiff[u], 0.0, 1.0, min_point[u], max_point[u])
diffn[u] = range_lerp(ndiff[u], 0.0, 1.0, min_normal[u], max_normal[u])
if abs(diff[u]) < 0.0001:
diff[u] = 0
mod_cache[index][k] = [diff, diffn]
v -= diff * maps[k].value
n -= diffn * maps[k].value
arrays[ArrayMesh.ARRAY_VERTEX][index] = v
arrays[ArrayMesh.ARRAY_NORMAL][index] = n.normalized()
for v in v_indices.keys():
if v_indices[v].size() <= 1:
continue
var vx: Vector3 = arrays[ArrayMesh.ARRAY_VERTEX][v_indices[v][0]]
for idx in range(1, v_indices[v].size()):
vx = vx.linear_interpolate(arrays[ArrayMesh.ARRAY_VERTEX][v_indices[v][idx]], 0.5)
for idx in v_indices[v]:
arrays[ArrayMesh.ARRAY_VERTEX][idx] = vx
mod_mesh.add_surface_from_arrays(ArrayMesh.PRIMITIVE_TRIANGLES, arrays)
if orig_mesh.surface_get_material(surface):
mod_mesh.surface_set_material(surface, orig_mesh.surface_get_material(surface).duplicate(true))
surf += 1
for k in maps.keys():
maps[k].image.unlock()
maps[k].image_normal.unlock()
return mod_mesh
func modify_part(part_name) -> ArrayMesh:
# dna_.modify_part(part_name)
var mesh = meshes[part_name].orig_mesh
var indices = meshes[part_name].same_indices
# var cache = meshes[part_name].cache
return dna_.modify_mesh(mesh, indices)
func set_modifier_value(modifier: String, value: float):
dna_.set_modifier_value(modifier, value)
maps[modifier].value = value
func _init(path: String):
dna_.load(path)
var fd = File.new()
fd.open(path, File.READ)
min_point = fd.get_var()
max_point = fd.get_var()
min_normal = fd.get_var()
max_normal = fd.get_var()
maps = fd.get_var()
print(maps.keys())
vert_indices = fd.get_var()
# uv_to_uv2 = fd.get_var()
fd.close()
print("min: ", min_point, " max: ", max_point)
for k in maps.keys():
print(k, ": ", maps[k].rect)
for k in maps.keys():
maps[k].image_normal = Image.new()
var normal_data = maps[k].image_normal_data.decompress(maps[k].image_normal_size, File.COMPRESSION_FASTLZ)
var data = maps[k].image_data.decompress(maps[k].image_size, File.COMPRESSION_FASTLZ)
maps[k].image_normal.create_from_data(maps[k].width, maps[k].height, false, maps[k].format, normal_data)
maps[k].image = Image.new()
maps[k].image.create_from_data(maps[k].width, maps[k].height, false, maps[k].format, data)
maps[k].value = 0.0