Created
May 7, 2020 23:10
-
-
Save slapin/9ab469a9b5482020fcf52ac0f97d6c31 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Spatial | |
class GraphicsElement extends MeshInstance: | |
var mi: MeshInstance | |
var work_mesh: ArrayMesh | |
var vertices: = PoolVector3Array() | |
var indices: = PoolIntArray() | |
var uvdata: = PoolVector2Array() | |
var debug : ImmediateGeometry | |
func add_triangle(points:Array, uvs: Array): | |
var cur_index: int = indices.size() | |
for p in range(points.size()): | |
# print(p) | |
vertices.push_back(points[p]) | |
uvdata.push_back(uvs[p]) | |
indices.push_back(cur_index) | |
cur_index += 1 | |
func add_quad(points:Array, uvs: Array): | |
var p1 = [points[0], points[1], points[2]] | |
var u1 = [uvs[0], uvs[1], uvs[2]] | |
var p2 = [points[0], points[2], points[3]] | |
var u2 = [uvs[0], uvs[2], uvs[3]] | |
add_triangle(p1, u1) | |
add_triangle(p2, u2) | |
func commit(material: Material): | |
var id = work_mesh.get_surface_count() | |
var array = [] | |
array.resize(ArrayMesh.ARRAY_MAX) | |
array[ArrayMesh.ARRAY_VERTEX] = vertices | |
array[ArrayMesh.ARRAY_TEX_UV] = uvdata | |
array[ArrayMesh.ARRAY_INDEX] = indices | |
work_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, array) | |
work_mesh.surface_set_material(id, material) | |
hide() | |
mesh = work_mesh | |
show() | |
func clear(): | |
work_mesh = ArrayMesh.new() | |
vertices = PoolVector3Array() | |
indices = PoolIntArray() | |
uvdata = PoolVector2Array() | |
func _init(): | |
work_mesh = ArrayMesh.new() | |
debug = ImmediateGeometry.new() | |
add_child(debug) | |
var debug_mat = SpatialMaterial.new() | |
debug_mat.flags_no_depth_test = true | |
debug_mat.flags_unshaded = true | |
debug_mat.vertex_color_use_as_albedo = true | |
debug.material_override = debug_mat | |
class ExtrudeProfile extends GraphicsElement: | |
var profile: = PoolVector2Array() | |
func extrude(step: float, count: int): | |
var d = 0.0 | |
var x1: = profile[0].x | |
var x2: = profile[profile.size() - 1].x | |
for e in profile: | |
if e.x > x2: | |
x2 = e.x | |
if abs(x2 - x1) < 0.0001: | |
return | |
var xd = abs(x2 - x1) | |
for i in range(count): | |
for j in range(profile.size()): | |
if i < count - 1 && j < profile.size() - 1: | |
var p0 = profile[j] | |
var p1 = profile[j + 1] | |
var pt0 = Vector3(p0.x, p0.y, d) | |
var uv0 = Vector2((p0.x - x1)/ xd, 0) | |
var pt1 = Vector3(p0.x, p0.y, d + step) | |
var uv1 = Vector2((p0.x - x1)/ xd, 1) | |
var pt2 = Vector3(p1.x, p1.y, d + step) | |
var uv2 = Vector2((p1.x - x1)/ xd, 1) | |
var pt3 = Vector3(p1.x, p1.y, d) | |
var uv3 = Vector2((p1.x - x1)/ xd, 0) | |
add_quad([pt3, pt2, pt1, pt0], [uv3, uv2, uv1, uv0]) | |
d += step | |
class ExtrudeIntersection extends GraphicsElement: | |
var profile: = PoolVector2Array() | |
var lane_curves = [] | |
var lane_geometry = [] | |
var lane_basis = [] | |
var center: Vector3 | |
var polygon = [] | |
var rect: Rect2 = Rect2() | |
var grid = PoolIntArray() | |
var size_x: int = 0 | |
var size_y: int = 0 | |
var mc_triangles = [] | |
func mark_inflated(orig: Array, poly: Array): | |
var mark = [] | |
var c: = Curve2D.new() | |
for k in orig: | |
c.add_point(k) | |
for p in poly: | |
var closest = -1 | |
var closest_dst = INF | |
for r in range(orig.size()): | |
var op = orig[r] | |
var d = p.distance_to(op) | |
if d < closest_dst: | |
closest = r | |
closest_dst = d | |
assert(closest >= 0) | |
mark.push_back(closest) | |
return mark | |
func poly2topoly3(p: Array): | |
var ret = [] | |
for j in range(p.size()): | |
ret.push_back(Vector3(p[j].x, 0, p[j].y)) | |
return ret | |
func poly3topoly2(p: Array): | |
var ret = [] | |
for j in range(p.size()): | |
ret.push_back(Vector2(p[j].x, p[j].z)) | |
return ret | |
func recover_from_mark(p: Array, m: Array, poly: Array): | |
var ret = [] | |
for s in range(m.size()): | |
var h = p[m[s]].y | |
var v = poly[s] | |
v.y = h | |
ret.push_back(v) | |
return ret | |
func isect_angle(left, modp, right, offset) -> Vector3: | |
var dir1 = (left - modp).normalized() | |
var dir2 = (right - modp).normalized() | |
var up = Vector3(0, 1, 0) | |
var dir1b = dir1.cross(up) | |
var dir2b = dir2.cross(up) | |
var isect: Vector3 | |
if abs(dir1.dot(dir2) - 1.0) > 0.001: | |
var m1 = Vector2(modp.x + dir1b.x * offset, modp.z + dir1b.z * offset) | |
var m2 = Vector2(modp.x - dir2b.x * offset, modp.z - dir2b.z * offset) | |
var d1 = Vector2(dir1.x, dir1.z) | |
var d2 = Vector2(dir2.x, dir2.z) | |
var xisect = Geometry.line_intersects_line_2d(m1, d1, m2, d2) | |
assert(xisect != null) | |
isect = Vector3(xisect.x, modp.y, xisect.y) | |
else: | |
isect = modp + dir1b * offset | |
return isect | |
func create_lanes(points: PoolVector3Array, lanes: int, lx: float): | |
var modp = points[1] | |
var left = points[0] | |
var right = points[2] | |
var dir1 = (left - modp).normalized() | |
var dir2 = (right - modp).normalized() | |
var up = Vector3(0, 1, 0) | |
var dir1b = dir1.cross(up) | |
var dir2b = dir2.cross(up) | |
for k in range(lanes): | |
var offset = float(k) * lx | |
var moffset = offset + lx * 0.5 | |
var isect = isect_angle(left, modp, right, moffset) | |
var lane_curve = Curve3D.new() | |
lane_curve.add_point(left + dir1b * moffset) | |
lane_curve.add_point(isect) | |
var inh = -dir2 * lx * 0.3 + dir1 * lx * 0.4 | |
var outh = -dir1 * lx * 0.3 + dir2 * lx * 0.4 | |
var depth = lx * 0.5 | |
if !k in [lanes - 1]: | |
# inh = Vector3() | |
# outh = Vector3() | |
depth = lx * 0.7 | |
inh = Vector3() | |
outh = Vector3() | |
lane_curve.set_point_in(1, inh) | |
lane_curve.set_point_out(1, outh) | |
lane_curve.add_point(right - dir2b * moffset) | |
lane_basis.push_back([left + dir1b * moffset, isect, right - dir2b * moffset]) | |
lane_curves.push_back(lane_curve) | |
var lane_data = lane_curve.tessellate(5, 4) | |
var lane_data_2d = poly3topoly2(lane_data) | |
var poly = Geometry.offset_polyline_2d(lane_data_2d, depth, 0, 2) | |
var pdata = Geometry.merge_polygons_2d(polygon, poly[0]) | |
polygon = pdata[0] | |
var mark = mark_inflated(lane_data_2d, poly[0]) | |
var poly3d = poly2topoly3(poly[0]) | |
poly3d = recover_from_mark(lane_data, mark, poly3d) | |
lane_geometry.push_back(poly3d) | |
func sort_neighbors(p1, p2): | |
var px1 = (p1 - center) | |
var px2 = (p2 - center) | |
var pvx1 = Vector2(px1.x, px1.z) | |
var pvx2 = Vector2(px2.x, px2.z) | |
return pvx1.angle() < pvx2.angle() | |
var edges = [ | |
0x0, # 0000 Nothing intersects | |
0x9, # 0001 0 | |
0x3, # 0010 1 | |
0xA, # 0011 0 1 | |
0x6, # 0100 2 | |
0xF, # 0101 0 2 | |
0x5, # 0110 1 2 | |
0xC, # 0111 0 1 2 | |
0xC, # 1000 3 | |
0x5, # 1001 0 3 | |
0xF, # 1010 1 3 | |
0x6, # 1011 0 1 3 | |
0xA, # 1100 2 3 | |
0x3, # 1101 0 2 3 | |
0x9, # 1110 1 2 3 | |
0x0 # 1111 0 1 2 3 | |
] | |
var triangles = [ | |
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], | |
[7, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ], | |
[3, 2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], | |
[7, 2, 0, 7, 3, 2, -1, -1, -1, -1, -1, -1, -1], | |
[5, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], | |
[7, 1, 0, 3, 5, 4, -1, -1, -1, -1, -1, -1, -1], | |
[1, 4, 2, 1, 5, 4, -1, -1, -1, -1, -1, -1, -1], | |
[0, 7, 5, 0, 5, 4, 0, 4, 2, -1, -1, -1, -1], | |
[7, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], | |
[0, 5, 1, 0, 6, 5, -1, -1, -1, -1, -1, -1, -1], | |
[1, 3, 2, 7, 6, 5, -1, -1, -1, -1, -1, -1, -1], | |
[3, 6, 5, 3, 0, 6, 3, 2, 0, -1, -1, -1, -1], | |
[7, 6, 4, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1], | |
[3, 1, 0, 3, 0, 6, 3, 6, 4, -1, -1, -1, -1], | |
[2, 1, 7, 2, 7, 6, 2, 6, 4, -1, -1, -1, -1], | |
[6, 2, 0, 6, 4, 2, -1, -1, -1, -1, -1, -1, -1], | |
[1, 0, 7, 1, 7, 5, 1, 5, 4, 1, 4, 3, -1], | |
[1, 3, 2, 1, 5, 3, 1, 6, 5, 1, 7, 6, -1] | |
] | |
func interpolate(p0, p1, v0, v1): | |
if abs(v0) < 0.001: | |
return p0 | |
if abs(v1) < 0.001: | |
return p1 | |
if abs(v1 - v0) < 0.001: | |
return p0 | |
var mu = -v0 / (v1 - v0) | |
return p0 + (p1 - p0) * mu | |
func ms_init(): | |
for p in polygon: | |
rect = rect.expand(p) | |
size_x = int(rect.size.x + 2) | |
size_y = int(rect.size.y + 2) | |
var dist = [] | |
grid.resize(size_x * size_y) | |
dist.resize(size_x * size_y) | |
for i in range(size_y): | |
for j in range(size_x): | |
var data = 0 | |
var verts = [Vector2(j, i), Vector2(j + 1, i), Vector2(j + 1, i + 1), Vector2(j, i + 1)] | |
var distances = [INF, INF, INF, INF] | |
for p in range(4): | |
var v = verts[p] + Vector2(-1, -1) + rect.position | |
var min_dist | |
var pip = Geometry.is_point_in_polygon(v, polygon) | |
if pip: | |
data |= (1 << p) | |
for h in range(polygon.size()): | |
var p1 = polygon[h] | |
var p2 = polygon[(h + 1) % polygon.size()] | |
var sp = Geometry.get_closest_point_to_segment_2d(v, p1, p2) | |
var d = v.distance_to(sp) | |
if distances[p] > d: | |
if pip: | |
distances[p] = d | |
else: | |
distances[p] = -d | |
grid[i * size_x + j] = data | |
dist[i * size_x + j] = distances | |
var intersection_points = PoolVector2Array() | |
intersection_points.resize(8) | |
var pv = verts.duplicate() | |
for p in range(verts.size()): | |
pv[p] += Vector2(-1, -1) + rect.position | |
intersection_points[p * 2] = pv[p] | |
var edge: int = edges[data] | |
if edge & 1: | |
intersection_points[1] = interpolate(pv[0], pv[1], distances[0], distances[1]) | |
if edge & 2: | |
intersection_points[3] = interpolate(pv[1], pv[2], distances[1], distances[2]) | |
if edge & 4: | |
intersection_points[5] = interpolate(pv[2], pv[3], distances[2], distances[3]) | |
if edge & 8: | |
intersection_points[7] = interpolate(pv[3], pv[0], distances[3], distances[0]) | |
for t in range(0, triangles[data].size(), 3): | |
if triangles[data][t] < 0: | |
break | |
var p0 = intersection_points[triangles[data][t]] | |
var p1 = intersection_points[triangles[data][t + 1]] | |
var p2 = intersection_points[triangles[data][t + 2]] | |
mc_triangles.push_back([p0, p1, p2]) | |
print(grid) | |
print(dist) | |
print(mc_triangles) | |
func extrude(step: float, var center: Vector3, neighbors: PoolVector3Array, lanes: int): | |
var lx = 3.0 | |
self.center = center | |
var n = Array(neighbors) | |
assert(neighbors.size() > 2) | |
n.sort_custom(self, "sort_neighbors") | |
for p in range(n.size()): | |
var p1 = n[p] | |
var p2 = n[(p + 1) % n.size()] | |
var points = [p1, center, p2] | |
create_lanes(PoolVector3Array(points), lanes, lx) | |
var modp = points[1] | |
var left = points[0] | |
var right = points[2] | |
# var lane_curves = [] | |
# var dir1 = (left - modp).normalized() | |
# var dir2 = (right - modp).normalized() | |
# var lane_geometry = [] | |
# var lane_basis = [] | |
# var up = Vector3(0, 1, 0) | |
# var dir1b = dir1.cross(up) | |
# var dir2b = dir2.cross(up) | |
# for k in range(lanes): | |
# var offset = float(k) * lx | |
# var moffset = offset + lx * 0.5 | |
# var isect = isect_angle(left, modp, right, moffset) | |
# var lane_curve = Curve3D.new() | |
# lane_curve.add_point(left + dir1b * moffset) | |
# lane_curve.add_point(isect) | |
# var inh = -dir2 * lx * 0.3 + dir1 * lx * 0.4 | |
# var outh = -dir1 * lx * 0.3 + dir2 * lx * 0.4 | |
# var depth = lx * 0.5 | |
# if !k in [lanes - 1]: | |
## inh = Vector3() | |
## outh = Vector3() | |
# depth = lx * 0.7 | |
# inh = Vector3() | |
# outh = Vector3() | |
# lane_curve.set_point_in(1, inh) | |
# lane_curve.set_point_out(1, outh) | |
# lane_curve.add_point(right - dir2b * moffset) | |
# lane_basis.push_back([left + dir1b * moffset, isect, right - dir2b * moffset]) | |
# lane_curves.push_back(lane_curve) | |
# var lane_data = lane_curve.tessellate(5, 4) | |
# var lane_data_2d = poly3topoly2(lane_data) | |
# var poly = Geometry.offset_polyline_2d(lane_data_2d, depth, 0, 2) | |
# var mark = mark_inflated(lane_data_2d, poly[0]) | |
# var poly3d = poly2topoly3(poly[0]) | |
# poly3d = recover_from_mark(lane_data, mark, poly3d) | |
# lane_geometry.push_back(poly3d) | |
debug.begin(Mesh.PRIMITIVE_LINES) | |
debug.set_color(Color(0, 1, 0, 1)) | |
debug.add_vertex(modp) | |
debug.add_vertex(left) | |
debug.add_vertex(modp) | |
debug.add_vertex(right) | |
debug.end() | |
ms_init() | |
var p3 = poly2topoly3(polygon) | |
debug.begin(Mesh.PRIMITIVE_LINES) | |
debug.set_color(Color(0, 0, 1, 1)) | |
for k in lane_curves: | |
var pts = k.tessellate(5, 4) | |
for r in range(pts.size() - 1): | |
var p1 = pts[r] | |
var p2 = pts[r + 1] | |
debug.add_vertex(p1) | |
debug.add_vertex(p2) | |
debug.end() | |
debug.begin(Mesh.PRIMITIVE_LINES) | |
debug.set_color(Color(1, 1, 0, 1)) | |
for k in lane_geometry: | |
for r in range(k.size()): | |
var p1 = k[r] | |
var p2 = k[(r + 1) % k.size()] | |
debug.add_vertex(p1) | |
debug.add_vertex(p2) | |
debug.end() | |
var poly3 = poly2topoly3(polygon) | |
debug.begin(Mesh.PRIMITIVE_LINES) | |
debug.set_color(Color(1, 1, 1, 1)) | |
for r in range(poly3.size()): | |
var p1 = poly3[r] | |
var p2 = poly3[(r + 1) % poly3.size()] | |
debug.add_vertex(p1) | |
debug.add_vertex(p2) | |
debug.end() | |
debug.begin(Mesh.PRIMITIVE_LINES) | |
debug.set_color(Color(1, 0.6, 0.6, 1)) | |
for t in mc_triangles: | |
var tx = poly2topoly3(t) | |
print(t) | |
debug.add_vertex(tx[0]) | |
debug.add_vertex(tx[1]) | |
debug.add_vertex(tx[1]) | |
debug.add_vertex(tx[2]) | |
debug.add_vertex(tx[2]) | |
debug.add_vertex(tx[0]) | |
debug.end() | |
func _ready(): | |
var mi1: = ExtrudeIntersection.new() | |
mi1.profile = PoolVector2Array([Vector2(-3.5, 0), Vector2(-3, 0.1), Vector2(0, 0), Vector2(3, 0.1)]) | |
var pathpt = PoolVector3Array([Vector3(-23, 0, 25.5), Vector3(-23, 0, -25.5), Vector3(13, 0, 25.5)]) | |
mi1.extrude(0.1, Vector3(0, 0, 0), pathpt, 6) | |
mi1.commit(SpatialMaterial.new()) | |
add_child(mi1) | |
# var mi2: = ExtrudeIntersection.new() | |
# mi2.profile = PoolVector2Array([Vector2(-3.5, 0), Vector2(-3, 0.1), Vector2(0, 0), Vector2(3, 0.1)]) | |
# var pathpt2 = PoolVector3Array([Vector3(10 + 3, 0, -6), Vector3(10 + 3, 0, 6)]) | |
# mi2.extrude(0.1, Vector3(10 + 0, 0, 0), pathpt, 1) | |
# mi2.commit(SpatialMaterial.new()) | |
# add_child(mi2) | |
var state = 0 | |
func _process(delta): | |
match(state): | |
0: | |
# get_tree().get_root().debug_draw = Viewport.DEBUG_DRAW_OVERDRAW | |
state = 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment