mirror of
https://github.com/danbulant/ambientlightdemo
synced 2026-05-19 04:18:32 +00:00
progress on single shared light
This commit is contained in:
parent
10a1b6d9d8
commit
7e5bfe891c
8 changed files with 151 additions and 25 deletions
25
main.gd
25
main.gd
|
|
@ -2,18 +2,21 @@ extends Node3D
|
|||
|
||||
@onready var lights: Lights = %Lights
|
||||
@onready var slider: HSlider = %HSlider
|
||||
@onready var networked_lights: Lights = %NetworkedLights
|
||||
|
||||
@export var light_rotation: float = 0.0
|
||||
@export var light_delta: float = 0.0
|
||||
@export var color_gradient: Gradient
|
||||
|
||||
var remote_light_rotation: float = 0.0
|
||||
var remote_light_delta: float = 0.0
|
||||
|
||||
var peer: PacketPeerUDP
|
||||
|
||||
func _ready():
|
||||
slider.value_changed.connect(set_local_light_rotation)
|
||||
peer = PacketPeerUDP.new()
|
||||
peer.bind(4433)
|
||||
peer.set_dest_address("rpi", 4444)
|
||||
peer.set_dest_address("rpi1", 4444)
|
||||
|
||||
|
||||
func send_data(data: Dictionary) -> void:
|
||||
|
|
@ -46,11 +49,21 @@ func set_local_light_rotation(value: float) -> void:
|
|||
send_data({"value": value})
|
||||
return
|
||||
|
||||
error_correction = 0.
|
||||
|
||||
lights.expected_rotation_delta = diff
|
||||
light_delta = diff
|
||||
light_rotation = value
|
||||
send_data({"value": value, "delta": diff})
|
||||
|
||||
func _process(_delta):
|
||||
var joystick_x = Input.get_joy_axis(0, JOY_AXIS_LEFT_X)
|
||||
var joystick_y = Input.get_joy_axis(0, JOY_AXIS_LEFT_Y)
|
||||
var joystick = Vector2(joystick_x, joystick_y)
|
||||
if joystick.length() > 0.2:
|
||||
var angle = (atan2(joystick_y, joystick_x) / TAU) + 0.25
|
||||
angle = wrapf(angle, 0, 1)
|
||||
set_local_light_rotation(angle)
|
||||
if peer.get_available_packet_count() > 0:
|
||||
var array_bytes = peer.get_packet()
|
||||
var packet_string = array_bytes.get_string_from_ascii()
|
||||
|
|
@ -58,8 +71,8 @@ func _process(_delta):
|
|||
if json != null:
|
||||
var value = json.value
|
||||
var delta = json.delta
|
||||
networked_lights.expected_rotation_delta = delta
|
||||
# networked_lights.expected_rotation_delta = delta
|
||||
|
||||
var polarized_value := pingpong(value * 4, 1)
|
||||
networked_lights.light_intensity = 1.0 - polarized_value
|
||||
networked_lights.light_color = color_gradient.sample(value)
|
||||
# var polarized_value := pingpong(value * 4, 1)
|
||||
# networked_lights.light_intensity = 1.0 - polarized_value
|
||||
# networked_lights.light_color = color_gradient.sample(value)
|
||||
18
main.tscn
18
main.tscn
|
|
@ -32,7 +32,6 @@ color_gradient = SubResource("Gradient_h2yge")
|
|||
|
||||
[node name="Plane" type="MeshInstance3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0)
|
||||
mesh = SubResource("CylinderMesh_0xm2m")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_7dm0k")
|
||||
|
||||
|
|
@ -45,26 +44,11 @@ light_count = 20
|
|||
light_radius = 0.7
|
||||
light_template = ExtResource("2_0xm2m")
|
||||
|
||||
[node name="NetworkedPlane" type="MeshInstance3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0)
|
||||
mesh = SubResource("CylinderMesh_0xm2m")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_7dm0k")
|
||||
|
||||
[node name="NetworkedLights" type="Marker3D" parent="NetworkedPlane"]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
gizmo_extents = 0.7
|
||||
script = ExtResource("1_ig7tw")
|
||||
light_count = 20
|
||||
light_radius = 0.7
|
||||
light_template = ExtResource("2_0xm2m")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_0xm2m")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 2, 0)
|
||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 1.4683123, 0)
|
||||
|
||||
[node name="HSlider" type="HSlider" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
|
|
|||
|
|
@ -15,6 +15,19 @@ run/main_scene="uid://bfysabo18nycq"
|
|||
config/features=PackedStringArray("4.5", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[input]
|
||||
|
||||
forward={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
anti_aliasing/quality/msaa_2d=2
|
||||
|
|
|
|||
|
|
@ -30,4 +30,13 @@ def sample_color_gradient(t):
|
|||
color_a = colors_rgb[i]
|
||||
color_b = colors_rgb[i + 1]
|
||||
return tuple(int(lerp(color_a[j], color_b[j], local_t)) for j in range(3))
|
||||
return colors_rgb[-1]
|
||||
return colors_rgb[-1]
|
||||
def shortest_diff(old, new):
|
||||
diff = old - new
|
||||
wrapped_diff = (new + 1) - old
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = -wrapped_diff
|
||||
wrapped_diff = (old + 1) - new
|
||||
if abs(wrapped_diff) < abs(diff):
|
||||
diff = wrapped_diff
|
||||
return diff
|
||||
|
|
@ -23,3 +23,5 @@ class Lights:
|
|||
self.pixels[i] = new_color
|
||||
self.pixels.show()
|
||||
self.expected_rotation_delta = lerp(self.expected_rotation_delta, 0, delta * LIGHT_SLOWDOWN_SPEED)
|
||||
|
||||
lights = Lights(pixels)
|
||||
73
rpi/main.py
Normal file
73
rpi/main.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import socket
|
||||
import time
|
||||
import json
|
||||
from lights import lights
|
||||
from stepper import stepper
|
||||
import gdmath
|
||||
from readangle import read_angle_f
|
||||
import threading
|
||||
|
||||
UDP_HOST = "steamdeck"
|
||||
UDP_PORT_LOCAL = 4444
|
||||
UDP_PORT_NETWORKED = 4433
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("", UDP_PORT_LOCAL))
|
||||
sock.setblocking(0)
|
||||
|
||||
def send_json(data):
|
||||
message = json.dumps(data).encode('utf-8')
|
||||
sock.sendto(message, (UDP_HOST, UDP_PORT_NETWORKED))
|
||||
|
||||
def receive_json():
|
||||
try:
|
||||
data, _ = sock.recvfrom(1024)
|
||||
return json.loads(data.decode('utf-8'))
|
||||
except BlockingIOError:
|
||||
return None
|
||||
|
||||
local_rotation = 0
|
||||
local_delta = 0
|
||||
remote_rotation = 0
|
||||
remote_delta = 0
|
||||
|
||||
def read_thread_fn():
|
||||
global local_rotation, local_delta
|
||||
while True:
|
||||
old_rotation = local_rotation
|
||||
local_rotation = read_angle_f()
|
||||
local_delta = gdmath.shortest_diff(old_rotation, local_rotation)
|
||||
send_json({"value": local_rotation, "delta": local_delta})
|
||||
|
||||
def lights_fn():
|
||||
global local_rotation, local_delta, remote_rotation, remote_delta
|
||||
last_time = time.time()
|
||||
delta = 1/60
|
||||
while True:
|
||||
lights.color = gdmath.sample_color_gradient(local_rotation + remote_rotation)
|
||||
lights.expected_rotation_delta = local_delta
|
||||
lights.process(delta)
|
||||
current_time = time.time()
|
||||
time.sleep(1/60)
|
||||
delta = current_time - last_time
|
||||
last_time = current_time
|
||||
|
||||
def network_recv_fn():
|
||||
global remote_rotation, remote_delta
|
||||
while True:
|
||||
data = receive_json()
|
||||
if data:
|
||||
remote_rotation = data["value"]
|
||||
remote_delta = data["delta"]
|
||||
time.sleep(0.01)
|
||||
|
||||
read_thread = threading.Thread(target=read_thread_fn)
|
||||
read_thread.start()
|
||||
lights_thread = threading.Thread(target=lights_fn)
|
||||
lights_thread.start()
|
||||
network_thread = threading.Thread(target=network_recv_fn)
|
||||
network_thread.start()
|
||||
|
||||
read_thread.join()
|
||||
lights_thread.join()
|
||||
network_thread.join()
|
||||
14
rpi/readangle.py
Normal file
14
rpi/readangle.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import smbus2
|
||||
|
||||
# Define I2C address and bus
|
||||
AS5600_ADDR = 0x36
|
||||
ANGLE_REG = 0x0E
|
||||
|
||||
bus = smbus2.SMBus(1)
|
||||
|
||||
def read_angle_f():
|
||||
# Read two bytes from the angle register
|
||||
raw_data = bus.read_i2c_block_data(AS5600_ADDR, ANGLE_REG, 2)
|
||||
angle = (raw_data[0] << 8) | raw_data[1] # Combine MSB and LSB
|
||||
angle = angle & 0x0FFF # Mask to 12 bits
|
||||
return (angle / 4096.0) # convert to 0-1
|
||||
|
|
@ -47,4 +47,22 @@ class StepperMotor:
|
|||
else:
|
||||
self.single_step_back()
|
||||
def pos(self):
|
||||
return self.current_step % self.step_count
|
||||
return self.current_step % self.step_count
|
||||
def fpos(self):
|
||||
return (self.current_step % self.step_count) / self.step_count
|
||||
|
||||
def single_step_towards(self, target_pos):
|
||||
current_pos = self.pos()
|
||||
# Determine shortest direction
|
||||
# includes wrap-around (it's a circular motion motor)
|
||||
diff = (target_pos - current_pos + self.step_count) % self.step_count
|
||||
if diff > self.step_count / 2:
|
||||
self.single_step_back()
|
||||
else:
|
||||
self.single_step()
|
||||
def angle_to_pos(self, angle):
|
||||
return int((angle % 360) / 360 * self.step_count)
|
||||
def fpos_to_pos(self, fpos):
|
||||
return int((fpos % 1) * self.step_count)
|
||||
|
||||
stepper = StepperMotor()
|
||||
Loading…
Reference in a new issue