Initial commit.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
@tool
|
||||
class_name PostProcessShader
|
||||
extends CompositorEffect
|
||||
|
||||
|
||||
@export var vignette_colour : Color = Color(0.0, 0.0, 0.0, 0.392)
|
||||
@export var vignette_pupil : float = 0.8
|
||||
@export var vignette_iris : float = 0.4
|
||||
|
||||
|
||||
# Called when this resource is constructed.
|
||||
func _init():
|
||||
effect_callback_type = CompositorEffect.EFFECT_CALLBACK_TYPE_POST_TRANSPARENT
|
||||
RenderingServer.call_on_render_thread(_initialize_compute)
|
||||
|
||||
# System notifications, we want to react on the notification that
|
||||
# alerts us we are about to be destroyed.
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
if shader.is_valid():
|
||||
# Freeing our shader will also free any dependents such as the pipeline!
|
||||
rd.free_rid(shader)
|
||||
|
||||
var rd : RenderingDevice
|
||||
var shader : RID
|
||||
var pipeline : RID
|
||||
|
||||
## Render thread code below
|
||||
|
||||
func _initialize_compute():
|
||||
rd = RenderingServer.get_rendering_device()
|
||||
if !rd: return
|
||||
|
||||
var shader_file = load("uid://bxunu0anan320")
|
||||
var shader_spirv : RDShaderSPIRV = shader_file.get_spirv()
|
||||
shader = rd.shader_create_from_spirv(shader_spirv)
|
||||
pipeline = rd.compute_pipeline_create(shader)
|
||||
|
||||
# Called by the rendering thread every frame.
|
||||
func _render_callback(p_effect_callback_type, p_render_data):
|
||||
if rd and p_effect_callback_type == EFFECT_CALLBACK_TYPE_POST_TRANSPARENT:
|
||||
# Get our render scene buffers object, this gives us access to our render buffers.
|
||||
# Note that implementation differs per renderer hence the need for the cast.
|
||||
var render_scene_buffers: RenderSceneBuffersRD = p_render_data.get_render_scene_buffers()
|
||||
if render_scene_buffers:
|
||||
|
||||
# Loop through views just in case we're doing stereo rendering. No extra cost if this is mono.
|
||||
var view_count = render_scene_buffers.get_view_count()
|
||||
for view in range(view_count):
|
||||
# Get our render size, this is the 3D render resolution!
|
||||
var raster_size = render_scene_buffers.get_internal_size()
|
||||
if raster_size.x == 0 and raster_size.y == 0:
|
||||
return
|
||||
|
||||
# We can use a compute shader here.
|
||||
var x_groups = (raster_size.x - 1) / 8 + 1
|
||||
var y_groups = (raster_size.y - 1) / 8 + 1
|
||||
var z_groups = 1
|
||||
|
||||
# Get the RID for our color image, we will be reading from and writing to it.
|
||||
var input_image = render_scene_buffers.get_color_layer(view)
|
||||
|
||||
# Push constant.
|
||||
var push_constant: PackedFloat32Array = PackedFloat32Array()
|
||||
push_constant.push_back(raster_size.x)
|
||||
push_constant.push_back(raster_size.y)
|
||||
push_constant.push_back(0.0)
|
||||
push_constant.push_back(0.0)
|
||||
|
||||
push_constant.push_back(vignette_colour.r)
|
||||
push_constant.push_back(vignette_colour.g)
|
||||
push_constant.push_back(vignette_colour.b)
|
||||
push_constant.push_back(vignette_colour.a)
|
||||
|
||||
push_constant.push_back(vignette_pupil)
|
||||
push_constant.push_back(vignette_iris)
|
||||
push_constant.push_back(0.0)
|
||||
push_constant.push_back(0.0)
|
||||
|
||||
# Create a uniform set.
|
||||
# This will be cached; the cache will be cleared if our viewport's configuration is changed.
|
||||
var uniform: RDUniform = RDUniform.new()
|
||||
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
|
||||
uniform.binding = 0
|
||||
uniform.add_id(input_image)
|
||||
var uniform_set = UniformSetCacheRD.get_cache(shader, 0, [ uniform ])
|
||||
|
||||
# Run our compute shader.
|
||||
var compute_list:= rd.compute_list_begin()
|
||||
rd.compute_list_bind_compute_pipeline(compute_list, pipeline)
|
||||
rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0)
|
||||
rd.compute_list_set_push_constant(compute_list, push_constant.to_byte_array(), push_constant.size() * 4)
|
||||
rd.compute_list_dispatch(compute_list, x_groups, y_groups, z_groups)
|
||||
rd.compute_list_end()
|
||||
@@ -0,0 +1 @@
|
||||
uid://crtv5xh5ud5kq
|
||||
@@ -0,0 +1,104 @@
|
||||
class_name SliceRing
|
||||
extends Node3D
|
||||
|
||||
@export var slice_ring_mesh : MeshInstance3D
|
||||
@export_file("*.scn", "*.tscn") var slice_ring_hurtbox : String
|
||||
|
||||
@export_category("Input")
|
||||
@export var slice_ring_input : InputResource
|
||||
@export var _joystick_tilt_threshold : float = 0.6
|
||||
@export var _flick_threshold : float = 0.15
|
||||
@export_range(0.01, 0.1, 0.001) var _flick_detection_timer_delay : float = 0.05
|
||||
@export var _rotation_lerp_speed : float = 20.0
|
||||
|
||||
@export var _random_slice_positions_horizontal : Array[float]
|
||||
@export var _random_slice_positions_vertical : Array[float]
|
||||
@export_range(0.02, 1.0, 0.02) var _max_time_between_cuts : float = 0.12
|
||||
|
||||
@export_category("Visuals")
|
||||
@export var _high_power_material : Material
|
||||
@export var _low_power_material : Material
|
||||
|
||||
@onready var _flick_timer : Timer = $FlickTimer
|
||||
@onready var _slice_timer : Timer = $SliceTimer
|
||||
|
||||
signal slice_aim_update(bool, float)
|
||||
signal slice_executed
|
||||
|
||||
var _is_aiming_slice : bool = false
|
||||
var _last_angle_vector_length : float = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
slice_ring_mesh.quaternion = Quaternion.IDENTITY
|
||||
|
||||
InputHandler.add_input_resource(self, slice_ring_input)
|
||||
|
||||
func set_high_power(_high_power:bool) -> void:
|
||||
slice_ring_mesh.mesh.surface_set_material(0, _high_power_material if _high_power else _low_power_material)
|
||||
|
||||
|
||||
func _calculate_slice_angle(_delta:float, _vector:Vector2, _tilt_input:bool) -> void:
|
||||
var angle_length : float = _vector.length()
|
||||
if _slice_timer.is_stopped():
|
||||
if angle_length >= _joystick_tilt_threshold or not _tilt_input:
|
||||
var normalised_vector : Vector2 = _vector.normalized()
|
||||
var angle : float = atan2(normalised_vector.y, normalised_vector.x)
|
||||
slice_ring_mesh.quaternion = lerp(slice_ring_mesh.quaternion, Quaternion(basis.z, angle), _delta * angle_length * _rotation_lerp_speed)
|
||||
_is_aiming_slice = true
|
||||
elif _tilt_input and _last_angle_vector_length >= _joystick_tilt_threshold:
|
||||
if _flick_timer.is_inside_tree() and _flick_timer.is_stopped() and _last_angle_vector_length >= _joystick_tilt_threshold:
|
||||
_flick_timer.start(_flick_detection_timer_delay)
|
||||
emit_signal("slice_aim_update", _is_aiming_slice, slice_ring_mesh.rotation.z)
|
||||
_last_angle_vector_length = angle_length
|
||||
|
||||
func _on_flick_timer_timeout() -> void:
|
||||
if _last_angle_vector_length < _flick_threshold:
|
||||
_execute_slice()
|
||||
_is_aiming_slice = false
|
||||
emit_signal("slice_aim_update", _is_aiming_slice, 0.0)
|
||||
|
||||
func _execute_slice(_treat_as_flick:bool = true, _vertical_slices:bool = false) -> void:
|
||||
slice_ring_mesh.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_INHERIT if _treat_as_flick else Node.PHYSICS_INTERPOLATION_MODE_OFF
|
||||
|
||||
if _slice_timer.is_inside_tree() and _slice_timer.is_stopped():
|
||||
if not _treat_as_flick and not _is_aiming_slice:
|
||||
var random_roll : float = 0.0
|
||||
if _vertical_slices:
|
||||
if _random_slice_positions_vertical.size() > 0:
|
||||
random_roll = _random_slice_positions_vertical[0]
|
||||
_random_slice_positions_vertical.remove_at(0)
|
||||
_random_slice_positions_vertical.append(random_roll)
|
||||
else:
|
||||
random_roll = 90.0
|
||||
else:
|
||||
if _random_slice_positions_horizontal.size() > 0:
|
||||
random_roll = _random_slice_positions_horizontal[0]
|
||||
_random_slice_positions_horizontal.remove_at(0)
|
||||
_random_slice_positions_horizontal.append(random_roll)
|
||||
else:
|
||||
random_roll = 90.0
|
||||
slice_ring_mesh.quaternion = Quaternion(Vector3.FORWARD, deg_to_rad(random_roll))
|
||||
|
||||
var _slice_ring_hurtbox_node : HurtboxBase = load(slice_ring_hurtbox).instantiate()
|
||||
if _slice_ring_hurtbox_node:
|
||||
_slice_ring_hurtbox_node.global_transform = slice_ring_mesh.global_transform
|
||||
get_tree().root.add_child(_slice_ring_hurtbox_node)
|
||||
|
||||
emit_signal("slice_executed")
|
||||
_slice_timer.start()
|
||||
|
||||
func _on_slice_timer_timeout() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _on_horizontal_slice_pressed() -> void:
|
||||
_execute_slice(false, false)
|
||||
|
||||
func _on_vertical_slice_pressed() -> void:
|
||||
_execute_slice(false, true)
|
||||
|
||||
func _on_aim_slice_ring_2d(_delta:float, _vector:Vector2) -> void:
|
||||
_calculate_slice_angle(_delta, _vector, true)
|
||||
func _on_aim_slice_ring_mouse(_delta:float, _vector:Vector2) -> void:
|
||||
_calculate_slice_angle(_delta, _vector, false)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cpvwd36exce1n
|
||||
Reference in New Issue
Block a user