2024-01-26 20:00:32 +00:00
|
|
|
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
|
2023-10-05 18:02:23 +00:00
|
|
|
# See `LICENSE.md` included in the source distribution for details.
|
|
|
|
#const RiverManager = preload("./river_manager.gd")
|
|
|
|
|
|
|
|
static func cart2bary(p : Vector3, a : Vector3, b : Vector3, c: Vector3) -> Vector3:
|
|
|
|
var v0 := b - a
|
|
|
|
var v1 := c - a
|
|
|
|
var v2 := p - a
|
|
|
|
var d00 := v0.dot(v0)
|
|
|
|
var d01 := v0.dot(v1)
|
|
|
|
var d11 := v1.dot(v1)
|
|
|
|
var d20 := v2.dot(v0)
|
|
|
|
var d21 := v2.dot(v1)
|
|
|
|
var denom := d00 * d11 - d01 * d01
|
|
|
|
var v = (d11 * d20 - d01 * d21) / denom
|
|
|
|
var w = (d00 * d21 - d01 * d20) / denom
|
|
|
|
var u = 1.0 - v - w
|
|
|
|
return Vector3(u, v, w)
|
|
|
|
|
|
|
|
|
|
|
|
static func bary2cart(a : Vector3, b : Vector3, c: Vector3, barycentric: Vector3) -> Vector3:
|
|
|
|
return barycentric.x * a + barycentric.y * b + barycentric.z * c
|
|
|
|
|
|
|
|
|
|
|
|
static func point_in_bariatric(v : Vector3) -> bool:
|
|
|
|
return 0 <= v.x and v.x <= 1 and 0 <= v.y and v.y <= 1 and 0 <= v.z and v.z <= 1;
|
|
|
|
|
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
static func sum_array(array : Array[float]) -> float:
|
2023-10-05 18:02:23 +00:00
|
|
|
var sum := 0.0
|
|
|
|
for element in array:
|
|
|
|
sum += element
|
|
|
|
return sum
|
|
|
|
|
|
|
|
|
|
|
|
static func calculate_side(steps : int) -> int:
|
|
|
|
var side_float : float = sqrt(steps)
|
|
|
|
if fmod(side_float, 1.0) != 0.0:
|
|
|
|
side_float += 1.0
|
|
|
|
return int(side_float)
|
|
|
|
|
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
static func generate_river_width_values(curve : Curve3D, steps : int, step_length_divs : int, step_width_divs : int, widths : Array[float]) -> Array[float]:
|
2023-10-05 18:02:23 +00:00
|
|
|
var river_width_values: Array[float]
|
|
|
|
var length := curve.get_baked_length()
|
|
|
|
for step in steps * step_length_divs + 1:
|
|
|
|
var target_pos := curve.sample_baked((float(step) / float(steps * step_length_divs + 1)) * curve.get_baked_length())
|
|
|
|
var closest_dist := 4096.0
|
|
|
|
var closest_interpolate : float
|
|
|
|
var closest_point : int
|
|
|
|
for c_point in curve.get_point_count() - 1:
|
|
|
|
for i in 100:
|
|
|
|
var interpolate := float(i) / 100.0
|
|
|
|
var pos := curve.sample(c_point, interpolate)
|
|
|
|
var dist = pos.distance_to(target_pos)
|
|
|
|
if dist < closest_dist:
|
|
|
|
closest_dist = dist
|
|
|
|
closest_interpolate = interpolate
|
|
|
|
closest_point = c_point
|
|
|
|
river_width_values.append( lerp(widths[closest_point], widths[closest_point + 1], closest_interpolate) )
|
|
|
|
|
|
|
|
return river_width_values
|
|
|
|
|
|
|
|
|
|
|
|
static func generate_river_mesh(curve: Curve3D, steps: int, step_length_divs: int, step_width_divs: int, smoothness: float, river_width_values: Array[float]) -> Mesh:
|
|
|
|
var st := SurfaceTool.new()
|
|
|
|
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
|
|
|
var curve_length := curve.get_baked_length()
|
|
|
|
st.set_smooth_group(0)
|
|
|
|
|
|
|
|
# Generating the verts
|
|
|
|
for step in steps * step_length_divs + 1:
|
|
|
|
var position := curve.sample_baked(float(step) / float(steps * step_length_divs) * curve_length, false)
|
|
|
|
var backward_pos := curve.sample_baked((float(step) - smoothness) / float(steps * step_length_divs) * curve_length, false)
|
|
|
|
var forward_pos := curve.sample_baked((float(step) + smoothness) / float(steps * step_length_divs) * curve_length, false)
|
|
|
|
var forward_vector := forward_pos - backward_pos
|
|
|
|
var right_vector := forward_vector.cross(Vector3.UP).normalized()
|
|
|
|
|
|
|
|
var width_lerp : float = river_width_values[step]
|
|
|
|
|
|
|
|
for w_sub in step_width_divs + 1:
|
|
|
|
st.set_uv(Vector2(float(w_sub) / (float(step_width_divs)), float(step) / float(step_length_divs) ))
|
|
|
|
st.add_vertex(position + right_vector * width_lerp - 2.0 * right_vector * width_lerp * float(w_sub) / (float(step_width_divs)))
|
|
|
|
|
|
|
|
# Defining the tris
|
|
|
|
for step in steps * step_length_divs:
|
|
|
|
for w_sub in step_width_divs:
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub)
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub + 1)
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub + 2 + step_width_divs - 1)
|
|
|
|
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub + 1)
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub + 3 + step_width_divs - 1)
|
|
|
|
st.add_index( (step * (step_width_divs + 1)) + w_sub + 2 + step_width_divs - 1)
|
|
|
|
|
|
|
|
st.generate_normals()
|
|
|
|
st.generate_tangents()
|
|
|
|
st.deindex()
|
|
|
|
|
|
|
|
var mesh := ArrayMesh.new()
|
|
|
|
var mesh2 := ArrayMesh.new()
|
|
|
|
var mesh3 := ArrayMesh.new()
|
|
|
|
mesh = st.commit()
|
|
|
|
|
|
|
|
var mdt := MeshDataTool.new()
|
|
|
|
mdt.create_from_surface(mesh, 0)
|
|
|
|
|
|
|
|
# Generate UV2
|
|
|
|
# Decide on grid size
|
|
|
|
var grid_side := calculate_side(steps)
|
|
|
|
var grid_side_length := 1.0 / float(grid_side)
|
|
|
|
var x_grid_sub_length := grid_side_length / float(step_width_divs)
|
|
|
|
var y_grid_sub_length := grid_side_length / float(step_length_divs)
|
|
|
|
var grid_size := pow(grid_side, 2)
|
|
|
|
var index := 0
|
|
|
|
var UVs := steps * step_width_divs * step_length_divs * 6
|
|
|
|
var x_offset := 0.0
|
|
|
|
for x in grid_side:
|
|
|
|
var y_offset := 0.0
|
|
|
|
for y in grid_side:
|
|
|
|
|
|
|
|
if index < UVs:
|
|
|
|
var sub_y_offset := 0.0
|
|
|
|
for sub_y in step_length_divs:
|
|
|
|
var sub_x_offset := 0.0
|
|
|
|
for sub_x in step_width_divs:
|
|
|
|
var x_comb_offset := x_offset + sub_x_offset
|
|
|
|
var y_comb_offset := y_offset + sub_y_offset
|
|
|
|
mdt.set_vertex_uv2(index, Vector2(x_comb_offset, y_comb_offset))
|
|
|
|
mdt.set_vertex_uv2(index + 1, Vector2(x_comb_offset + x_grid_sub_length, y_comb_offset))
|
|
|
|
mdt.set_vertex_uv2(index + 2, Vector2(x_comb_offset, y_comb_offset + y_grid_sub_length))
|
|
|
|
|
|
|
|
mdt.set_vertex_uv2(index + 3, Vector2(x_comb_offset + x_grid_sub_length, y_comb_offset))
|
|
|
|
mdt.set_vertex_uv2(index + 4, Vector2(x_comb_offset + x_grid_sub_length, y_comb_offset + y_grid_sub_length))
|
|
|
|
mdt.set_vertex_uv2(index + 5, Vector2(x_comb_offset, y_comb_offset + y_grid_sub_length))
|
|
|
|
index += 6
|
|
|
|
sub_x_offset += grid_side_length / float(step_width_divs)
|
|
|
|
sub_y_offset += grid_side_length / float(step_length_divs)
|
|
|
|
|
|
|
|
y_offset += grid_side_length
|
|
|
|
x_offset += grid_side_length
|
|
|
|
|
|
|
|
mdt.commit_to_surface(mesh2)
|
|
|
|
st.clear()
|
|
|
|
st.create_from(mesh2, 0)
|
|
|
|
st.index()
|
|
|
|
mesh3 = st.commit()
|
|
|
|
return mesh3
|
|
|
|
|
|
|
|
|
|
|
|
static func generate_collisionmap(image: Image, mesh_instance: MeshInstance3D, raycast_dist: float, raycast_layers: int, steps: int, step_length_divs: int, step_width_divs: int, river) -> Image:
|
|
|
|
var space_state := mesh_instance.get_world_3d().direct_space_state
|
|
|
|
|
|
|
|
var uv2 := mesh_instance.mesh.surface_get_arrays(0)[5] as PackedVector2Array
|
|
|
|
var verts := mesh_instance.mesh.surface_get_arrays(0)[0] as PackedVector3Array
|
|
|
|
# We need to move the verts into world space
|
|
|
|
var world_verts := PackedVector3Array()
|
|
|
|
for v in verts.size():
|
|
|
|
world_verts.append( mesh_instance.global_transform * (verts[v]) )
|
|
|
|
|
|
|
|
var tris_in_step_quad := step_length_divs * step_width_divs * 2
|
|
|
|
var side := calculate_side(steps)
|
|
|
|
var percentage = 0.0
|
|
|
|
|
|
|
|
river.emit_signal("progress_notified", percentage, "Calculating Collisions (" + str(image.get_width()) + "x" + str(image.get_width()) + ")")
|
|
|
|
await river.get_tree().process_frame
|
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
#var ray_params := PhysicsRayQueryParameters3D.create(Vector3(0.0, 5.0, 0.0), Vector3(0.0, 0.0, 0.0), raycast_layers)
|
2023-10-05 18:02:23 +00:00
|
|
|
#ray_params_up.collision_mask = raycast_layers
|
2024-01-26 20:00:32 +00:00
|
|
|
#var result = space_state.intersect_ray(ray_params)
|
2023-10-05 18:02:23 +00:00
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
#print(result)
|
2023-10-05 18:02:23 +00:00
|
|
|
|
|
|
|
for x in image.get_width():
|
|
|
|
var cur_percentage := float(x) / float(image.get_width())
|
|
|
|
if cur_percentage > percentage + 0.1:
|
|
|
|
percentage += 0.1
|
|
|
|
|
|
|
|
river.emit_signal("progress_notified", percentage, "Calculating Collisions (" + str(image.get_width()) + "x" + str(image.get_width()) + ")")
|
|
|
|
await river.get_tree().process_frame
|
|
|
|
for y in image.get_height():
|
|
|
|
var uv_coordinate := Vector2( ( 0.5 + float(x)) / float(image.get_width()), ( 0.5 + float(y)) / float(image.get_height()) )
|
|
|
|
var baryatric_coords : Vector3
|
|
|
|
var correct_triangle := []
|
|
|
|
|
|
|
|
var pixel := int(x * image.get_width() + y)
|
|
|
|
var column := (pixel / image.get_width()) / (image.get_width() / side)
|
|
|
|
var row := (pixel % image.get_width()) / (image.get_width() / side)
|
|
|
|
var step_quad := column * side + row
|
|
|
|
|
|
|
|
if step_quad >= steps:
|
|
|
|
break # we are in the empty part of UV2 so we break to the next column
|
|
|
|
|
|
|
|
for tris in tris_in_step_quad:
|
|
|
|
var offset_tris: int = (tris_in_step_quad * step_quad) + tris
|
|
|
|
var triangle := PackedVector2Array()
|
|
|
|
triangle.append(uv2[offset_tris * 3])
|
|
|
|
triangle.append(uv2[offset_tris * 3 + 1])
|
|
|
|
triangle.append(uv2[offset_tris * 3 + 2])
|
|
|
|
var p := Vector3(uv_coordinate.x, uv_coordinate.y, 0.0)
|
|
|
|
var a := Vector3(uv2[offset_tris * 3].x, uv2[offset_tris * 3].y, 0.0)
|
|
|
|
var b := Vector3(uv2[offset_tris * 3 + 1].x, uv2[offset_tris * 3 + 1].y, 0.0)
|
|
|
|
var c := Vector3(uv2[offset_tris * 3 + 2].x, uv2[offset_tris * 3 + 2].y, 0.0)
|
|
|
|
baryatric_coords = cart2bary(p, a, b, c)
|
|
|
|
|
|
|
|
if point_in_bariatric(baryatric_coords):
|
|
|
|
correct_triangle = [offset_tris * 3, offset_tris * 3 + 1, offset_tris * 3 + 2]
|
|
|
|
break # we have the correct triangle so we break out of loop
|
|
|
|
|
|
|
|
if correct_triangle:
|
|
|
|
var vert0: Vector3 = world_verts[correct_triangle[0]]
|
|
|
|
var vert1: Vector3 = world_verts[correct_triangle[1]]
|
|
|
|
var vert2: Vector3 = world_verts[correct_triangle[2]]
|
|
|
|
|
|
|
|
var real_pos := bary2cart(vert0, vert1, vert2, baryatric_coords)
|
|
|
|
var real_pos_up := real_pos + Vector3.UP * raycast_dist
|
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
var ray_params_up := PhysicsRayQueryParameters3D.create(real_pos, real_pos_up, raycast_layers)
|
2023-10-05 18:02:23 +00:00
|
|
|
var result_up = space_state.intersect_ray(ray_params_up)
|
|
|
|
|
2024-01-26 20:00:32 +00:00
|
|
|
var ray_params_down := PhysicsRayQueryParameters3D.create(real_pos_up, real_pos, raycast_layers)
|
2023-10-05 18:02:23 +00:00
|
|
|
var result_down = space_state.intersect_ray(ray_params_down)
|
|
|
|
|
|
|
|
var up_hit_frontface := false
|
|
|
|
if result_up:
|
|
|
|
if result_up.normal.y < 0:
|
|
|
|
true
|
|
|
|
|
|
|
|
if result_up or result_down:
|
|
|
|
if not up_hit_frontface and result_down:
|
|
|
|
image.set_pixel(x, y, Color(1.0, 1.0, 1.0))
|
|
|
|
return image
|
|
|
|
|
|
|
|
|
|
|
|
# Adds offset margins so filters will correctly extend across UV edges
|
|
|
|
static func add_margins(image : Image, resolution : int, margin : int) -> Image:
|
|
|
|
var with_margins_size := resolution + 2 * margin
|
|
|
|
|
|
|
|
var image_with_margins := Image.create(with_margins_size, with_margins_size, true, Image.FORMAT_RGB8)
|
|
|
|
image_with_margins.blend_rect(image, Rect2i(0, resolution - margin, resolution, margin), Vector2i(margin + margin, 0))
|
|
|
|
image_with_margins.blend_rect(image, Rect2i(0, 0, resolution, resolution), Vector2i(margin, margin))
|
|
|
|
image_with_margins.blend_rect(image, Rect2i(0, 0, resolution, margin), Vector2i(0, resolution + margin))
|
|
|
|
|
|
|
|
return image_with_margins
|