make miniature view separate

This commit is contained in:
Nitwel 2024-04-05 19:29:18 +02:00
parent 9cb0c63fa0
commit c0dccc8401
17 changed files with 408 additions and 203 deletions

View File

@ -5,6 +5,8 @@ const Entity = preload ("../entity.gd")
@onready var label: Label3D = $Label
@onready var collision_shape = $CollisionShape3D
var sensor_data = {}
# Called when the node enters the scene tree for the first time.
func _ready():
super()
@ -17,6 +19,9 @@ func _ready():
)
func set_text(stateInfo):
if stateInfo == null:
return
var text = stateInfo["state"]
if stateInfo["attributes"]["friendly_name"] != null:
@ -25,6 +30,9 @@ func set_text(stateInfo):
if stateInfo["attributes"].has("unit_of_measurement")&&stateInfo["attributes"]["unit_of_measurement"] != null:
text += " " + stateInfo["attributes"]["unit_of_measurement"]
if stateInfo["attributes"].has("device_class"):
sensor_data[stateInfo["attributes"]["device_class"]] = stateInfo["state"]
label.text = text
var font = label.get_font()
@ -35,3 +43,9 @@ func set_text(stateInfo):
collision_shape.shape.size.x = size.x * label.pixel_size * 0.5
collision_shape.shape.size.y = size.y * label.pixel_size * 0.25
func get_sensor_data(type: String):
if sensor_data.has(type) == false:
return null
return sensor_data[type]

View File

@ -6,13 +6,10 @@ const RoomType = preload ("./room/room.gd")
@onready var levels = $Levels
@onready var collision_shape = $Levels/CollisionShape3D
@onready var align_reference = $AlignReference
@onready var mini_view = $Miniature
var fixing_reference: bool = false
var editing_room: RoomType = null
var mini_view: bool = false:
set(value):
mini_view = value
update_mini_view()
func _ready():
Store.house.on_loaded.connect(func():
@ -198,44 +195,6 @@ func create_entity_in(entity_id: String, room_name: String):
return entity
func update_mini_view():
collision_shape.disabled = !mini_view
var tween = create_tween()
tween.set_parallel(true)
tween.set_trans(Tween.TRANS_CUBIC)
if mini_view:
var aabb = get_level_aabb(0)
aabb.position.y = -0.03
aabb.size.y = 0.06
var center = aabb.position + aabb.size / 2.0
collision_shape.global_position = center
collision_shape.shape.size = aabb.size
var camera = get_node("/root/Main/XROrigin3D/XRCamera3D")
var camera_position = camera.global_position
var camera_direction = -camera.global_transform.basis.z
camera_position.y *= 0.5
camera_direction.y = 0.0
var target_position = camera_position + camera_direction.normalized() * 0.2
var new_position = target_position - center * 0.1
tween.tween_property(levels, "global_position", new_position, 0.5)
tween.tween_property(levels, "scale", Vector3(0.1, 0.1, 0.1), 0.5)
for room in get_rooms(0):
room.state_machine.change_to("Mini")
else:
tween.tween_property(levels, "global_position", Vector3(0, 0, 0), 0.5)
tween.tween_property(levels, "scale", Vector3(1.0, 1.0, 1.0), 0.5)
await tween.finished
for room in get_rooms(0):
room.state_machine.change_to("View")
func edit_reference():
fixing_reference = false
align_reference.visible = true

View File

@ -1,8 +1,9 @@
[gd_scene load_steps=5 format=3 uid="uid://cbemihbxkd4ll"]
[gd_scene load_steps=6 format=3 uid="uid://cbemihbxkd4ll"]
[ext_resource type="Script" path="res://content/system/house/house.gd" id="1_p8amj"]
[ext_resource type="Script" path="res://content/functions/movable.gd" id="2_w1auk"]
[ext_resource type="PackedScene" uid="uid://jls16btb8nko" path="res://content/system/house/align_reference.tscn" id="3_e1tcn"]
[ext_resource type="PackedScene" uid="uid://ds60i5n211hi3" path="res://content/system/house/mini/miniature.tscn" id="4_qjbly"]
[sub_resource type="BoxShape3D" id="BoxShape3D_x81up"]
@ -25,3 +26,5 @@ lock_rotation = true
[node name="AlignReference" parent="." instance=ExtResource("3_e1tcn")]
visible = false
disabled = true
[node name="Miniature" parent="." instance=ExtResource("4_qjbly")]

View File

@ -0,0 +1,3 @@
extends Node3D
const mini_wall_shader: ShaderMaterial = preload ("./mini_wall.tres")

View File

@ -0,0 +1,19 @@
[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://bcfcough6ucvc"]
[ext_resource type="Shader" path="res://content/system/house/mini/mini_wall_shader.gdshader" id="1_sbr3e"]
[sub_resource type="Gradient" id="Gradient_2jwis"]
interpolation_color_space = 2
offsets = PackedFloat32Array(0.00280112, 1)
colors = PackedColorArray(0, 0.558935, 0.886772, 1, 0.999396, 0, 0.058647, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_rrsal"]
gradient = SubResource("Gradient_2jwis")
[resource]
render_priority = 0
shader = ExtResource("1_sbr3e")
shader_parameter/data = PackedFloat32Array()
shader_parameter/data_size = 0
shader_parameter/min_max_data = null
shader_parameter/color_gradient = SubResource("GradientTexture1D_rrsal")

View File

@ -0,0 +1,39 @@
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_lambert, specular_schlick_ggx, unshaded;
uniform vec4 data[100];
uniform int data_size: hint_range(0, 100, 1);
uniform vec2 min_max_data;
uniform sampler2D color_gradient;
varying vec3 color;
void vertex() {
// Calculate Global Coordinates
vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
color = vec3(1.0, 1.0, 1.0);
vec2 distances[100];
float dist_sum = 0.0;
if(data_size > 0) {
for(int i = 0; i < data_size; i++) {
float delta = 1.0 / distance(data[i].xyz, world_position);
distances[i] = vec2(delta, data[i].w);
dist_sum += delta;
}
for(int i = 0; i < data_size; i++) {
float average = distances[i].x / dist_sum * distances[i].y;
color.xyz = texture(color_gradient, vec2(average, 0)).xyz;
}
}
}
void fragment() {
ALBEDO = vec3(color.xyz);
ALPHA = 0.3;
}

View File

@ -0,0 +1,84 @@
extends Node3D
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
const wall_material = preload ("./mini_wall.tres")
@onready var walls_mesh = $WallsMesh
@onready var floor_mesh = $FloorMesh
@onready var collision_shape = $CollisionShape3D
@onready var toggle_heatmap = $HeatmapButton
var enabled = true:
set(value):
enabled = value
update()
func _ready():
update()
if Store.house.is_loaded() == false:
await Store.house.on_loaded
var room = Store.house.rooms[0]
var corners = room.corners
var height = room.height
walls_mesh.mesh = ConstructRoomMesh.generate_wall_mesh_grid(corners, height)
floor_mesh.mesh = ConstructRoomMesh.generate_ceiling_mesh_grid(corners)
walls_mesh.material_override = wall_material
floor_mesh.material_override = wall_material
active = true
update_data(0.0)
toggle_heatmap.on_button_down.connect(func():
active=true
EventSystem.on_slow_tick.connect(update_data)
)
toggle_heatmap.on_button_up.connect(func():
wall_material.set_shader_parameter("data", [])
wall_material.set_shader_parameter("data_size", 0)
active=false
EventSystem.on_slow_tick.disconnect(update_data)
)
func update():
walls_mesh.visible = enabled
floor_mesh.visible = enabled
collision_shape.disabled = not enabled
const SensorEntity = preload ("res://content/entities/sensor/sensor.gd")
var active: bool = false
func update_data(delta: float) -> void:
var data_list = []
var min_max_data
for room in House.body.get_rooms(0):
for entity in room.get_node("Entities").get_children():
if entity is SensorEntity:
var sensor = entity as SensorEntity
var data = sensor.get_sensor_data("temperature")
if data == null:
continue
var sensor_pos = sensor.global_position
if min_max_data == null:
min_max_data = Vector2(float(data), float(data))
else:
min_max_data.x = min(min_max_data.x, float(data))
min_max_data.y = max(min_max_data.y, float(data))
data_list.append(Vector4(sensor_pos.x, sensor_pos.y, sensor_pos.z, float(data)))
for data in data_list:
data.w = (data.w - min_max_data.x) / (min_max_data.y - min_max_data.x)
wall_material.set_shader_parameter("data", data_list)
wall_material.set_shader_parameter("min_max_data", min_max_data)
wall_material.set_shader_parameter("data_size", data_list.size())

View File

@ -0,0 +1,24 @@
[gd_scene load_steps=5 format=3 uid="uid://ds60i5n211hi3"]
[ext_resource type="Script" path="res://content/system/house/mini/miniature.gd" id="1_b53yn"]
[ext_resource type="Script" path="res://content/functions/movable.gd" id="2_x7oed"]
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_tgdcf"]
[sub_resource type="BoxShape3D" id="BoxShape3D_bckw3"]
[node name="Miniature" type="StaticBody3D"]
script = ExtResource("1_b53yn")
[node name="WallsMesh" type="MeshInstance3D" parent="."]
[node name="FloorMesh" type="MeshInstance3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_bckw3")
[node name="Movable" type="Node" parent="."]
script = ExtResource("2_x7oed")
[node name="HeatmapButton" parent="." instance=ExtResource("3_tgdcf")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.25, 0.5, 0.48)
toggleable = true

View File

@ -1,5 +1,7 @@
extends Node3D
const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd")
@onready var wall_corners = $Ceiling/WallCorners
@onready var wall_edges = $Ceiling/WallEdges
@onready var wall_mesh: MeshInstance3D = $WallMesh
@ -55,75 +57,12 @@ func get_aabb():
return AABB(to_global(min_pos), to_global(max_pos) - to_global(min_pos))
static func generate_wall_mesh(room_store: Dictionary):
if room_store.corners.size() < 2:
return null
var corners = room_store.corners
var height = room_store.height
var st = SurfaceTool.new()
var wall_up = Vector3.UP * room_store.height
st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
for corner in room_store.corners:
var corner3D = Vector3(corner.x, 0, corner.y)
st.add_vertex(corner3D)
st.add_vertex(corner3D + wall_up)
var first_corner = Vector3(room_store.corners[0].x, 0, room_store.corners[0].y)
st.add_vertex(first_corner)
st.add_vertex(first_corner + wall_up)
st.index()
st.generate_normals()
st.generate_tangents()
var mesh = st.commit()
return mesh
return ConstructRoomMesh.generate_wall_mesh_grid(corners, height)
static func generate_ceiling_mesh(room_store: Dictionary):
var points: PackedVector2Array = PackedVector2Array()
var edges: PackedInt32Array = PackedInt32Array()
var triangles: PackedInt32Array
var corners = room_store.corners
if corners.size() < 3:
return null
for i in range(corners.size()):
var corner = corners[i]
points.append(Vector2(corner.x, corner.y))
edges.append(i)
edges.append((i + 1) % corners.size())
var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new()
cdt.init(true, true, 0.1)
cdt.insert_vertices(points)
cdt.insert_edges(edges)
cdt.erase_outer_triangles()
points = cdt.get_all_vertices()
triangles = cdt.get_all_triangles()
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
for i in range(points.size()):
st.add_vertex(Vector3(points[i].x, 0, points[i].y))
for i in range(triangles.size()):
st.add_index(triangles[i])
st.index()
st.generate_normals()
st.generate_tangents()
var mesh = st.commit()
return mesh
return ConstructRoomMesh.generate_ceiling_mesh_grid(corners)

View File

@ -1,9 +1,8 @@
[gd_scene load_steps=9 format=3 uid="uid://bswgmclohuqui"]
[gd_scene load_steps=8 format=3 uid="uid://bswgmclohuqui"]
[ext_resource type="Script" path="res://content/system/house/room/room.gd" id="1_fccq0"]
[ext_resource type="Script" path="res://content/functions/clickable.gd" id="1_ugebq"]
[ext_resource type="Script" path="res://lib/utils/state_machine/state_machine.gd" id="4_nbbo6"]
[ext_resource type="Script" path="res://content/system/house/room/states/mini.gd" id="6_g4qca"]
[ext_resource type="Script" path="res://content/system/house/room/states/view.gd" id="6_g066t"]
[ext_resource type="Script" path="res://content/system/house/room/states/edit.gd" id="7_ap14h"]
@ -57,7 +56,4 @@ script = ExtResource("6_g066t")
[node name="Edit" type="Node" parent="StateMachine"]
script = ExtResource("7_ap14h")
[node name="Mini" type="Node" parent="StateMachine"]
script = ExtResource("6_g4qca")
[node name="Entities" type="Node3D" parent="."]

View File

@ -1,41 +0,0 @@
extends RoomState
const RoomState = preload("./room_state.gd")
const walls_mini_material = preload("../walls_mini.tres")
const walls_material = preload("../walls.tres")
func _on_enter():
room.wall_mesh.visible = true
room.ceiling_mesh.visible = false
room.wall_mesh.material_override = walls_mini_material
room.room_ceiling.get_node("CollisionShape3D").disabled = true
room.room_floor.get_node("CollisionShape3D").disabled = true
for collision in room.wall_collisions.get_children():
collision.get_child(0).disabled = true
for corner in room.wall_corners.get_children():
corner.get_node("CollisionShape3D").disabled = true
for edge in room.wall_edges.get_children():
edge.get_node("CollisionShape3D").disabled = true
func _on_leave():
room.wall_mesh.visible = false
room.ceiling_mesh.visible = false
room.wall_mesh.material_override = walls_material
room.room_ceiling.get_node("CollisionShape3D").disabled = false
room.room_floor.get_node("CollisionShape3D").disabled = false
for collision in room.wall_collisions.get_children():
collision.get_child(0).disabled = false
for corner in room.wall_corners.get_children():
corner.get_node("CollisionShape3D").disabled = false
for edge in room.wall_edges.get_children():
edge.get_node("CollisionShape3D").disabled = false

View File

@ -29,9 +29,9 @@ func _on_enter():
floor_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape()
ceiling_shape.shape.backface_collision = true
var collisions = generate_collision()
var collision = CollisionShape3D.new()
collision.shape = room.wall_mesh.mesh.create_trimesh_shape()
for collision in collisions:
var static_body = StaticBody3D.new()
static_body.set_collision_layer_value(4, true)
static_body.set_collision_layer_value(5, true)
@ -46,33 +46,3 @@ func _on_leave():
for collision in room.wall_collisions.get_children():
collision.queue_free()
await collision.tree_exited
func generate_collision():
var room_store = Store.house.get_room(room.name)
var collision_shapes: Array[CollisionShape3D] = []
var corners = room_store.corners
for i in range(corners.size()):
var corner = Vector3(corners[i].x, 0, corners[i].y)
var next_corner_index = (i + 1) % corners.size()
var next_corner = Vector3(corners[next_corner_index].x, 0, corners[next_corner_index].y)
var shape = BoxShape3D.new()
shape.size = Vector3((next_corner - corner).length(), room_store.height, 0.04)
var transform = Transform3D()
var back_vector = (corner - next_corner).cross(Vector3.UP).normalized() * shape.size.z / 2
transform.basis = Basis((next_corner - corner).normalized(), Vector3.UP, back_vector.normalized())
transform.origin = corner + (next_corner - corner) / 2 + back_vector + Vector3.UP * shape.size.y / 2
var collision_shape = CollisionShape3D.new()
collision_shape.shape = shape
collision_shape.transform = transform
collision_shapes.append(collision_shape)
return collision_shapes

View File

@ -1,6 +0,0 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://dxyuncqxagt28"]
[resource]
transparency = 1
cull_mode = 2
albedo_color = Color(1, 1, 1, 0.47451)

View File

@ -32,6 +32,15 @@ func _enter_tree():
func load_devices():
if devices.size() == 0:
devices = await HomeApi.get_devices()
devices.sort_custom(func(a, b):
return a.values()[0]["name"].to_lower() < b.values()[0]["name"].to_lower()
)
for device in devices:
device.values()[0]["entities"].sort_custom(func(a, b):
return a.to_lower() < b.to_lower()
)
render()
HomeApi.on_disconnect.connect(func():

View File

@ -7,6 +7,5 @@ func _ready():
background.visible = false
mini_view.on_button_down.connect(func():
House.body.mini_view = !House.body.mini_view
House.body.mini_view.enabled=!House.body.mini_view.enabled
)

View File

@ -0,0 +1,194 @@
static func generate_wall_mesh(corners, height):
if corners.size() < 3:
return null
var st = SurfaceTool.new()
var wall_up = Vector3.UP * height
st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
for corner in corners:
var corner3D = Vector3(corner.x, 0, corner.y)
st.add_vertex(corner3D)
st.add_vertex(corner3D + wall_up)
var first_corner = Vector3(corners[0].x, 0, corners[0].y)
st.add_vertex(first_corner)
st.add_vertex(first_corner + wall_up)
st.index()
st.generate_normals()
st.generate_tangents()
var mesh = st.commit()
return mesh
static func generate_ceiling_mesh(corners):
var points: PackedVector2Array = PackedVector2Array()
var edges: PackedInt32Array = PackedInt32Array()
var triangles: PackedInt32Array
if corners.size() < 3:
return null
for i in range(corners.size()):
var corner = corners[i]
points.append(Vector2(corner.x, corner.y))
edges.append(i)
edges.append((i + 1) % corners.size())
var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new()
cdt.init(true, true, 0.1)
cdt.insert_vertices(points)
cdt.insert_edges(edges)
cdt.erase_outer_triangles()
points = cdt.get_all_vertices()
triangles = cdt.get_all_triangles()
return _create_mesh(points, triangles)
static func generate_wall_mesh_grid(corners, height, grid: Vector2=Vector2(0.1, 0.1)):
if corners.size() < 3:
return null
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
for corner_i in range(corners.size()):
var corner = Vector3(corners[corner_i].x, 0, corners[corner_i].y)
var next_index = (corner_i + 1) % corners.size()
var next_corner = Vector3(corners[next_index].x, 0, corners[next_index].y)
var steps = ceil(Vector2((next_corner - corner).length() / grid.x, height / grid.y))
var forward_dir = (next_corner - corner).normalized() * grid.x
var up_dir = Vector3.UP * grid.y
var close_distance = Vector2(1, 1)
for y in range(0, steps.y):
close_distance.x = 1
if y == steps.y - 1:
close_distance.y = fmod(height, grid.y) / grid.y
print(close_distance.y)
for x in range(0, steps.x):
var point = corner + forward_dir * x + Vector3.UP * grid.y * y
if x == steps.x - 1:
close_distance.x = fmod(corner.distance_to(next_corner), grid.x) / grid.x
st.add_vertex(point)
st.add_vertex(point + forward_dir * close_distance.x)
st.add_vertex(point + up_dir * close_distance.y)
st.add_vertex(point + forward_dir * close_distance.x)
st.add_vertex(point + forward_dir * close_distance.x + up_dir * close_distance.y)
st.add_vertex(point + up_dir * close_distance.y)
st.index()
st.generate_normals()
st.generate_tangents()
var mesh = st.commit()
return mesh
static func generate_ceiling_mesh_grid(corners, grid: Vector2=Vector2(0.1, 0.1)):
var points: PackedVector2Array = PackedVector2Array()
var edges: PackedInt32Array = PackedInt32Array()
var triangles: PackedInt32Array
if corners.size() < 3:
return null
var min_val = Vector2(corners[0])
var max_val = Vector2(corners[0])
for i in range(corners.size()):
var corner = corners[i]
min_val.x = min(min_val.x, corner.x)
min_val.y = min(min_val.y, corner.y)
max_val.x = max(max_val.x, corner.x)
max_val.y = max(max_val.y, corner.y)
points.append(Vector2(corner.x, corner.y))
edges.append(i)
edges.append((i + 1) % corners.size())
var size = max_val - min_val
## Fill points insde the polygon
for y in range(1, int(size.y / grid.y)):
var x_intersections: Array[float] = []
var y_start = Vector2(min_val.x, min_val.y + y * grid.y)
var y_end = Vector2(max_val.x, min_val.y + y * grid.y)
for i in range(corners.size()):
var a = corners[i]
var b = corners[(i + 1) % corners.size()]
var result = Geometry2D.segment_intersects_segment(a, b, y_start, y_end)
if result != null:
x_intersections.append(result.x)
var intersection_counter = 0
x_intersections.sort()
for x in range(1, int(size.x / grid.x)):
var point = min_val + Vector2(x * grid.x, y * grid.y)
for i in range(intersection_counter, x_intersections.size()):
if x_intersections[i] < point.x:
intersection_counter += 1
var color = Color(1, 1, 0)
if intersection_counter % 2 == 1:
color = Color(1, 0, 1)
points.append(point)
var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new()
cdt.init(true, true, 0.1)
cdt.insert_vertices(points)
cdt.insert_edges(edges)
cdt.erase_outer_triangles()
points = cdt.get_all_vertices()
triangles = cdt.get_all_triangles()
return _create_mesh(points, triangles)
static func _create_mesh(points: PackedVector2Array, triangles: PackedInt32Array):
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
for i in range(points.size()):
st.add_vertex(Vector3(points[i].x, 0, points[i].y))
for i in range(triangles.size()):
st.add_index(triangles[i])
st.index()
st.generate_normals()
st.generate_tangents()
var mesh = st.commit()
return mesh