I’m making a dodge ball like game and I want the ball to stretch when thrown and squish when it hits an object. I’m guessing I would do this based off its acceleration and would use a vertex shader. I’m pretty new to shaders so any guidance would be helpful.
Thanks! I tried that tutorial but it seems to not be quite what I’m looking for. I don’t like how it squashes in the middle. Here is a Unity asset that does more like what I’m looking for: https://www.youtube.com/watch?v=RjFjx_sC_XM&t=60s
The problem I’m facing now is the squash when hitting objects doesn’t look correct. It seems the object flips directions instead of squashing. Here is my code:
extends MeshInstance3D
@export var factor: float = 0.6 # Adjust as needed for stretching
@export var threshold: float = 0.1 # Acceleration threshold for stretching
@export var jerk_threshold: float = 1.0 # Jerk threshold for collision detection
@export var min_stretch: float = 1
@export var max_stretch: float = 2
@export var min_squash: float = .5 # Minimum squash factor
@export var smoothing_factor: float = 11 # Between 0 and 1
@export var squash_factor_multiplier: float = 0.7 # Adjust for squashing
var prev_pos: Vector3
var velocity: Vector3 = Vector3.ZERO
var prev_velocity: Vector3 = Vector3.ZERO
var acceleration: Vector3 = Vector3.ZERO
var prev_acceleration: Vector3 = Vector3.ZERO
var smoothed_acceleration: Vector3 = Vector3.ZERO
var prev_stretch_factor: float = 1.0
var prev_axis: Vector3 = Vector3.UP
func _ready() -> void:
prev_pos = global_transform.origin
func _physics_process(delta: float) -> void:
# Update velocity and acceleration
velocity = (global_transform.origin - prev_pos) / delta
print(velocity.length())
acceleration = (velocity - prev_velocity) / delta
prev_velocity = velocity
prev_pos = global_transform.origin # Update prev_pos here
# Apply smoothing to acceleration
smoothed_acceleration = smoothed_acceleration.lerp(acceleration, smoothing_factor)
# Calculate jerk (rate of change of acceleration)
var jerk = (smoothed_acceleration - prev_acceleration) / delta
prev_acceleration = smoothed_acceleration
# Calculate magnitudes
var accel_length = smoothed_acceleration.length()
var jerk_length = jerk.length()
# Determine if a collision occurred based on jerk threshold
var collision_detected = false
if jerk_length > jerk_threshold:
#print(jerk_length)
collision_detected = true
# Determine target stretch values
var target_stretch_factor = 1.0
var target_stretch_axis = prev_axis
if get_parent().get_attached_status() == false:
if velocity.length() > threshold:
print("threshhold")
# No collision detected, apply stretch based on acceleration
target_stretch_factor = clamp(1.0 + (velocity.length() * factor), min_stretch, max_stretch)
target_stretch_axis = velocity.normalized()
if target_stretch_axis.length() == 0:
target_stretch_axis = prev_axis
else:
# Optional: Use previous values for smoother transition
target_stretch_factor = 1.0
target_stretch_axis = prev_axis
# Prevent abrupt flipping of the stretch axis
if prev_axis.dot(target_stretch_axis) < 0:
pass
#target_stretch_axis = -target_stretch_axis
else:
target_stretch_axis = Vector3.UP
target_stretch_factor = 1.0
#Smoothly interpolate current values towards target values
var t = 1.0 - exp(-smoothing_factor * delta)
var material = mesh.surface_get_material(0)
var current_stretch_factor = prev_stretch_factor
var new_stretch_factor = lerp(current_stretch_factor, target_stretch_factor, t)
material.set("shader_parameter/stretch_factor", new_stretch_factor)
prev_stretch_factor = new_stretch_factor
var current_stretch_axis = prev_axis
var new_stretch_axis = current_stretch_axis.lerp(target_stretch_axis, t)
var inv_basis : Basis= global_transform.basis.inverse()
var target_stretch_axis_local = inv_basis * new_stretch_axis
material.set("shader_parameter/stretch_axis", target_stretch_axis_local.normalized())
prev_axis = new_stretch_axis
I think the issue is with the lerping of the axis.