101 lines
4.2 KiB
GDScript
101 lines
4.2 KiB
GDScript
extends MeshInstance3D
|
|
class_name MyPortal
|
|
|
|
## My own portal implementation
|
|
|
|
@export var exit_portal: MyPortal
|
|
|
|
#preload("res://scripts/my_portal_material.tres")
|
|
const MY_PORTAL_MATERIAL = preload("uid://cwobk5ik5k5aj")
|
|
|
|
var _viewport: SubViewport
|
|
var _camera: Camera3D = Camera3D.new()
|
|
var _main_camera: Camera3D = null
|
|
|
|
var exit_scale: int = 1 # This is not really needed I think
|
|
|
|
func _ready() -> void:
|
|
assert(exit_portal != null)
|
|
|
|
# Update portals last
|
|
process_priority = 1000
|
|
_main_camera = get_viewport().get_camera_3d()
|
|
|
|
# NOTE: In case the exit portal is in a different world, better put the viewport and camera
|
|
# onto IT, rather than me (?)
|
|
_viewport = SubViewport.new()
|
|
_viewport.name = name + "_Viewport"
|
|
_viewport.size = get_viewport().size
|
|
add_child(_viewport)
|
|
|
|
_camera.name = name + "_ExitCamera"
|
|
_viewport.add_child(_camera)
|
|
|
|
# FIXME: Remove this - debug only
|
|
var debug = MeshInstance3D.new()
|
|
debug.rotate_z(PI / 2)
|
|
debug.material_override = StandardMaterial3D.new()
|
|
debug.material_override.albedo_color = Color.MAGENTA
|
|
debug.mesh = PrismMesh.new()
|
|
_camera.add_child(debug)
|
|
|
|
|
|
var mat: ShaderMaterial = MY_PORTAL_MATERIAL
|
|
material_override = mat
|
|
mat.set_shader_parameter("albedo", _viewport.get_texture())
|
|
|
|
print(name, ": _ready")
|
|
|
|
func _process(delta: float) -> void:
|
|
_camera.global_transform = real_to_exit_transform(_main_camera.global_transform)
|
|
|
|
# TODO: Adjust near clip plane to the portal
|
|
_camera.near = _main_camera.near
|
|
_camera.far = _main_camera.far
|
|
_camera.fov = _main_camera.fov
|
|
_camera.keep_aspect = _main_camera.keep_aspect
|
|
|
|
|
|
## Return a new Transform3D relative to the exit portal based on the real Transform3D relative to this portal.
|
|
func real_to_exit_transform(real:Transform3D) -> Transform3D:
|
|
# Convert from global space to local space at the entrance (this) portal
|
|
var local:Transform3D = global_transform.affine_inverse() * real
|
|
# Compensate for any scale the entrance portal may have
|
|
var unscaled:Transform3D = local.scaled(global_transform.basis.get_scale())
|
|
# Flip it (the portal always flips the view 180 degrees)
|
|
var flipped:Transform3D = unscaled.rotated(Vector3.UP, PI)
|
|
# Apply any scale the exit portal may have (and apply custom exit scale)
|
|
var exit_scale_vector:Vector3 = exit_portal.global_transform.basis.get_scale()
|
|
var scaled_at_exit:Transform3D = flipped.scaled(Vector3.ONE / exit_scale_vector * exit_scale)
|
|
# Convert from local space at the exit portal to global space
|
|
var local_at_exit:Transform3D = exit_portal.global_transform * scaled_at_exit
|
|
return local_at_exit
|
|
|
|
## Return a new position relative to the exit portal based on the real position relative to this portal.
|
|
func real_to_exit_position(real:Vector3) -> Vector3:
|
|
# Convert from global space to local space at the entrance (this) portal
|
|
var local:Vector3 = global_transform.affine_inverse() * real
|
|
# Compensate for any scale the entrance portal may have
|
|
var unscaled:Vector3 = local * global_transform.basis.get_scale()
|
|
# Apply any scale the exit portal may have (and apply custom exit scale)
|
|
var exit_scale_vector:Vector3 = Vector3(-1, 1, 1) * exit_portal.global_transform.basis.get_scale()
|
|
var scaled_at_exit:Vector3 = unscaled / exit_scale_vector * exit_scale
|
|
# Convert from local space at the exit portal to global space
|
|
var local_at_exit:Vector3 = exit_portal.global_transform * scaled_at_exit
|
|
return local_at_exit
|
|
|
|
## Return a new direction relative to the exit portal based on the real direction relative to this portal.
|
|
func real_to_exit_direction(real:Vector3) -> Vector3:
|
|
# Convert from global to local space at the entrance (this) portal
|
|
var local:Vector3 = global_transform.basis.inverse() * real
|
|
# Compensate for any scale the entrance portal may have
|
|
var unscaled:Vector3 = local * global_transform.basis.get_scale()
|
|
# Flip it (the portal always flips the view 180 degrees)
|
|
var flipped:Vector3 = unscaled.rotated(Vector3.UP, PI)
|
|
# Apply any scale the exit portal may have (and apply custom exit scale)
|
|
var exit_scale_vector:Vector3 = exit_portal.global_transform.basis.get_scale()
|
|
var scaled_at_exit:Vector3 = flipped / exit_scale_vector * exit_scale
|
|
# Convert from local space at the exit portal to global space
|
|
var local_at_exit:Vector3 = exit_portal.global_transform.basis * scaled_at_exit
|
|
return local_at_exit
|