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):
-[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
[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
--- /dev/null
+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)
--- /dev/null
+[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")
--- /dev/null
+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
--- /dev/null
+[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")
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
script = ExtResource("1_31hj6")
[node name="Dot" type="CSGSphere3D" parent="."]
-radius = 0.05
+radius = 0.01
material = SubResource("StandardMaterial3D_2qrn4")
--- /dev/null
+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.
+//}
[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
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():
# 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()
-[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")
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")