From: Zachary Vance Date: Mon, 1 Jul 2024 15:00:10 +0000 (-0400) Subject: make an actual geodesic dome X-Git-Url: https://git.za3k.com/?a=commitdiff_plain;h=d8ea3b96418402a899d72a61d95db7313b7bb87b;p=the_dome.git make an actual geodesic dome --- diff --git a/geodesic.avi b/geodesic.avi new file mode 100644 index 0000000..565ce97 Binary files /dev/null and b/geodesic.avi differ diff --git a/geodesic_dome.gd b/geodesic_dome.gd index b6c3ffa..9e09b85 100644 --- a/geodesic_dome.gd +++ b/geodesic_dome.gd @@ -1,23 +1,80 @@ extends Node3D @export var vertex_scene: PackedScene +@export var edge_scene: PackedScene +@export var face_scene: PackedScene -func random_position(): - return Vector3( - randf_range(-2,2), - randf_range(-2,2), - randf_range(-2,2) - ) +var VERTICES : Array[Vector3] = [ + Vector3(0, 1, 0), + Vector3(0, -1, 0), + Vector3(cos(deg_to_rad(36*0)), 1/sqrt(5), sin(deg_to_rad(36*0))).normalized(), + Vector3(cos(deg_to_rad(36*1)), -1/sqrt(5), sin(deg_to_rad(36*1))).normalized(), + Vector3(cos(deg_to_rad(36*2)), 1/sqrt(5), sin(deg_to_rad(36*2))).normalized(), + Vector3(cos(deg_to_rad(36*3)), -1/sqrt(5), sin(deg_to_rad(36*3))).normalized(), + Vector3(cos(deg_to_rad(36*4)), 1/sqrt(5), sin(deg_to_rad(36*4))).normalized(), + Vector3(cos(deg_to_rad(36*5)), -1/sqrt(5), sin(deg_to_rad(36*5))).normalized(), + Vector3(cos(deg_to_rad(36*6)), 1/sqrt(5), sin(deg_to_rad(36*6))).normalized(), + Vector3(cos(deg_to_rad(36*7)), -1/sqrt(5), sin(deg_to_rad(36*7))).normalized(), + Vector3(cos(deg_to_rad(36*8)), 1/sqrt(5), sin(deg_to_rad(36*8))).normalized(), + Vector3(cos(deg_to_rad(36*9)), -1/sqrt(5), sin(deg_to_rad(36*9))).normalized(), +] +@export var level = 1 # Detail level -func add_vertex(p : Vector3): - var vertex = vertex_scene.instantiate() - vertex.position = p +func is_edge(v1 : Vector3, v2 : Vector3): + return (VERTICES.find(v1) < VERTICES.find(v2) and + (v1-v2).length() < 1.3) + +func add_vertex(v1 : Vector3): + var vertex : IsoVertex = vertex_scene.instantiate() + vertex.position = v1 add_child(vertex) -# Called when the node enters the scene tree for the first time. +func add_edge(v1 : Vector3, v2: Vector3, level : int): + if level == 1: + var edge : DomeEdge = edge_scene.instantiate() + edge.v1 = v1 + edge.v2 = v2 + add_child(edge) + elif level > 1: + var v12 = sphere_midpoint(v1, v2) + add_edge(v1, v12, level-1) + add_edge(v12, v2, level-1) + +func sphere_midpoint(v1 : Vector3, v2 : Vector3): + return ((v1 + v2) / 2).normalized() + +func add_face(v1 : Vector3, v2: Vector3, v3: Vector3, level : int): + # Precondition: EXTERIOR edges are already drawn + if level == 1: + var face : GlassTriangle = face_scene.instantiate() + face.v1 = v1 + face.v2 = v2 + face.v3 = v3 + add_child(face) + elif level > 1: + var v12 = sphere_midpoint(v1, v2) + var v13 = sphere_midpoint(v1, v3) + var v23 = sphere_midpoint(v2, v3) + add_vertex(v12) + add_vertex(v13) + add_vertex(v23) + add_edge(v12, v23, level-1) + add_edge(v13, v23, level-1) + add_edge(v12, v13, level-1) + add_face(v1, v12, v13, level-1) + add_face(v2, v12, v23, level-1) + add_face(v3, v13, v23, level-1) + add_face(v12, v13, v23, level-1) + func _ready(): - for i in range(11): - add_vertex(random_position()) + for v1 in VERTICES: + add_vertex(v1) + for v2 in VERTICES: + if is_edge(v1, v2): + add_edge(v1, v2, level) + for v3 in VERTICES: + if is_edge(v1, v3) and is_edge(v2, v3): + add_face(v1, v2, v3, level) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): diff --git a/geodesic_dome.tscn b/geodesic_dome.tscn index 56f1092..4ee329b 100644 --- a/geodesic_dome.tscn +++ b/geodesic_dome.tscn @@ -1,7 +1,9 @@ -[gd_scene load_steps=4 format=3 uid="uid://cr06eruxv1iyp"] +[gd_scene load_steps=6 format=3 uid="uid://cr06eruxv1iyp"] [ext_resource type="Script" path="res://geodesic_dome.gd" id="1_ewsyw"] [ext_resource type="PackedScene" uid="uid://bn7wa6in76pce" path="res://ico_vertex.tscn" id="2_loxxg"] +[ext_resource type="PackedScene" uid="uid://d11qr1jxoxt8b" path="res://geodesic_dome_edge.tscn" id="3_o0t1j"] +[ext_resource type="PackedScene" uid="uid://dnfk0fawcv6pb" path="res://glass_triangle.tscn" id="4_t0bv2"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dw2k7"] transparency = 1 @@ -11,11 +13,12 @@ albedo_color = Color(1, 1, 1, 0.254902) [node name="GeodesicDome" type="Node3D"] script = ExtResource("1_ewsyw") vertex_scene = ExtResource("2_loxxg") +edge_scene = ExtResource("3_o0t1j") +face_scene = ExtResource("4_t0bv2") [node name="UnitSphere" type="CSGSphere3D" parent="."] +visible = false radius = 0.9 +radial_segments = 48 +rings = 24 material = SubResource("StandardMaterial3D_dw2k7") - -[node name="TopVertex" parent="." instance=ExtResource("2_loxxg")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) -fixed = true diff --git a/geodesic_dome_edge.gd b/geodesic_dome_edge.gd new file mode 100644 index 0000000..48ac9d0 --- /dev/null +++ b/geodesic_dome_edge.gd @@ -0,0 +1,23 @@ +class_name DomeEdge extends StaticBody3D + +@export var v1 : Vector3 +@export var v2 : Vector3 + +# Called when the node enters the scene tree for the first time. +func _ready(): + var length = (v2-v1).length() + var center = (v1 + v2) / 2 + var direction = (v2-v1).normalized() + + position = center + #rotation = direction + var cyclinder_mesh : CylinderMesh = $MeshInstance3D.mesh + cyclinder_mesh.height = length + look_at(v2) + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + pass + #get_tree().current_scene.draw_line(v1, v2) diff --git a/geodesic_dome_edge.tscn b/geodesic_dome_edge.tscn new file mode 100644 index 0000000..8ffec9b --- /dev/null +++ b/geodesic_dome_edge.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=4 format=3 uid="uid://d11qr1jxoxt8b"] + +[ext_resource type="Script" path="res://geodesic_dome_edge.gd" id="1_m4hun"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qgvan"] +albedo_color = Color(0.205117, 0.205117, 0.205117, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_v76vy"] +material = SubResource("StandardMaterial3D_qgvan") +top_radius = 0.01 +bottom_radius = 0.01 + +[node name="GeodesicDomeEdge" type="StaticBody3D"] +script = ExtResource("1_m4hun") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0) +mesh = SubResource("CylinderMesh_v76vy") diff --git a/glass_triangle.gd b/glass_triangle.gd new file mode 100644 index 0000000..1e9311f --- /dev/null +++ b/glass_triangle.gd @@ -0,0 +1,45 @@ +class_name GlassTriangle extends StaticBody3D + +const thickness = 0.05 +@export var v1 : Vector3 +@export var v2 : Vector3 +@export var v3 : Vector3 +var v1_inner +var v2_inner +var v3_inner +@export var material : Material + +func is_clockwise(): + var center = (v1 + v2 + v3) / 3 + return v1.signed_angle_to(v2, center) < 0 + +func _ready(): + # Re-order vertices are in clockwise order + if not is_clockwise(): + var temp = v2 + v2 = v3 + v3 = temp + v1_inner = v1 * (1-thickness) + v2_inner = v2 * (1-thickness) + v3_inner = v3 * (1-thickness) + update_mesh() + +func _process(delta): + pass + +func update_mesh(): + var vertices = [v1, v2, v3, v1_inner, v2_inner, v3_inner] + + var st = SurfaceTool.new() + st.begin(Mesh.PRIMITIVE_TRIANGLES) + st.set_color(Color(1, 1, 1)) + st.set_uv(Vector2(0, 0)) + st.set_material(material) + for vertex in vertices: + #st.add_vertex(Vector3(0, 0, 0)) + st.add_vertex(vertex) + var am = st.commit() + $VisibleShape.mesh = am + + var cps : ConvexPolygonShape3D = $CollisionShape.shape + cps.points = vertices diff --git a/glass_triangle.tscn b/glass_triangle.tscn new file mode 100644 index 0000000..bbe679d --- /dev/null +++ b/glass_triangle.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=5 format=3 uid="uid://dnfk0fawcv6pb"] + +[ext_resource type="Script" path="res://glass_triangle.gd" id="1_w50by"] +[ext_resource type="Shader" path="res://pbr_glass.gdshader" id="2_hi517"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_kvcah"] +render_priority = 0 +shader = ExtResource("2_hi517") +shader_parameter/albedo = Color(1, 1, 1, 0.156863) +shader_parameter/roughness = 0.15 +shader_parameter/normal_strength = 1.0 +shader_parameter/edge_color = Color(0, 0, 0, 1) + +[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_nt2r6"] +points = PackedVector3Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +[node name="GlassTriangle" type="StaticBody3D"] +script = ExtResource("1_w50by") +material = SubResource("ShaderMaterial_kvcah") + +[node name="VisibleShape" type="MeshInstance3D" parent="."] + +[node name="CollisionShape" type="CollisionShape3D" parent="."] +shape = SubResource("ConvexPolygonShape3D_nt2r6") diff --git a/ico_vertex.gd b/ico_vertex.gd index 9406e98..6773381 100644 --- a/ico_vertex.gd +++ b/ico_vertex.gd @@ -1,34 +1,9 @@ class_name IsoVertex extends RigidBody3D -@export var fixed : bool = false - # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): - get_tree().call_group("vertex", "maybe_draw_line", self) - -func maybe_draw_line(other : IsoVertex): - if self == other: return - var v1 := self.position - var v2 := other.position - var midpoint = (v1 + v2) / 2 - if midpoint.length() > 0.75: # If it doesn't pass through the 'middle' - get_tree().current_scene.draw_line(v1, v2) - -func push_away_from(other : IsoVertex, delta : float): - if self == other: return - if fixed: return - var displacement = self.position - other.position - var forceDirection = displacement.normalized() - var forceStrength = 10 / displacement.length_squared() # Some function of - apply_force(forceDirection * forceStrength * delta) - -func _physics_process(delta): - # Step 1, get a list of all other vertices - # Step 2, apply force to each - get_tree().call_group("vertex", "push_away_from", self, delta) - # Step 3, normalize current position - position = position.normalized() + pass diff --git a/ico_vertex.tscn b/ico_vertex.tscn index 56455d4..d035dd3 100644 --- a/ico_vertex.tscn +++ b/ico_vertex.tscn @@ -12,5 +12,5 @@ gravity_scale = 0.0 script = ExtResource("1_31hj6") [node name="Dot" type="CSGSphere3D" parent="."] -radius = 0.05 +radius = 0.01 material = SubResource("StandardMaterial3D_2qrn4") diff --git a/pbr_glass.gdshader b/pbr_glass.gdshader new file mode 100644 index 0000000..e756af2 --- /dev/null +++ b/pbr_glass.gdshader @@ -0,0 +1,56 @@ +shader_type spatial; + +render_mode diffuse_burley, specular_schlick_ggx, blend_mix; + +group_uniforms albedo; +uniform vec4 albedo : source_color = vec4(1.0, 1.0, 1.0, 0.0); +uniform sampler2D albedo_texture : source_color, hint_default_white; + +group_uniforms roughness; +uniform float roughness : hint_range(0.0, 1.0) = 0.15; +uniform sampler2D roughness_texture : hint_roughness_r; + +group_uniforms normal; +uniform float normal_strength : hint_range(-16.0, 16.0) = 1.0; +uniform sampler2D normal_map : hint_normal; + +group_uniforms misc; +uniform vec4 edge_color : source_color = vec4(0.0, 0.0, 0.0, 1.0); + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; +} + +void fragment() { + // calculate fresnel values + float VdotN = dot(VIEW, NORMAL); + float fresnel = clamp(SchlickFresnel(VdotN), 0.0, 1.0); + + // sample and mix textures + vec4 _albedo = texture(albedo_texture, UV) * albedo; + float _roughness = texture(roughness_texture, UV).r * roughness; + + // apply glass look + float a = mix(0.001, 1.0, _albedo.a); + ALPHA = mix(fresnel * edge_color.a, 1.0, a); + ALBEDO = mix(edge_color.rgb * edge_color.a, _albedo.rgb, a); + + ROUGHNESS = _roughness; + NORMAL_MAP = texture(normal_map, UV).xyz; + NORMAL_MAP_DEPTH = normal_strength; + + // function to compensate specular for alpha blend + // 0.5 * ALPHA^-0.5 + SPECULAR = 0.5 * inversesqrt(ALPHA); +} + +void vertex() { + // Called for every vertex the material is visible on. +} + +//void light() { + // Called for every pixel for every light affecting the material. + // Uncomment to replace the default light processing function with this one. +//} diff --git a/project.godot b/project.godot index 858ed5e..d426ae2 100644 --- a/project.godot +++ b/project.godot @@ -18,3 +18,29 @@ config/icon="res://icon.svg" [autoload] DrawLine3d="*res://DrawLine3D.gd" + +[display] + +window/size/viewport_width=1080 +window/size/viewport_height=720 + +[editor] + +movie_writer/movie_file="/home/zachary/the_dome/geodesic.avi" + +[input] + +quit={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"echo":false,"script":null) +] +} +restart={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"echo":false,"script":null) +] +} + +[physics] + +3d/default_gravity=0.0 diff --git a/world.gd b/world.gd index 8183573..7524a02 100644 --- a/world.gd +++ b/world.gd @@ -3,7 +3,7 @@ extends Node3D var LineDrawer = preload("res://DrawLine3D.gd").new() func draw_line(v1 : Vector3, v2 : Vector3): - LineDrawer.DrawLine(v1, v2, Color.BROWN, 0.1) + LineDrawer.DrawLine(v1, v2, Color.BROWN, 1/60) # Called when the node enters the scene tree for the first time. func _ready(): @@ -11,4 +11,8 @@ func _ready(): # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): - pass + $CameraPivot.position += Vector3( + Input.get_axis("ui_left", "ui_right"), + 0, 0) * delta + if Input.is_action_pressed("quit"): + get_tree().quit() diff --git a/world.tscn b/world.tscn index 645362c..56f0588 100644 --- a/world.tscn +++ b/world.tscn @@ -1,8 +1,18 @@ -[gd_scene load_steps=3 format=3 uid="uid://cotgytv6xac3l"] +[gd_scene load_steps=6 format=3 uid="uid://cotgytv6xac3l"] [ext_resource type="PackedScene" uid="uid://cr06eruxv1iyp" path="res://geodesic_dome.tscn" id="1_j3sin"] [ext_resource type="Script" path="res://world.gd" id="1_lxwr8"] +[sub_resource type="BoxShape3D" id="BoxShape3D_njt1i"] +size = Vector3(10, 1, 10) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tajc4"] +albedo_color = Color(0.100215, 0.230141, 0.0754749, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_6hk8v"] +material = SubResource("StandardMaterial3D_tajc4") +size = Vector3(10, 1, 10) + [node name="World" type="Node3D"] script = ExtResource("1_lxwr8") @@ -10,8 +20,20 @@ script = ExtResource("1_lxwr8") transform = Transform3D(1, 0, 0, 0, 0.846797, 0.531916, 0, -0.531916, 0.846797, 0.0169442, 1.0738, 1.64421) [node name="Camera3D" type="Camera3D" parent="CameraPivot"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0485562, 0.137679) [node name="GeodesicDome" parent="." instance=ExtResource("1_j3sin")] +level = 3 [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] -transform = Transform3D(1, 0, 0, 0, -0.258819, 0.965926, 0, -0.965926, -0.258819, 0, 2.14709, 3) +transform = Transform3D(1, 0, 0, 0, 0.560234, 0.828334, 0, -0.828334, 0.560234, 0, 4.51738, 2.88875) + +[node name="Ground" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] +shape = SubResource("BoxShape3D_njt1i") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +mesh = SubResource("BoxMesh_6hk8v")