Update portal plugin to 1.0.1
Includes the flickering fix!
This commit is contained in:
parent
d52d760b18
commit
79ce6cc145
13
addons/portals/CHANGELOG.md
Normal file
13
addons/portals/CHANGELOG.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
### 1.0.1
|
||||||
|
|
||||||
|
- Fix flickering when going sideways through a portal. PR #4
|
||||||
|
|
||||||
|
# 1.0.0
|
||||||
|
|
||||||
|
First public release! This plugin was developed as part of my master's thesis. As such, the thesis
|
||||||
|
itself is the best documentation at the moment:
|
||||||
|
[https://is.muni.cz/th/ydltb](https://is.muni.cz/th/ydltb/?lang=en).
|
||||||
|
|
||||||
|
Also check out the included README.md for tips and potentially also the
|
||||||
|
[GitHub repository](https://github.com/VojtaStruhar/godot-portals-plugin)
|
||||||
|
for some showcase levels.
|
@ -3,5 +3,5 @@
|
|||||||
name="Portals 3D"
|
name="Portals 3D"
|
||||||
description="Seamless portals plugin in 3D"
|
description="Seamless portals plugin in 3D"
|
||||||
author="Vojtech Struhar"
|
author="Vojtech Struhar"
|
||||||
version="1.0"
|
version="1.0.1"
|
||||||
script="plugin.gd"
|
script="plugin.gd"
|
||||||
|
@ -344,6 +344,9 @@ var portal_viewport: SubViewport = null
|
|||||||
class TeleportableMeta:
|
class TeleportableMeta:
|
||||||
## Forward distance from the portal
|
## Forward distance from the portal
|
||||||
var forward: float = 0
|
var forward: float = 0
|
||||||
|
## True only if the [member Portal3D.player_camera] is a child of the object being teleported.
|
||||||
|
## In that case, we consider it the player.
|
||||||
|
var is_player: bool = false
|
||||||
## Meshes that the object gave for duplication. Retrieved by the
|
## Meshes that the object gave for duplication. Retrieved by the
|
||||||
## [constant Portal3D.DUPLICATE_MESHES_CALLBACK] callback.
|
## [constant Portal3D.DUPLICATE_MESHES_CALLBACK] callback.
|
||||||
var meshes: Array[MeshInstance3D] = []
|
var meshes: Array[MeshInstance3D] = []
|
||||||
@ -468,7 +471,7 @@ func _ready() -> void:
|
|||||||
teleport_area.collision_mask = teleport_collision_mask
|
teleport_area.collision_mask = teleport_collision_mask
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -552,14 +555,13 @@ func _process_teleports() -> void:
|
|||||||
on_teleport.emit(teleportable)
|
on_teleport.emit(teleportable)
|
||||||
exit_portal.on_teleport_receive.emit(teleportable)
|
exit_portal.on_teleport_receive.emit(teleportable)
|
||||||
|
|
||||||
# Force the cameras to refresh if we just teleported a player
|
|
||||||
var was_player := not str(teleportable.get_path_to(player_camera)).begins_with(".")
|
if tp_meta.is_player:
|
||||||
if was_player:
|
|
||||||
_process_cameras()
|
_process_cameras()
|
||||||
exit_portal._process_cameras()
|
exit_portal._process_cameras()
|
||||||
|
|
||||||
# Resolve teleport interactions
|
# Resolve teleport interactions
|
||||||
if was_player and _check_tp_interaction(TeleportInteractions.PLAYER_UPRIGHT):
|
if tp_meta.is_player and _check_tp_interaction(TeleportInteractions.PLAYER_UPRIGHT):
|
||||||
get_tree().create_tween().tween_property(teleportable, "rotation:x", 0, 0.3)
|
get_tree().create_tween().tween_property(teleportable, "rotation:x", 0, 0.3)
|
||||||
get_tree().create_tween().tween_property(teleportable, "rotation:z", 0, 0.3)
|
get_tree().create_tween().tween_property(teleportable, "rotation:z", 0, 0.3)
|
||||||
|
|
||||||
@ -691,11 +693,22 @@ func _on_window_resize() -> void:
|
|||||||
#region UTILS
|
#region UTILS
|
||||||
|
|
||||||
func _construct_tp_metadata(node: Node3D) -> void:
|
func _construct_tp_metadata(node: Node3D) -> void:
|
||||||
|
var teleportable = node.get_node(node.get_meta(TELEPORT_ROOT_META, ".")) # Usually the node itself
|
||||||
|
|
||||||
var meta = TeleportableMeta.new()
|
var meta = TeleportableMeta.new()
|
||||||
meta.forward = forward_distance(node)
|
meta.forward = forward_distance(node)
|
||||||
|
meta.is_player = not str(teleportable.get_path_to(player_camera)).begins_with(".")
|
||||||
|
|
||||||
if _check_tp_interaction(TeleportInteractions.DUPLICATE_MESHES) and \
|
## This is a workaround to prevent flickering when traversing portals.
|
||||||
node.has_method(DUPLICATE_MESHES_CALLBACK):
|
## There is a bit of lag when restarting RTT when the exit portal becomes physically visible.
|
||||||
|
## Ensuring both portals are updated regardless of visibility while in the portals prevents flickering.
|
||||||
|
## More info: https://github.com/VojtaStruhar/godot-portals-plugin/pull/4
|
||||||
|
if meta.is_player:
|
||||||
|
_set_portal_pair_update_mode(SubViewport.UPDATE_ALWAYS)
|
||||||
|
|
||||||
|
if _check_tp_interaction(TeleportInteractions.DUPLICATE_MESHES)\
|
||||||
|
and node.has_method(DUPLICATE_MESHES_CALLBACK):
|
||||||
|
|
||||||
meta.meshes = node.call(DUPLICATE_MESHES_CALLBACK)
|
meta.meshes = node.call(DUPLICATE_MESHES_CALLBACK)
|
||||||
for m: MeshInstance3D in meta.meshes:
|
for m: MeshInstance3D in meta.meshes:
|
||||||
var dupe = m.duplicate(0)
|
var dupe = m.duplicate(0)
|
||||||
@ -711,11 +724,40 @@ func _erase_tp_metadata(node_id: int) -> void:
|
|||||||
var meta = _watchlist_teleportables.get(node_id)
|
var meta = _watchlist_teleportables.get(node_id)
|
||||||
if meta != null:
|
if meta != null:
|
||||||
meta = meta as TeleportableMeta
|
meta = meta as TeleportableMeta
|
||||||
|
|
||||||
|
if meta.is_player:
|
||||||
|
_set_portal_pair_update_mode(SubViewport.UPDATE_WHEN_VISIBLE)
|
||||||
|
|
||||||
for m in meta.meshes: _disable_mesh_clipping(m)
|
for m in meta.meshes: _disable_mesh_clipping(m)
|
||||||
for c in meta.mesh_clones: c.queue_free()
|
for c in meta.mesh_clones: c.queue_free()
|
||||||
|
|
||||||
_watchlist_teleportables.erase(node_id)
|
_watchlist_teleportables.erase(node_id)
|
||||||
|
|
||||||
|
|
||||||
|
func _transfer_tp_metadata_to_exit(for_body: Node3D) -> void:
|
||||||
|
if not exit_portal.is_teleport:
|
||||||
|
return # One-way teleport scenario
|
||||||
|
|
||||||
|
var body_id = for_body.get_instance_id()
|
||||||
|
var tp_meta = _watchlist_teleportables[body_id]
|
||||||
|
assert(tp_meta != null, "Attempted to trasfer teleport metadata for a node that is not being watched.")
|
||||||
|
|
||||||
|
tp_meta.forward = exit_portal.forward_distance(for_body)
|
||||||
|
_enable_mesh_clipping(tp_meta, exit_portal) # Switch, the main mesh is clipped by exit portal!
|
||||||
|
|
||||||
|
exit_portal._watchlist_teleportables.set(body_id, tp_meta)
|
||||||
|
|
||||||
|
if tp_meta.is_player and exit_portal.exit_portal != self:
|
||||||
|
# Not a portal pair - the transition isn't seamless anyways. Flip the update
|
||||||
|
# mode of this portal "manually" and enable the next portal pair, since `_construct_tp_metadata`
|
||||||
|
# will not get called there. Usually portals are symmetric, though.
|
||||||
|
portal_viewport.set_update_mode(SubViewport.UPDATE_WHEN_VISIBLE)
|
||||||
|
exit_portal._set_portal_pair_update_mode(SubViewport.UPDATE_ALWAYS)
|
||||||
|
|
||||||
|
# NOTE: Not using '_erase_tp_metadata' here, as it also frees the cloned meshes!
|
||||||
|
_watchlist_teleportables.erase(body_id)
|
||||||
|
|
||||||
|
|
||||||
func _enable_mesh_clipping(meta: TeleportableMeta, along_portal: Portal3D) -> void:
|
func _enable_mesh_clipping(meta: TeleportableMeta, along_portal: Portal3D) -> void:
|
||||||
for mi: MeshInstance3D in meta.meshes:
|
for mi: MeshInstance3D in meta.meshes:
|
||||||
var clip_normal = signf(meta.forward) * along_portal.global_basis.z
|
var clip_normal = signf(meta.forward) * along_portal.global_basis.z
|
||||||
@ -733,23 +775,6 @@ func _enable_mesh_clipping(meta: TeleportableMeta, along_portal: Portal3D) -> vo
|
|||||||
func _disable_mesh_clipping(mi: MeshInstance3D) -> void:
|
func _disable_mesh_clipping(mi: MeshInstance3D) -> void:
|
||||||
mi.set_instance_shader_parameter("portal_clip_active", false)
|
mi.set_instance_shader_parameter("portal_clip_active", false)
|
||||||
|
|
||||||
func _transfer_tp_metadata_to_exit(for_body: Node3D) -> void:
|
|
||||||
if not exit_portal.is_teleport:
|
|
||||||
return # One-way teleport scenario
|
|
||||||
|
|
||||||
var body_id = for_body.get_instance_id()
|
|
||||||
var tp_meta = _watchlist_teleportables[body_id]
|
|
||||||
if tp_meta == null:
|
|
||||||
push_error("Attempted to trasfer teleport metadata for a node that is not being watched.")
|
|
||||||
return
|
|
||||||
|
|
||||||
tp_meta.forward = exit_portal.forward_distance(for_body)
|
|
||||||
_enable_mesh_clipping(tp_meta, exit_portal) # Switch, the main mesh is clipped by exit portal!
|
|
||||||
|
|
||||||
exit_portal._watchlist_teleportables.set(body_id, tp_meta)
|
|
||||||
# NOTE: Not using '_erase_tp_metadata' here, as it also frees the cloned meshes!
|
|
||||||
_watchlist_teleportables.erase(body_id)
|
|
||||||
|
|
||||||
## [b]Crucial[/b] piece of a portal - transforming where objects should appear
|
## [b]Crucial[/b] piece of a portal - transforming where objects should appear
|
||||||
## on the other side. Used for both cameras and teleports.
|
## on the other side. Used for both cameras and teleports.
|
||||||
func to_exit_transform(g_transform: Transform3D) -> Transform3D:
|
func to_exit_transform(g_transform: Transform3D) -> Transform3D:
|
||||||
@ -828,6 +853,12 @@ func _calculate_viewport_size() -> Vector2i:
|
|||||||
func _check_tp_interaction(flag: int) -> bool:
|
func _check_tp_interaction(flag: int) -> bool:
|
||||||
return (teleport_interactions & flag) > 0
|
return (teleport_interactions & flag) > 0
|
||||||
|
|
||||||
|
func _set_portal_pair_update_mode(mode: SubViewport.UpdateMode) -> void:
|
||||||
|
assert(is_instance_valid(exit_portal))
|
||||||
|
self.portal_viewport.set_update_mode(mode)
|
||||||
|
if exit_portal.portal_viewport:
|
||||||
|
exit_portal.portal_viewport.set_update_mode(mode)
|
||||||
|
|
||||||
## Get a point where the portal plane intersects a line. Line [param start] and [param end]
|
## Get a point where the portal plane intersects a line. Line [param start] and [param end]
|
||||||
## are in global coordinates and so is the result. Used for forwarding raycast queries.
|
## are in global coordinates and so is the result. Used for forwarding raycast queries.
|
||||||
func line_intersection(start: Vector3, end: Vector3) -> Vector3:
|
func line_intersection(start: Vector3, end: Vector3) -> Vector3:
|
||||||
|
Loading…
Reference in New Issue
Block a user