Skip to content

Instantly share code, notes, and snippets.

@chaojian-zhang
Created December 10, 2024 23:42
Show Gist options
  • Save chaojian-zhang/41957b6c7be8998c996c05b510a762e6 to your computer and use it in GitHub Desktop.
Save chaojian-zhang/41957b6c7be8998c996c05b510a762e6 to your computer and use it in GitHub Desktop.
Project scripts and resources
class_name FreeLookCamera extends Camera3D
# Modifier keys' speed multiplier
const SHIFT_MULTIPLIER = 2.5
const ALT_MULTIPLIER = 1.0 / SHIFT_MULTIPLIER
@export_range(0.0, 1.0) var sensitivity: float = 0.25
# Mouse state
var _mouse_position = Vector2(0.0, 0.0)
var _total_pitch = 0.0
# Movement state
var _direction = Vector3(0.0, 0.0, 0.0)
var _velocity = Vector3(0.0, 0.0, 0.0)
var _acceleration = 30
var _deceleration = -10
var _vel_multiplier = 4
# Keyboard state
var _w = false
var _s = false
var _a = false
var _d = false
var _q = false
var _e = false
var _shift = false
var _alt = false
func _input(event):
# Receives mouse motion
if event is InputEventMouseMotion:
_mouse_position = event.relative
# Receives mouse button input
if event is InputEventMouseButton:
match event.button_index:
MOUSE_BUTTON_RIGHT: # Only allows rotation if right click down
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE)
MOUSE_BUTTON_WHEEL_UP: # Increases max velocity
_vel_multiplier = clamp(_vel_multiplier * 1.1, 0.2, 20)
MOUSE_BUTTON_WHEEL_DOWN: # Decereases max velocity
_vel_multiplier = clamp(_vel_multiplier / 1.1, 0.2, 20)
# Receives key input
if event is InputEventKey:
match event.keycode:
KEY_W:
_w = event.pressed
KEY_S:
_s = event.pressed
KEY_A:
_a = event.pressed
KEY_D:
_d = event.pressed
KEY_Q:
_q = event.pressed
KEY_E:
_e = event.pressed
KEY_SHIFT:
_shift = event.pressed
KEY_ALT:
_alt = event.pressed
# Updates mouselook and movement every frame
func _process(delta):
_update_mouselook()
_update_movement(delta)
# Updates camera movement
func _update_movement(delta):
# Computes desired direction from key states
_direction = Vector3(
(_d as float) - (_a as float),
(_e as float) - (_q as float),
(_s as float) - (_w as float)
)
# Computes the change in velocity due to desired direction and "drag"
# The "drag" is a constant acceleration on the camera to bring it's velocity to 0
var offset = _direction.normalized() * _acceleration * _vel_multiplier * delta \
+ _velocity.normalized() * _deceleration * _vel_multiplier * delta
# Compute modifiers' speed multiplier
var speed_multi = 1
if _shift: speed_multi *= SHIFT_MULTIPLIER
if _alt: speed_multi *= ALT_MULTIPLIER
# Checks if we should bother translating the camera
if _direction == Vector3.ZERO and offset.length_squared() > _velocity.length_squared():
# Sets the velocity to 0 to prevent jittering due to imperfect deceleration
_velocity = Vector3.ZERO
else:
# Clamps speed to stay within maximum value (_vel_multiplier)
_velocity.x = clamp(_velocity.x + offset.x, -_vel_multiplier, _vel_multiplier)
_velocity.y = clamp(_velocity.y + offset.y, -_vel_multiplier, _vel_multiplier)
_velocity.z = clamp(_velocity.z + offset.z, -_vel_multiplier, _vel_multiplier)
translate(_velocity * delta * speed_multi)
# Updates mouse look
func _update_mouselook():
# Only rotates mouse if the mouse is captured
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
_mouse_position *= sensitivity
var yaw = _mouse_position.x
var pitch = _mouse_position.y
_mouse_position = Vector2(0, 0)
# Prevents looking up/down too far
pitch = clamp(pitch, -90 - _total_pitch, 90 - _total_pitch)
_total_pitch += pitch
rotate_y(deg_to_rad(-yaw))
rotate_object_local(Vector3(1,0,0), deg_to_rad(-pitch))
shader_type spatial;
instance uniform float my_instance_id;
// Helper function to convert HSV to RGB
vec3 hsv2rgb(vec3 c) {
vec3 p = abs(fract(c.x + vec3(0.0, 1.0, 2.0) / 3.0) * 6.0 - 3.0) - 1.0;
return c.z * mix(vec3(1.0), clamp(p, 0.0, 1.0), c.y);
}
void fragment() {
// Simple pseudo-random generator using sine function
float random_value = fract(sin(my_instance_id/100.0));
// Create a low-saturation color
float hue = random_value; // Use the random value for hue
float saturation = 0.5; // Low saturation for pastel-like colors
float value = 0.8; // Keep the brightness/value high for visibility
// Convert HSV to RGB
vec3 color = hsv2rgb(vec3(hue, saturation, value));
// Assign the color to the fragment
ALBEDO = color;
}
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://bfcm41ftrla60"]
[ext_resource type="Shader" path="res://instance_shader.gdshader" id="1_k4nph"]
[resource]
render_priority = 0
shader = ExtResource("1_k4nph")
extends Node3D
@export var root:Node3D = null
@export var material:ShaderMaterial = null
var counter = 0.0
# Function to assign a material to all children of a node
func assign_material_to_children(parent_node: Node, material: Material) -> void:
for child in parent_node.get_children():
if child is MeshInstance3D: # Check if the child is a MeshInstance
child.material_override = material
child.set_instance_shader_parameter("my_instance_id", counter)
counter += 1
elif child.get_child_count() > 0:
# Recursively assign the material to the children of children
assign_material_to_children(child, material)
# Example usage
func _ready() -> void:
assign_material_to_children(root, material)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment