Compare commits

...

26 Commits

Author SHA1 Message Date
42490ddad9 GDScript formatting
Thanks, VS Code (:
2025-03-04 21:51:27 +01:00
1e100bee4d Add test level to menu 2025-03-04 20:11:28 +01:00
5e8725eefc Test level for viewport frame delay
These viewports are NOT delayed. What am I doing wrong? Is it that they
are created programmatically???
2025-03-04 19:04:48 +01:00
eba916fb81 WIP: Camera transforms not working 2025-03-03 23:03:10 +01:00
50314f1ad8 My own buggy portal implementation 2025-03-03 22:31:31 +01:00
ded1600175 Add hermione level to menu 2025-02-28 16:13:33 +01:00
5012b5f73e Multiple worlds absolutely do work 2025-02-27 18:57:27 +01:00
da87b39b3d Create rooms for house that's bigger on the inside 2025-02-26 22:45:11 +01:00
5345386d36 Try out locking an internal node in editor 2025-02-26 16:07:43 +01:00
447e821429 Marek konzultace 2025-02-26 14:42:00 +01:00
1fa1e709ff Play around with internal nodes
They are selectable, isn't that interesting?
2025-02-25 22:49:55 +01:00
ac50e8eee7 Try out rounded portal frame 2025-02-25 21:23:51 +01:00
200694a005 Try out custom mesh resource 2025-02-25 21:06:49 +01:00
4a08b21bed Wanted to try out cube portals 2025-02-25 19:53:52 +01:00
7266a89b60 Turn off portal gizmo bezier curve 2025-02-25 19:14:29 +01:00
a50449c71b Used procedural mesh in semaphore level 2025-02-24 22:49:03 +01:00
f39c7e70c7 Fix UV coordinates 2025-02-24 22:20:05 +01:00
1a908d4eff Indented plane mesh procgen 2025-02-24 21:38:11 +01:00
2e8c1a5562 Indexing into mesh arrays more efficiently 2025-02-24 20:12:56 +01:00
2c01143579 Test procedural mesh generation 2025-02-24 18:38:38 +01:00
3187c3d359 Clean up debug prints + smooth bezier 2025-02-24 17:14:12 +01:00
3834d282ca Fixed cubic bezier curve 2025-02-21 17:15:52 +01:00
808e1503fb WIP: Bezier curve gizmo connecting the portals
Broken for some reason. Only works nicely when the source portal is NOT
rotated in any way
2025-02-20 22:57:51 +01:00
eeb35efa18 Gizmos - simple line connecting the portals 2025-02-20 21:58:19 +01:00
2da0429cdd Godot 4.4-beta4 2025-02-17 21:03:18 +01:00
f3440af264 Create README 2025-02-16 17:56:12 +01:00
89 changed files with 2981 additions and 163 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
# Godot 4+ specific ignores
.godot/
/android/
.idea
.DS_Store

View File

@ -28,4 +28,61 @@ venkovního úhlu. Protože reálně jsem od něj mega daleko, takže portálov
- **Fejkování světel** (OmniLight) by možná šlo!!! S rendering layerama bys nastavil aby některé světla byly vidět JEN skrz portály a NE tou kamerou co má hráč na sobě.
- Tohle platí hlavně u ~~free-standing~~ portálů na které jde koukat z obou stran. *Bylo by divné kdyby byl zezadu portálu ve vzduchu light source jenom proto, že na druhé straně portálu (bůh ví kde) takový source někde je*
- Free-standing portál neni uplně dobrý příklad, protože by to světlo mělo házet _výseč_ ven. To ničím fajné, to jsme zpátky u raytracingu. Leda by to člověk oblbnul nějakým shadow meshem nebo něco.. hm. Velmi specifické. Ale u těch dveří jako v semaforovém levelu by to fungovalo asi v pohodě, protože kolem futer je stěna.
- Spotlight..?
- Spotlight..?
### Gizmos
- Kreslím kubickou bezierku, která spojuje portál s exit portálem, ale nevypadá to nic moc. Je to blbě vidět a hloubka se dost ztrácí.
- Možná by bylo lepší ten exit portal _highlightnout_ podobně jak je zrovna vybraný node - double line gizmo
- TODO: Handly na procedurální mesh. Inspirace v godotím CollisionShape
### Procedural mesh
Momentálně procedural mesh generuju helper nodem. Tohle je ideální kandidát na _gizmo handles_ podobně jak collision shape
- Normály jsou pass. Mám jenom 8 vertexů, takže to bude dycky vypadat blbě. Ale portály jsou stejně vždycky unshaded.
- **Zmínit v DP!** Docela dobrý sell, obhajoba rozhodnutí.
- *UV coords:* Když se na portál podívám přímo zepředu (ortogonálně), tak ten indent není vubec vidět. Nejsem si jistý jestli to je k něčemu.. ten portálový mesh který jsem vzal z _simple portal sytem_ ani žádné UV coodinates nemá. Procedural mesh funguje hezky ✅
- Možná by se to hodilo kdyby měl portál "inactive" texturu... ale to se dá obejít placatým meshem narvaným před něj.. a neřešíš prohlubeň. Asi undefined behavior tady :D nechám na vývojářích
- Na to kolik jsem s tím teď zabil času, tak tohle je asi nanic. Prohlubeň je extrémně důležitá featura.
![portal-uv-coordinates](assets/portal-uv-coordinates.png)
- **Stíny** - shadow mesh tam můžu a nemusím plácnout (stejný jako hlavní). Další věc je že stíny by asi měly být na OFF a nebo DOUBLE_SIDED. Asi to nechám na uživateli.. to s meshem nesouvisí nutně.
### Texture portal mask :x:
Mám v plánu udělat texture masku pro tvarování protálů. S házením stínů to bude průser. V tomhle je přístup s _tvarem meshe_ lepší. Měl bych nakódit generování vícero tvarů...?
:exclamation: Tohle asi nebude fungovat kvůli té prohlubni
- Kdybys měl oblouk nahoře, tak nemůžeš jenom tak clipnout obdélníkový portál. Kdyby byl plochý, tak jo. Ale takhle bude ten okraj nahoře jakoby zabořený a nebude to pěkné (asi). Zvlášť v rožkách.
![round-portal-frame-square-portal-mesh](assets/round-portal-frame-square-portal-mesh.png)
:question: Tohle asi řeší tenký box s **culling- off** jak měl Sebastian ve svém Unity videu. Akorát to žere trochu renderingu.. ale v porovnání s X kamerama navíc je to asi fuk.
> BoxMesh3D mi nefunguje na hned. Ugh, nejsem si jistý proč.. ale mám dojem že ten chlapík co vyrobil ty portály by to asi zkusil. Prohlubeň možná dává smysl.
> Dal by se udělat celkem jednoduchý algoritmus co by generoval mesh "s prohlubní" pro jakýkoliv nákres zepředu. Obdélník je nejjednodušší, ale udělat oblouček by asi nebyl problém.
>
> Podobně jak se dá "kreslit" s CSG polygonem. Ale to by byl teda komplikovaný editor widget. Ty oblouky bysme asi chtěli hladké - to vypadá na něco na styl Curve editoru... ugh
>
> ![csg-polygon](assets/csg-polygon.png)
>
> [Cyclops Level Editor](https://github.com/blackears/cyclopsLevelBuilder/blob/master/doc/index.md#display-mode)
**Custom Mesh subclassa?**
- Custom mesh subclassa je trochu divná věc. Když to všechno nastaví jeden editorový Node tak to bude asi lepší. Custom mesh se mi přegenerovává při každém spuštění, ale já chci aby se prostě "zapekl" a uložil a nazdar bazar...
## Detekce teleportu
> Marek Zouhar: navrhuje predikovat jestli hráč projde portálem příští frame. Tohle by mohlo řešit
> clipping. Protože já vlastně toho hráče _doopravdy_ teleportuju až když je _za_ portálem.
>
> V tu chvilku už je pozdě!! A pak musím mít promáčklý mesh.
>
> S tímhle bych mohl mít prostě _plane mesh_.
> Potenciálně 2 plejny těsně za sebou abych předešel clippingu?

6
README.md Normal file
View File

@ -0,0 +1,6 @@
# Portals Demo
Git repos
- Gitea: https://git.vojtechstruhar.com/Vojta/dp-konzultace
- GitHub (mirror): https://github.com/VojtaStruhar/dp-konzultace

View File

@ -0,0 +1,49 @@
@tool
extends EditorPlugin
var editor_button_plugin:EditorButtonPlugin
func _enter_tree() -> void:
print("[inspector_buttons] enter")
editor_button_plugin = EditorButtonPlugin.new()
add_inspector_plugin(editor_button_plugin)
func _exit_tree() -> void:
if is_instance_valid(editor_button_plugin):
print("[inspector_buttons] exit")
remove_inspector_plugin(editor_button_plugin)
editor_button_plugin = null
class EditorButtonPlugin extends EditorInspectorPlugin:
func _can_handle(object: Object) -> bool:
return object.has_method('_add_inspector_buttons')
func _parse_begin(object: Object) -> void:
var buttons_data = object._add_inspector_buttons()
for button_data in buttons_data:
var name = button_data.get("name", null)
var icon = button_data.get("icon", null)
var pressed = button_data.get("pressed", null)
if not name:
push_warning('_add_inspector_buttons(): A button does not have a name key. Defaulting to: "Button"')
name = "Button"
if icon and not icon is Texture:
push_warning('_add_inspector_buttons(): The button <{name}> icon is not a texture.'.format({"name":name}))
icon = null
if not pressed:
push_warning('_add_inspector_buttons(): The button <{name}> does not have a pressed key. Skipping.'.format({"name":name}))
continue
if not pressed is Callable:
push_warning('_add_inspector_buttons(): The button <{name}> pressed is not a Callable. Skipping.'.format({"name":name}))
continue
var button = Button.new()
button.text = name
if icon:
button.icon = icon
button.expand_icon = true
button.pressed.connect(pressed)
add_custom_control(button)

View File

@ -0,0 +1 @@
uid://cmkf6s21ky7b5

View File

@ -0,0 +1,7 @@
[plugin]
name="Inspector Buttons"
description="Quick and dirty Godot inspector plugins. Taken from the internets"
author="mrcdk"
version="0.1"
script="inspector_buttons.gd"

View File

@ -0,0 +1,70 @@
extends EditorNode3DGizmoPlugin
func _init():
print("[gizmo] _init")
create_material("main", Color(1,0,1), false, true, false)
func _get_gizmo_name() -> String:
return "PortalGizmo"
func _has_gizmo(for_node_3d: Node3D) -> bool:
var result: bool = for_node_3d is Portal
return result
func _redraw(gizmo):
var portal = gizmo.get_node_3d() as Portal
gizmo.clear() # Always clear the gizmo
if portal not in EditorInterface.get_selection().get_selected_nodes():
return # If not selected, don't draw anything
var lines = PackedVector3Array()
if portal.exit_portal != null:
# Draw a bezier curve connecting the two portals
var exit = portal.exit_portal
var D = portal.global_position.distance_to(exit.global_position)
var p0 = portal.global_position
var p3 = exit.global_position
var p1 = p0 -portal.global_transform.basis.z * D * 0.25
var p2 = p3 -exit.global_transform.basis.z * D * 0.25
p0 = portal.to_local(p0)
p1 = portal.to_local(p1)
p2 = portal.to_local(p2)
p3 = portal.to_local(p3)
lines.push_back(p0)
const RESOLUTION: int = 24
for i in range(1, RESOLUTION + 1):
var t: float = float(i) / RESOLUTION
var spline_pos: Vector3 = pow(1 - t, 3) * p0 \
+ 3 * pow(1 - t, 2) * t * p1 \
+ 3 * (1 - t) * pow(t, 2) * p2 \
+ pow(t, 3) * p3
lines.push_back(spline_pos)
lines.push_back(spline_pos)
lines.push_back(p3)
#var handles = PackedVector3Array()
#handles.push_back(Vector3(0, 1, 0))
#handles.push_back(Vector3(0, 2, 0))
gizmo.add_lines(lines, get_material("main", gizmo))
# Thicker dashed line
var l2 = lines.duplicate()
for i in range(l2.size()): l2[i].x += 0.01
gizmo.add_lines(l2, get_material("main", gizmo))
#gizmo.add_handles(handles, get_material("handles", gizmo), [])

View File

@ -0,0 +1 @@
uid://b8vlwx31bxx4b

View File

@ -0,0 +1,7 @@
[plugin]
name="Portal Gizmos"
description="Plugin providing 3D Gizmos for portals"
author="Vojtech Struhar"
version="0.1"
script="portal_gizmos.gd"

View File

@ -0,0 +1,13 @@
@tool
extends EditorPlugin
const GIZMO_PACKED = preload("gizmo.gd")
var gizmo = GIZMO_PACKED.new()
func _enter_tree() -> void:
print("[portal_gizmos] Enter")
add_node_3d_gizmo_plugin(gizmo)
func _exit_tree() -> void:
print("[portal_gizmos] Exit")
remove_node_3d_gizmo_plugin(gizmo)

View File

@ -0,0 +1 @@
uid://c61kmx68labq0

View File

@ -11,16 +11,16 @@ extends Area3D
class_name AdvancedPortalTeleport
## Checks if the node is moving TOWARDS the portal before teleporting it.
@export var velocity_check:bool = true
@export var velocity_check: bool = true
## An additional velocity push given to RigidBody3Ds/CharacterBody3D exiting the portal.
@export var exit_push_velocity:float = 0
@export var exit_push_velocity: float = 0
## Seconds to keep portal clones visible after the node leaves the teleporter.
@export var clone_keep_alive_seconds:float = 0.1
@export var clone_keep_alive_seconds: float = 0.1
var _parent_portal:Portal
var _parent_portal: Portal
# Info about the nodes currently crossing the portal
var _crossing_nodes:Array = []
var _crossing_nodes: Array = []
func _ready() -> void:
_parent_portal = get_parent() as Portal
@ -30,10 +30,10 @@ func _ready() -> void:
connect("area_entered", _on_area_entered)
connect("area_exited", _on_area_exited)
func _process(delta:float) -> void:
func _process(delta: float) -> void:
# Update nodes crossing the portal
for i in range(_crossing_nodes.size() - 1, -1, -1):
var crossing_node:Dictionary = _crossing_nodes[i]
var crossing_node: Dictionary = _crossing_nodes[i]
if not is_instance_valid(crossing_node.node):
# Node has been freed, remove crossing_node
@ -61,17 +61,17 @@ func _process(delta:float) -> void:
_crossing_nodes.remove_at(i)
# Try to teleport the crossing node, and return false otherwise
func _try_teleport(crossing_node:Dictionary) -> bool:
var node:Node3D = crossing_node.node
func _try_teleport(crossing_node: Dictionary) -> bool:
var node: Node3D = crossing_node.node
# Check if the node is moving towards the portal
if velocity_check:
if node is RigidBody3D:
var local_velocity:Vector3 = _parent_portal.global_transform.basis.inverse() * node.linear_velocity
var local_velocity: Vector3 = _parent_portal.global_transform.basis.inverse() * node.linear_velocity
if local_velocity.z >= 0:
return false
elif node is CharacterBody3D:
var local_velocity:Vector3 = _parent_portal.global_transform.basis.inverse() * node.velocity
var local_velocity: Vector3 = _parent_portal.global_transform.basis.inverse() * node.velocity
if local_velocity.z >= 0:
return false
else:
@ -88,7 +88,7 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
# Additional push when exiting the portal
if exit_push_velocity > 0:
var exit_forward:Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
var exit_forward: Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
node.linear_velocity += exit_forward * exit_push_velocity
# Handle CharacterBody3D physics
@ -98,7 +98,7 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
# Additional push when exiting the portal
if exit_push_velocity > 0:
var exit_forward:Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
var exit_forward: Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
node.velocity += exit_forward * exit_push_velocity
# Transform the position and orientation
@ -106,22 +106,21 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
return true
func _on_area_entered(area:Area3D) -> void:
func _on_area_entered(area: Area3D) -> void:
if area.has_meta("teleportable_root"):
# The node may not teleport immediately if it's not heading TOWARDS the portal,
# so we keep a reference to it until it teleports or leaves.
# This also allows us to hide its portal clone after it leaves.
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
var crossing_node:Dictionary
var crossing_node: Dictionary
if root.has_meta("crossing_node"):
# Node is crossing another portal, erase it from that portal and start using this one instead
crossing_node = root.get_meta("crossing_node")
crossing_node.teleporter._crossing_nodes.erase(crossing_node)
else:
# First portal
var clone:Node3D = area.get_node(area.get_meta("portal_clone")) if area.has_meta("portal_clone") else null
var clone: Node3D = area.get_node(area.get_meta("portal_clone")) if area.has_meta("portal_clone") else null
crossing_node = {
"node": root,
"clone": clone,
@ -151,10 +150,10 @@ func _on_area_entered(area:Area3D) -> void:
crossing_node.clone_portal = _parent_portal.exit_portal
crossing_node.left = true
func _on_area_exited(area:Area3D) -> void:
func _on_area_exited(area: Area3D) -> void:
if area.has_meta("teleportable_root"):
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
var crossing_node:Dictionary = root.get_meta("crossing_node")
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
var crossing_node: Dictionary = root.get_meta("crossing_node")
if crossing_node.teleporter == self:
# The node left the enter portal without teleporting (but don't erase it yet)

View File

@ -11,18 +11,18 @@ extends Area3D
class_name CollisionDisableArea
## Seconds until collisions are re-enabled after the body leaves the area.
@export var re_enable_delay_seconds:float = 0.1
@export var re_enable_delay_seconds: float = 0.1
# Info about the disabled bodies
var _disables:Array = []
var _disables: Array = []
func _ready() -> void:
connect("body_entered", _on_body_entered)
connect("body_exited", _on_body_exited)
func _process(delta:float) -> void:
func _process(delta: float) -> void:
for i in range(_disables.size() - 1, -1, -1):
var disable_info:Dictionary = _disables[i]
var disable_info: Dictionary = _disables[i]
if not is_instance_valid(disable_info.body):
# Body has been freed, remove disable info
@ -50,7 +50,7 @@ func _process(delta:float) -> void:
# Final disable, so re-enable the collision mask
disable_info.body.set_collision_mask_value(layer_number, true)
func _on_body_entered(body:PhysicsBody3D) -> void:
func _on_body_entered(body: PhysicsBody3D) -> void:
if not body.has_meta("disabled_collision_masks"):
return
@ -65,10 +65,10 @@ func _on_body_entered(body:PhysicsBody3D) -> void:
# Keep track of the number of times each collision mask is disabled in a meta field
if not body.has_meta("collision_disable_count"):
body.set_meta("collision_disable_count", {})
var disable_count:Dictionary = body.get_meta("collision_disable_count")
var disable_count: Dictionary = body.get_meta("collision_disable_count")
# Disable the collision masks specified in the "disabled_collision_masks" metadata array
var disabled_layers:Array = body.get_meta("disabled_collision_masks")
var disabled_layers: Array = body.get_meta("disabled_collision_masks")
for layer_number in disabled_layers:
# Only consider layers which were enabled to begin with
if disable_count.has(layer_number) or body.get_collision_mask_value(layer_number):
@ -87,7 +87,7 @@ func _on_body_entered(body:PhysicsBody3D) -> void:
"left": false,
})
func _on_body_exited(body:PhysicsBody3D) -> void:
func _on_body_exited(body: PhysicsBody3D) -> void:
if body.has_meta("disabled_collision_masks"):
for disable_info in _disables:
if disable_info.body == body:

View File

@ -9,16 +9,16 @@
extends RigidBody3D
class_name Hoverable
@onready var _mesh:MeshInstance3D = $Mesh
@onready var _mesh: MeshInstance3D = $Mesh
var hovered:bool
var hovered: bool
var _strength:float
var _strength: float
func _ready() -> void:
_mesh.material_override = _mesh.mesh.surface_get_material(0).duplicate()
func _process(delta:float) -> void:
func _process(delta: float) -> void:
_strength = min(1, _strength + delta * 10) if hovered else max(0, _strength - delta * 10)
_mesh.material_override.albedo_color = lerp(Color.WHITE, Color.RED, _strength)

View File

@ -9,15 +9,15 @@
extends MeshInstance3D
class_name LineRenderer
@export var material:Material
@export var material: Material
var _lines:Array
var _dirty:bool
var _lines: Array
var _dirty: bool
func _ready() -> void:
mesh = ImmediateMesh.new()
func add_line(from:Vector3, to:Vector3, color:Color = Color.WHITE) -> void:
func add_line(from: Vector3, to: Vector3, color: Color = Color.WHITE) -> void:
_lines.push_back([from, to, color])
_dirty = true
@ -25,7 +25,7 @@ func clear_lines() -> void:
_lines.clear()
_dirty = true
func _process(_delta:float) -> void:
func _process(_delta: float) -> void:
if not _dirty:
return
_dirty = false

View File

@ -8,18 +8,18 @@
extends MeshInstance3D
const _MOUSE_PAN_THRESHOLD:float = 0.4;
const _MOUSE_PAN_SPEED:float = 200
const _MOUSE_PAN_THRESHOLD: float = 0.4;
const _MOUSE_PAN_SPEED: float = 200
const _MOVE_SPEED:float = 4
const _MOVE_SPEED: float = 4
var _mouse_look:Vector2
var _mouse_look: Vector2
@onready var _line_renderer:LineRenderer = $"../LineRenderer"
@onready var _camera:Camera3D = $Camera
@onready var _pip_camera:Camera3D = $PipViewport1/Camera
@onready var _line_renderer: LineRenderer = $"../LineRenderer"
@onready var _camera: Camera3D = $Camera
@onready var _pip_camera: Camera3D = $PipViewport1/Camera
@onready var _handle_raycast_callable:Callable = Callable(self, "_handle_raycast")
@onready var _handle_raycast_callable: Callable = Callable(self, "_handle_raycast")
func _ready() -> void:
set_layer_mask_value(1, false)
@ -27,16 +27,16 @@ func _ready() -> void:
_camera.set_cull_mask_value(2, false)
func _process(delta:float) -> void:
var viewport:Viewport = get_viewport()
var mouse_position:Vector2 = viewport.get_mouse_position()
var viewport_size:Vector2i = viewport.size
var normalized_mouse_position:Vector2 = mouse_position / Vector2(viewport_size)
func _process(delta: float) -> void:
var viewport: Viewport = get_viewport()
var mouse_position: Vector2 = viewport.get_mouse_position()
var viewport_size: Vector2i = viewport.size
var normalized_mouse_position: Vector2 = mouse_position / Vector2(viewport_size)
var horizontal_speed:float = 0
var vertical_speed:float = 0
var horizontal_speed: float = 0
var vertical_speed: float = 0
if normalized_mouse_position.x > 0 and normalized_mouse_position.x < 1 and\
if normalized_mouse_position.x > 0 and normalized_mouse_position.x < 1 and \
normalized_mouse_position.y > 0 and normalized_mouse_position.y < 1:
if normalized_mouse_position.x < _MOUSE_PAN_THRESHOLD:
horizontal_speed = lerp(0, 1, _MOUSE_PAN_THRESHOLD - normalized_mouse_position.x)
@ -53,15 +53,15 @@ func _process(delta:float) -> void:
rotation_degrees = Vector3(0, _mouse_look.x, 0)
_camera.rotation_degrees = Vector3(_mouse_look.y, 0, 0)
var right:Vector3 = (global_transform.basis.x * Vector3(1, 0, 1)).normalized()
var forward:Vector3 = (global_transform.basis.z * Vector3(1, 0, 1)).normalized()
var right: Vector3 = (global_transform.basis.x * Vector3(1, 0, 1)).normalized()
var forward: Vector3 = (global_transform.basis.z * Vector3(1, 0, 1)).normalized()
if Input.is_key_pressed(KEY_LEFT) or Input.is_key_pressed(KEY_A):
global_translate(-right * _MOVE_SPEED * delta)
global_translate(- right * _MOVE_SPEED * delta)
if Input.is_key_pressed(KEY_RIGHT) or Input.is_key_pressed(KEY_D):
global_translate(right * _MOVE_SPEED * delta)
if Input.is_key_pressed(KEY_UP) or Input.is_key_pressed(KEY_W):
global_translate(-forward * _MOVE_SPEED * delta)
global_translate(- forward * _MOVE_SPEED * delta)
if Input.is_key_pressed(KEY_DOWN) or Input.is_key_pressed(KEY_S):
global_translate(forward * _MOVE_SPEED * delta)
@ -75,16 +75,16 @@ func _process(delta:float) -> void:
_pip_camera.global_position = _camera.to_global(Vector3(0, 1.5, 1.5))
_pip_camera.global_rotation = _camera.global_rotation
var origin:Vector3 = _camera.project_ray_origin(mouse_position)
var end:Vector3 = origin + _camera.project_ray_normal(mouse_position) * 100
var origin: Vector3 = _camera.project_ray_origin(mouse_position)
var end: Vector3 = origin + _camera.project_ray_normal(mouse_position) * 100
_line_renderer.clear_lines()
Portal.raycast(get_tree(), origin, (end - origin).normalized(), _handle_raycast_callable)
func _handle_raycast(from:Vector3, dir:Vector3, segment_distance:float, _recursive_distance:float, recursions:int) -> bool:
var distance:float = min(100, segment_distance)
var target:Vector3 = from + dir * distance
func _handle_raycast(from: Vector3, dir: Vector3, segment_distance: float, _recursive_distance: float, recursions: int) -> bool:
var distance: float = min(100, segment_distance)
var target: Vector3 = from + dir * distance
_line_renderer.add_line(from, target, Color.GREEN)
for i in 16:
@ -98,9 +98,9 @@ func _handle_raycast(from:Vector3, dir:Vector3, segment_distance:float, _recursi
randf_range(-0.1, 0.1),
randf_range(-0.1, 0.1)), Color.BLUE)
var space_state:PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
var query:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, from + dir * distance)
var result:Dictionary = space_state.intersect_ray(query)
var space_state: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
var query: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, from + dir * distance)
var result: Dictionary = space_state.intersect_ray(query)
if not result.is_empty() and result.collider is Hoverable:
result.collider.hovered = true
for i in 16:

View File

@ -12,56 +12,56 @@ class_name Portal
## The portal represents a single portal mesh in a pair of portals.
## The delay between the main viewport changing size and the portal viewport resizing.
const _RESIZE_THROTTLE_SECONDS:float = 0.1
const _RESIZE_THROTTLE_SECONDS: float = 0.1
## The minimum camera near clipping distance.
const _EXIT_CAMERA_NEAR_MIN:float = 0.01
const _EXIT_CAMERA_NEAR_MIN: float = 0.01
## The portal mesh's local bounding box.
@onready var _mesh_aabb:AABB = mesh.get_aabb()
@onready var _mesh_aabb: AABB = mesh.get_aabb()
## The vertical resolution of the portal viewport which covers the entire screen not just the portal mesh. Use 0 to use the real resolution.
@export var vertical_viewport_resolution:int = 512
@export var vertical_viewport_resolution: int = 512
## Disable viewport distance. Portals further away than this won't have their viewports rendered.
@export var disable_viewport_distance:float = 11
@export var disable_viewport_distance: float = 11
## Whether to destroy the disabled viewport to save texture memory. Useful when you have a lot of portals. The viewport is re/-created when within disable_viewport_distance and visible.
@export var destroy_disabled_viewport:bool = true
@export var destroy_disabled_viewport: bool = true
## The maximum fade-out distance.
@export var fade_out_distance_max:float = 10
@export var fade_out_distance_max: float = 10
## The minimum fade-out distance.
@export var fade_out_distance_min:float = 8
@export var fade_out_distance_min: float = 8
## The fade-out color.
@export var fade_out_color:Color = Color.WHITE
@export var fade_out_color: Color = Color.WHITE
## The scale of the exit side of the portal. < 1 means the exit is smaller than the entrance.
@export var exit_scale:float = 1.0
@export var exit_scale: float = 1.0
## A value subtracted from the exit camera near clipping plane. Useful for handling clipping issues.
@export var exit_near_subtract:float = 0.05
@export var exit_near_subtract: float = 0.05
## The main camera. Leave unset to use the default 3D camera.
@export var main_camera:Camera3D
@export var main_camera: Camera3D
## An environment set for the exit camera. Leave unset to use the default environment.
@export var exit_environment:Environment
@export var exit_environment: Environment
## The cull mask for the exit camera. Use it to hide certain objects in the exit camera.
@export_flags_3d_render var exit_cull_mask:int = 0b11111111111111111111
@export_flags_3d_render var exit_cull_mask: int = 0b11111111111111111111
## The exit portal. Leave unset to use this portal as an exit only.
@export var exit_portal:Portal
@export var exit_portal: Portal
## An environment set for the exit camera. Leave unset to use the default environment.
@export var portal_shader:Shader = preload("res://addons/simple-portal-system/shaders/portal.gdshader")
@export var portal_shader: Shader = preload("res://addons/simple-portal-system/shaders/portal.gdshader")
# The viewport rendering the portal surface
var _viewport:SubViewport
var _viewport: SubViewport
# The exit camera copies the main camera's position relative to the exit portal
var _exit_camera:Camera3D
var _exit_camera: Camera3D
# The number of seconds until the viewport updates its size
var _seconds_until_resize:float
var _seconds_until_resize: float
func _enter_tree() -> void:
add_to_group("portals")
@ -81,7 +81,7 @@ func _ready() -> void:
# Non-uniform parent scaling can introduce skew which isn't compensated for
if get_parent() != null:
var parent_scale:Vector3 = get_parent().global_transform.basis.get_scale()
var parent_scale: Vector3 = get_parent().global_transform.basis.get_scale()
if abs(parent_scale.x - parent_scale.y) > 0.01 or abs(parent_scale.x - parent_scale.z) > 0.01:
push_warning("The parent of \"%s\" is not uniformly scaled. The portal will not work correctly." % name)
@ -105,7 +105,7 @@ func _ready() -> void:
# Create the viewport when _ready if it's not destroyed when disabled.
# This may potentially get rid of the initial lag when the viewport is first created at the cost of texture memory.
if not destroy_disabled_viewport:
_create_viewport()
_createa_viewport()
get_viewport().connect("size_changed", _handle_resize)
@ -130,9 +130,9 @@ func _create_viewport() -> void:
# Resize the viewport on the next _process
_seconds_until_resize = 0
func _process(delta:float) -> void:
func _process(delta: float) -> void:
# Disable the viewport if the portal is further away than disable_viewport_distance or if the portal is invisible in the scene tree
var disable_viewport:bool = not is_visible_in_tree() or\
var disable_viewport: bool = not is_visible_in_tree() or \
main_camera.global_position.distance_squared_to(global_position) > disable_viewport_distance * disable_viewport_distance
# Enable or disable 3D rendering for the viewport (if it exists)
@ -163,13 +163,13 @@ func _process(delta:float) -> void:
if _seconds_until_resize <= 0:
_seconds_until_resize = NAN
var viewport_size:Vector2i = get_viewport().size
var viewport_size: Vector2i = get_viewport().size
if vertical_viewport_resolution == 0:
# Resize the viewport to the main viewport size
_viewport.size = viewport_size
else:
# Resize the viewport to the fixed height vertical_viewport_resolution and dynamic width
var aspect_ratio:float = float(viewport_size.x) / viewport_size.y
var aspect_ratio: float = float(viewport_size.x) / viewport_size.y
_viewport.size = Vector2i(int(vertical_viewport_resolution * aspect_ratio + 0.5), vertical_viewport_resolution)
# Move the exit camera relative to the exit portal based on the main camera's position relative to the entrance portal
@ -177,18 +177,18 @@ func _process(delta:float) -> void:
# Get the four X, Y corners of the scaled entrance portal bounding box clamped to Z=0 (portal surface) relative to the exit portal.
# The entrance portal bounding box is used since the entrance portal mesh does not need to match the exit portal mesh.
var corner_1:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y, 0) * exit_scale)
var corner_2:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y, 0) * exit_scale)
var corner_3:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
var corner_4:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
var corner_1: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y, 0) * exit_scale)
var corner_2: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y, 0) * exit_scale)
var corner_3: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
var corner_4: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
# Calculate the distance along the exit camera forward vector at which each of the portal corners projects
var camera_forward:Vector3 = -_exit_camera.global_transform.basis.z.normalized()
var camera_forward: Vector3 = - _exit_camera.global_transform.basis.z.normalized()
var d_1:float = (corner_1 - _exit_camera.global_position).dot(camera_forward)
var d_2:float = (corner_2 - _exit_camera.global_position).dot(camera_forward)
var d_3:float = (corner_3 - _exit_camera.global_position).dot(camera_forward)
var d_4:float = (corner_4 - _exit_camera.global_position).dot(camera_forward)
var d_1: float = (corner_1 - _exit_camera.global_position).dot(camera_forward)
var d_2: float = (corner_2 - _exit_camera.global_position).dot(camera_forward)
var d_3: float = (corner_3 - _exit_camera.global_position).dot(camera_forward)
var d_4: float = (corner_4 - _exit_camera.global_position).dot(camera_forward)
# The near clip distance is the shortest distance which still contains all the corners
_exit_camera.near = max(_EXIT_CAMERA_NEAR_MIN, min(d_1, d_2, d_3, d_4) - exit_near_subtract)
@ -197,60 +197,60 @@ func _process(delta:float) -> void:
_exit_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:
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
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())
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)
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)
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
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:
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
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()
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
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
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:
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
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()
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)
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
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
var local_at_exit: Vector3 = exit_portal.global_transform.basis * scaled_at_exit
return local_at_exit
## Raycast against portals (See instructions).
static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Callable,
max_distance:float = INF, max_recursions:int = 16, ignore_backside:bool = true) -> void:
var portals:Array = tree.get_nodes_in_group("portals")
var ignore_portal:Portal = null
var recursive_distance:float = 0
static func raycast(tree: SceneTree, from: Vector3, dir: Vector3, handle_raycast: Callable,
max_distance: float = INF, max_recursions: int = 16, ignore_backside: bool = true) -> void:
var portals: Array = tree.get_nodes_in_group("portals")
var ignore_portal: Portal = null
var recursive_distance: float = 0
for r in max_recursions + 1:
var closest_hit:Vector3
var closest_dir:Vector3
var closest_portal:Portal
var closest_distance_sqr:float = INF
var closest_hit: Vector3
var closest_dir: Vector3
var closest_portal: Portal
var closest_distance_sqr: float = INF
# Find the closest portal the ray intersects
for portal in portals:
@ -258,8 +258,8 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
if portal == ignore_portal or not portal.is_inside_tree() or tree != portal.get_tree() or not portal.is_visible_in_tree():
continue
var local_from:Vector3 = portal.to_local(from)
var local_dir:Vector3 = portal.global_transform.basis.inverse() * dir
var local_from: Vector3 = portal.to_local(from)
var local_dir: Vector3 = portal.global_transform.basis.inverse() * dir
# Check if ray is parallel to the portal
if local_dir.z == 0:
@ -270,22 +270,22 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
continue
# Get the intersection point of the ray with the Z axis
var t:float = -local_from.z / local_dir.z
var t: float = - local_from.z / local_dir.z
# Is the intersection behind the start position?
if t < 0:
continue
# Check if the ray hit inside the portal bounding box (ignoring Z)
var local_hit:Vector3 = local_from + t * local_dir
var aabb:AABB = portal._mesh_aabb
if local_hit.x < aabb.position.x or local_hit.x > aabb.position.x + aabb.size.x or\
var local_hit: Vector3 = local_from + t * local_dir
var aabb: AABB = portal._mesh_aabb
if local_hit.x < aabb.position.x or local_hit.x > aabb.position.x + aabb.size.x or \
local_hit.y < aabb.position.y or local_hit.y > aabb.position.y + aabb.size.y:
continue
# Check if this was the closest portal
var hit:Vector3 = portal.to_global(local_hit)
var distance_sqr:float = hit.distance_squared_to(from)
var hit: Vector3 = portal.to_global(local_hit)
var distance_sqr: float = hit.distance_squared_to(from)
if distance_sqr < closest_distance_sqr:
closest_hit = hit
closest_dir = dir
@ -293,7 +293,7 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
closest_portal = portal
# Calculate the ray distance
var hit_distance:float = INF if is_inf(closest_distance_sqr) else sqrt(closest_distance_sqr)
var hit_distance: float = INF if is_inf(closest_distance_sqr) else sqrt(closest_distance_sqr)
# Call the user-defined raycast function
if handle_raycast.call(from, dir, hit_distance, recursive_distance, r):

View File

@ -22,9 +22,11 @@ func _ready():
func _on_area_entered(area: Area3D) -> void:
if area.has_meta("teleportable_root"):
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
print("[%f] Teleporting %s to %s" % [roundi(Time.get_ticks_msec() / 100) / 10.0, root.name, _parent_portal.exit_portal.name])
root.global_transform = _parent_portal.real_to_exit_transform(root.global_transform)
func _on_body_entered(body: Node3D) -> void:
if body.get_meta("teleportable", false) == true:
body.global_transform = _parent_portal.real_to_exit_transform(body.global_transform)
print("Teleporting %s to %s" % [body.name, _parent_portal.exit_portal.name])

View File

@ -9,6 +9,7 @@
shader_type spatial;
render_mode unshaded;
uniform float fade_out_distance_max = 10.0;
uniform float fade_out_distance_min = 8.0;
uniform vec4 fade_out_color = vec4(0.0);

0
assets/.gdignore Normal file
View File

BIN
assets/csg-polygon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 KiB

6
hud.gd
View File

@ -1,13 +1,17 @@
extends VBoxContainer
@onready var fps_label: Label = $FPS_Label
func _ready() -> void:
toggle_hud() # This should hide the HUD by default
fps_label.reparent.call_deferred(get_parent())
func _process(delta: float) -> void:
func _process(_delta: float) -> void:
if Input.is_action_just_pressed("ui_cancel"):
toggle_hud()
fps_label.text = "FPS: %d" % Engine.get_frames_per_second()
func toggle_hud() -> void:
var should_show = Input.mouse_mode == Input.MOUSE_MODE_CAPTURED

View File

@ -12,6 +12,10 @@ unique_name_in_owner = true
layout_mode = 2
text = "Back to Menu"
[node name="FPS_Label" type="Label" parent="."]
layout_mode = 2
text = "FPS: -1"
[node name="HSeparator" type="HSeparator" parent="."]
layout_mode = 2

View File

@ -1,12 +1,12 @@
[gd_scene load_steps=12 format=3 uid="uid://27pb62xwsqd8"]
[gd_scene load_steps=14 format=4 uid="uid://27pb62xwsqd8"]
[ext_resource type="PackedScene" uid="uid://b5x7fmpwck335" path="res://hud.tscn" id="1_mmt1i"]
[ext_resource type="MeshLibrary" uid="uid://bedqgubx1g1uf" path="res://prototypes.tres" id="2_vdsn8"]
[ext_resource type="ArrayMesh" uid="uid://bqilnvlfws6xh" path="res://portal-mesh.tres" id="3_c4jka"]
[ext_resource type="Script" uid="uid://d2bvvjsibau8c" path="res://addons/simple-portal-system/scripts/portal.gd" id="4_top28"]
[ext_resource type="Script" uid="uid://bkv7t4hw21byg" path="res://addons/simple-portal-system/scripts/simple_portal_teleport.gd" id="5_evjit"]
[ext_resource type="PackedScene" uid="uid://cgdlowfuuorvi" path="res://player.tscn" id="6_hlt8e"]
[ext_resource type="Script" uid="uid://cili3lyodjqel" path="res://portal_environment_adapter.gd" id="7_2gewm"]
[ext_resource type="PackedScene" uid="uid://d1dtxvwk86ple" path="res://procedural_mesh_maker.tscn" id="8_vdsn8"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_b0o0q"]
sky_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
@ -22,9 +22,37 @@ tonemap_mode = 3
tonemap_exposure = 1.5
glow_enabled = true
[sub_resource type="ArrayMesh" id="ArrayMesh_vdsn8"]
_surfaces = [{
"aabb": AABB(-1, -1, -0.1, 2, 2, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD/NzEw9zcxMPTMzcz/NzEw9zcxMPTMzcz8zM3M/MzNzPw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AACAvwAAgD8AAAAAAACAPwAAgD8AAAAAAACAvwAAgL8AAAAAAACAPwAAgL8AAAAAZmZmv2ZmZj/NzMy9ZmZmP2ZmZj/NzMy9ZmZmv2ZmZr/NzMy9ZmZmP2ZmZr/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[sub_resource type="BoxShape3D" id="BoxShape3D_cgnft"]
size = Vector3(2, 2, 0.5)
[sub_resource type="ArrayMesh" id="ArrayMesh_mmt1i"]
_surfaces = [{
"aabb": AABB(-1, -1, -0.1, 2, 2, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD/NzEw9zcxMPTMzcz/NzEw9zcxMPTMzcz8zM3M/MzNzPw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AACAvwAAgD8AAAAAAACAPwAAgD8AAAAAAACAvwAAgL8AAAAAAACAPwAAgL8AAAAAZmZmv2ZmZj/NzMy9ZmZmP2ZmZj/NzMy9ZmZmv2ZmZr/NzMy9ZmZmP2ZmZr/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[node name="level_3rooms" type="Node3D"]
[node name="HUD" parent="." instance=ExtResource("1_mmt1i")]
@ -44,7 +72,7 @@ metadata/_editor_floor_ = Vector3(0, 3, 0)
[node name="Portal_red" type="MeshInstance3D" parent="." node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -0.5, 2, -4)
mesh = ExtResource("3_c4jka")
mesh = SubResource("ArrayMesh_vdsn8")
skeleton = NodePath("")
script = ExtResource("4_top28")
vertical_viewport_resolution = 1080
@ -63,7 +91,7 @@ shape = SubResource("BoxShape3D_cgnft")
[node name="Portal_orange" type="MeshInstance3D" parent="." node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 2, -0.5)
mesh = ExtResource("3_c4jka")
mesh = SubResource("ArrayMesh_mmt1i")
skeleton = NodePath("")
script = ExtResource("4_top28")
vertical_viewport_resolution = 1080
@ -104,3 +132,7 @@ omni_range = 4.0
[node name="PortalEnvironmentAdapter" type="Node" parent="." node_paths=PackedStringArray("base")]
script = ExtResource("7_2gewm")
base = NodePath("../WorldEnvironment")
[node name="ProceduralMeshMaker" parent="." node_paths=PackedStringArray("portal") instance=ExtResource("8_vdsn8")]
portal = NodePath("../Portal_orange")
width = 2.0

File diff suppressed because one or more lines are too long

31
levels/level_hermione.gd Normal file
View File

@ -0,0 +1,31 @@
extends Node
@onready var player: CharacterBody3D = %Player
@onready var outside_world: SubViewport = %OutsideWorld
@onready var inside_world: SubViewport = %InsideWorld
@onready var sub_viewport_container: SubViewportContainer = $SubViewportContainer
var current_world: Node
func _ready() -> void:
current_world = outside_world
func _process(delta: float) -> void:
if Input.is_action_just_pressed("debug_teleport"):
_on_teleport_button_pressed()
func _on_teleport_button_pressed() -> void:
if current_world == outside_world:
outside_world.reparent(self)
inside_world.reparent(sub_viewport_container)
current_world = inside_world
else:
inside_world.reparent(self)
outside_world.reparent(sub_viewport_container)
current_world = outside_world
player.reparent(current_world.get_child(0))

View File

@ -0,0 +1 @@
uid://ca45js46kc0l7

View File

@ -0,0 +1,48 @@
[gd_scene load_steps=6 format=3 uid="uid://dgvdetmbv5jya"]
[ext_resource type="PackedScene" uid="uid://b5x7fmpwck335" path="res://hud.tscn" id="1_2k7q4"]
[ext_resource type="Script" uid="uid://ca45js46kc0l7" path="res://levels/level_hermione.gd" id="1_gyvwl"]
[ext_resource type="PackedScene" uid="uid://drhaqr78kv1o2" path="res://levels/room_hermione_outside.tscn" id="2_empe6"]
[ext_resource type="PackedScene" uid="uid://ci81nttn6foio" path="res://levels/room_hermione_inside.tscn" id="2_lv1mc"]
[ext_resource type="PackedScene" uid="uid://cgdlowfuuorvi" path="res://player.tscn" id="3_gyvwl"]
[node name="level_hermione" type="Node"]
script = ExtResource("1_gyvwl")
[node name="SubViewportContainer" type="SubViewportContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="OutsideWorld" type="SubViewport" parent="SubViewportContainer"]
unique_name_in_owner = true
handle_input_locally = false
size = Vector2i(1920, 1080)
render_target_update_mode = 4
[node name="OutsideWorldContainer" type="Node3D" parent="SubViewportContainer/OutsideWorld"]
[node name="room_hermione_outside" parent="SubViewportContainer/OutsideWorld/OutsideWorldContainer" instance=ExtResource("2_empe6")]
[node name="Player" parent="SubViewportContainer/OutsideWorld/OutsideWorldContainer" instance=ExtResource("3_gyvwl")]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.08041, 1.41104, 0)
[node name="HUD" parent="." instance=ExtResource("1_2k7q4")]
[node name="TeleportButton" type="Button" parent="HUD"]
layout_mode = 2
text = "Switch Worlds (T)"
[node name="InsideWorld" type="SubViewport" parent="."]
unique_name_in_owner = true
own_world_3d = true
size = Vector2i(1920, 1080)
[node name="InsideWorldContainer" type="Node3D" parent="InsideWorld"]
[node name="room_hermione_inside" parent="InsideWorld/InsideWorldContainer" instance=ExtResource("2_lv1mc")]
[connection signal="pressed" from="HUD/TeleportButton" to="." method="_on_teleport_button_pressed"]

View File

@ -0,0 +1,15 @@
extends Node3D
@onready var orange: Node3D = $Orange
@onready var green: Node3D = $Green
@onready var player: CharacterBody3D = $Player
func _on_transport_to_orange_pressed() -> void:
player.global_position = orange.global_position
player.global_position.y += 10
func _on_transport_to_green_pressed() -> void:
player.global_position = green.global_position
player.global_position.y += 10

View File

@ -0,0 +1 @@
uid://c8vjum7jkvrv0

View File

@ -0,0 +1,269 @@
[gd_scene load_steps=25 format=4 uid="uid://rlienyx6av8u"]
[ext_resource type="PackedScene" uid="uid://cxopylew5786r" path="res://portal_environment_adapter.tscn" id="1_eoaoo"]
[ext_resource type="Script" uid="uid://c8vjum7jkvrv0" path="res://levels/level_my_portals.gd" id="1_pccqs"]
[ext_resource type="Material" uid="uid://bx6qeabdhq2s" path="res://addons/kenney_prototype_tools/materials/dark/material_01.tres" id="1_v6nyh"]
[ext_resource type="Material" uid="uid://dn16yhnqtqh7i" path="res://addons/kenney_prototype_tools/materials/orange/material_02.tres" id="2_5nkxg"]
[ext_resource type="PackedScene" uid="uid://cgdlowfuuorvi" path="res://player.tscn" id="3_ysrn6"]
[ext_resource type="PackedScene" uid="uid://b5x7fmpwck335" path="res://hud.tscn" id="4_t21k5"]
[ext_resource type="Material" uid="uid://oob6p5w3hsl5" path="res://addons/kenney_prototype_tools/materials/red/material_09.tres" id="6_2ffpc"]
[ext_resource type="Material" uid="uid://b7kc8jfs4fowj" path="res://addons/kenney_prototype_tools/materials/green/material_02.tres" id="6_b88kk"]
[ext_resource type="Script" uid="uid://dh8miiv7xc4ps" path="res://scripts/my_portal.gd" id="7_pvdtj"]
[ext_resource type="Material" uid="uid://ci8rdsdqe5a61" path="res://addons/kenney_prototype_tools/materials/light/material_06.tres" id="8_dhtg5"]
[ext_resource type="PackedScene" uid="uid://d1dtxvwk86ple" path="res://procedural_mesh_maker.tscn" id="9_dhtg5"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_t21k5"]
sky_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
ground_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
[sub_resource type="Sky" id="Sky_eoaoo"]
sky_material = SubResource("ProceduralSkyMaterial_t21k5")
[sub_resource type="Environment" id="Environment_b88kk"]
background_mode = 2
sky = SubResource("Sky_eoaoo")
glow_enabled = true
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_7nftg"]
data = PackedVector3Array(-9, -1.5, -9, -10, -1.5, -10, -9, -1.5, 9, -10, -1.5, 10, -10, -1.5, -10, -10, 1.5, -10, -10, -1.5, -10, -9, -1.5, -9, 9, -1.5, -9, 10, -1.5, -10, -10, 1.5, -10, -10, -1.5, -10, -9, -1.5, 9, -10, -1.5, -10, -10, -1.5, 10, 10, -1.5, 10, -9, -1.5, 9, -10, -1.5, 10, -9, 1.5, -9, -10, 1.5, 10, -10, 1.5, -10, 10, 1.5, -10, -9, 1.5, -9, -10, 1.5, -10, -10, 1.5, -10, -10, 1.5, 10, -10, -1.5, 10, -9, 1.5, 9, -10, 1.5, 10, -9, 1.5, -9, -10, 1.5, 10, 10, 1.5, 10, -10, -1.5, 10, -10, 1.5, 10, -9, 1.5, 9, 9, 1.5, 9, -10, -1.5, -10, 9, -1.5, -9, 10, -1.5, -10, 9, -1.5, -9, 10, -1.5, 10, 10, -1.5, -10, 10, -1.5, 10, 9, -1.5, 9, -9, -1.5, 9, 10, 1.5, 10, 10, -1.5, 10, -10, -1.5, 10, 9, -1.5, 9, 10, -1.5, 10, 9, -1.5, -9, 10, -1.5, 10, 10, 1.5, 10, 10, -1.5, -10, 10, -1.5, -10, 10, 1.5, -10, -10, 1.5, -10, 10, 1.5, -10, 9, 1.5, -9, -9, 1.5, -9, 10, 1.5, 10, 10, 1.5, -10, 10, -1.5, -10, 9, 1.5, -9, 10, 1.5, -10, 9, 1.5, 9, -10, 1.5, 10, 9, 1.5, 9, 10, 1.5, 10, 9, 1.5, 9, 10, 1.5, -10, 10, 1.5, 10, -9, 1.5, -9, -9, -1.5, -9, -9, -1.5, 9, 9, -1.5, -9, -9, -1.5, -9, -9, 1.5, -9, -9, -1.5, 9, -9, 1.5, 9, -9, 1.5, -9, 9, 1.5, 9, -9, 1.5, 9, -9, -1.5, 9, -9, -1.5, 9, 9, -1.5, 9, 9, 1.5, 9, 9, 1.5, 9, 9, -1.5, 9, 9, -1.5, -9, -9, 1.5, -9, 9, 1.5, -9, 9, -1.5, -9, 9, -1.5, -9, 9, 1.5, -9, 9, 1.5, 9)
[sub_resource type="ArrayMesh" id="ArrayMesh_v6nyh"]
_surfaces = [{
"aabb": AABB(-10, -1.5, -10, 20, 3, 20),
"attribute_data": PackedByteArray("MzNzP83MTD0AAIA/AAAAAM3MTD3NzEw9AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAzM3M/zcxMPTMzcz8zM3M/AAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAzcxMPc3MTD0AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD/NzEw9zcxMPQAAAAAAAAAAMzNzPzMzcz8AAAAAAACAPwAAgD8AAIA/AACAPwAAAAAzM3M/MzNzPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/zcxMPTMzcz8AAAAAAACAPzMzcz8zM3M/AACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAgD/NzEw9MzNzP83MTD3NzEw9AACAPwAAAAAzM3M/MzNzPwAAgD8AAIA/MzNzPzMzcz8AAAAAAACAPwAAgD8AAIA/AAAAAAAAgD/NzEw9MzNzP83MTD3NzEw9AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/zcxMPTMzcz8AAAAAAACAPzMzcz8zM3M/AACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAzM3M/zcxMPTMzcz8zM3M/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/MzNzP83MTD0AAIA/AAAAAM3MTD3NzEw9AAAAAAAAgD/NzEw9zcxMPQAAAAAAAAAAzcxMPc3MTD0AAIA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAIA/AAAAAAAAAAAAAIA/AAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAACAPwAAAAAAAAAAAACAPwAAgD8AAAAAAACAPwAAAAAAAAAA"),
"format": 34359738391,
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 96,
"vertex_data": PackedByteArray("AAAQwQAAwL8AABDBAAAgwQAAwL8AACDBAAAQwQAAwL8AABBBAAAgwQAAwL8AACBBAAAgwQAAwL8AACDBAAAgwQAAwD8AACDBAAAgwQAAwL8AACDBAAAQwQAAwL8AABDBAAAQQQAAwL8AABDBAAAgQQAAwL8AACDBAAAgwQAAwD8AACDBAAAgwQAAwL8AACDBAAAQwQAAwL8AABBBAAAgwQAAwL8AACDBAAAgwQAAwL8AACBBAAAgQQAAwL8AACBBAAAQwQAAwL8AABBBAAAgwQAAwL8AACBBAAAQwQAAwD8AABDBAAAgwQAAwD8AACBBAAAgwQAAwD8AACDBAAAgQQAAwD8AACDBAAAQwQAAwD8AABDBAAAgwQAAwD8AACDBAAAgwQAAwD8AACDBAAAgwQAAwD8AACBBAAAgwQAAwL8AACBBAAAQwQAAwD8AABBBAAAgwQAAwD8AACBBAAAQwQAAwD8AABDBAAAgwQAAwD8AACBBAAAgQQAAwD8AACBBAAAgwQAAwL8AACBBAAAgwQAAwD8AACBBAAAQwQAAwD8AABBBAAAQQQAAwD8AABBBAAAgwQAAwL8AACDBAAAQQQAAwL8AABDBAAAgQQAAwL8AACDBAAAQQQAAwL8AABDBAAAgQQAAwL8AACBBAAAgQQAAwL8AACDBAAAgQQAAwL8AACBBAAAQQQAAwL8AABBBAAAQwQAAwL8AABBBAAAgQQAAwD8AACBBAAAgQQAAwL8AACBBAAAgwQAAwL8AACBBAAAQQQAAwL8AABBBAAAgQQAAwL8AACBBAAAQQQAAwL8AABDBAAAgQQAAwL8AACBBAAAgQQAAwD8AACBBAAAgQQAAwL8AACDBAAAgQQAAwL8AACDBAAAgQQAAwD8AACDBAAAgwQAAwD8AACDBAAAgQQAAwD8AACDBAAAQQQAAwD8AABDBAAAQwQAAwD8AABDBAAAgQQAAwD8AACBBAAAgQQAAwD8AACDBAAAgQQAAwL8AACDBAAAQQQAAwD8AABDBAAAgQQAAwD8AACDBAAAQQQAAwD8AABBBAAAgwQAAwD8AACBBAAAQQQAAwD8AABBBAAAgQQAAwD8AACBBAAAQQQAAwD8AABBBAAAgQQAAwD8AACDBAAAgQQAAwD8AACBBAAAQwQAAwD8AABDBAAAQwQAAwL8AABDBAAAQwQAAwL8AABBBAAAQQQAAwL8AABDBAAAQwQAAwL8AABDBAAAQwQAAwD8AABDBAAAQwQAAwL8AABBBAAAQwQAAwD8AABBBAAAQwQAAwD8AABDBAAAQQQAAwD8AABBBAAAQwQAAwD8AABBBAAAQwQAAwL8AABBBAAAQwQAAwL8AABBBAAAQQQAAwL8AABBBAAAQQQAAwD8AABBBAAAQQQAAwD8AABBBAAAQQQAAwL8AABBBAAAQQQAAwL8AABDBAAAQwQAAwD8AABDBAAAQQQAAwD8AABDBAAAQQQAAwL8AABDBAAAQQQAAwL8AABDBAAAQQQAAwD8AABDBAAAQQQAAwD8AABBB/38AAP//AAD/fwAA//8AAP9/AAD//wAAAAD/f/9//n8AAP9//3/+fwAA/3//f/5//38AAP//AAD/fwAA//8AAP9/AAD//wAA/////wAA/z//////AAD/P/////8AAP8//38AAP//AAD/fwAA//8AAP9/AAD//wAA/38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//////AAD/f///AAAAAP9//////wAA/3//////AAD/f/////8AAP9//////wAAAAD/f/9//n8AAP9//3/+fwAA/3//f/5//3///wAAAAD/f///AAAAAP9//////wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8//3///wAAAAD/f///AAAAAP9///8AAAAA/38AAP//AAD/fwAA//8AAP9/AAD//wAA/38AAP//AAD/fwAA//8AAP9/AAD//wAA/38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8//38AAP//AAD/fwAA//8AAP9/AAD//wAA////f/9//n////9//3/+f////3//f/5//////wAA/z//////AAD/P/////8AAP8//3//////AAD/f/////8AAP9//////wAA////f/9//n////9//3/+f////3//f/5//3//////AAD/f/////8AAP9///8AAAAA/3///wAAAAD/f///AAAAAP9//////wAA/3///wAAAAD/f/////8AAP9//////wAA////f/9/AID///9//38AgP///3//fwCA/3//fwAA/7//f/9/AAD/v/9//38AAP+/////f/9/AID///9//38AgP///3//fwCA/////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+/AAD/f/9/AIAAAP9//38AgAAA/3//fwCA/3//fwAA/7//f/9/AAD/v/9//38AAP+/AAD/f/9/AIAAAP9//38AgAAA/3//fwCA")
}]
[sub_resource type="BoxMesh" id="BoxMesh_ysrn6"]
size = Vector3(20, 1, 20)
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_5nkxg"]
points = PackedVector3Array(-10, -0.5, -10, -10, 0.5, -10, 10, -0.5, -10, -10, -0.5, 10, -10, 0.5, 10, 10, 0.5, -10, 10, -0.5, 10, 10, 0.5, 10)
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_eoaoo"]
data = PackedVector3Array(0.125, 1.5, 1.25, 0.125, 1.25, -1, 0.125, 1.25, 1, -0.125, -1.5, -1.25, -0.125, 1.25, -1, -0.125, -1.25, -1, -0.125, -1.5, 1.25, 0.125, -1.5, -1.25, -0.125, -1.5, -1.25, 0.125, -1.5, -1.25, -0.125, 1.5, -1.25, -0.125, -1.5, -1.25, -0.125, -1.5, 1.25, -0.125, -1.25, -1, -0.125, -1.25, 1, -0.125, -1.5, 1.25, -0.125, -1.25, 1, -0.125, 1.5, 1.25, -0.125, 1.5, -1.25, -0.125, 1.25, -1, -0.125, -1.5, -1.25, -0.125, 1.5, -1.25, -0.125, 1.25, 1, -0.125, 1.25, -1, -0.125, 1.5, 1.25, -0.125, -1.25, 1, -0.125, 1.25, 1, -0.125, 1.5, 1.25, -0.125, 1.25, 1, -0.125, 1.5, -1.25, -0.125, 1.5, 1.25, 0.125, 1.5, 1.25, -0.125, -1.5, 1.25, -0.125, 1.5, -1.25, 0.125, 1.5, 1.25, -0.125, 1.5, 1.25, -0.125, -1.5, -1.25, -0.125, -1.25, -1, -0.125, -1.5, 1.25, 0.125, -1.5, -1.25, 0.125, -1.25, 1, 0.125, -1.25, -1, 0.125, -1.5, -1.25, 0.125, -1.25, -1, 0.125, 1.5, -1.25, -0.125, -1.5, 1.25, 0.125, -1.5, 1.25, 0.125, -1.5, -1.25, 0.125, 1.5, 1.25, 0.125, -1.5, 1.25, -0.125, -1.5, 1.25, 0.125, -1.5, 1.25, 0.125, -1.25, 1, 0.125, -1.5, -1.25, 0.125, -1.5, 1.25, 0.125, 1.25, 1, 0.125, -1.25, 1, 0.125, -1.5, -1.25, 0.125, 1.5, -1.25, -0.125, 1.5, -1.25, 0.125, 1.5, -1.25, 0.125, 1.5, 1.25, -0.125, 1.5, -1.25, 0.125, 1.5, -1.25, 0.125, -1.25, -1, 0.125, 1.25, -1, 0.125, 1.5, -1.25, 0.125, 1.25, -1, 0.125, 1.5, 1.25, 0.125, 1.5, 1.25, 0.125, 1.25, 1, 0.125, -1.5, 1.25, 0.125, -1.25, -1, -0.125, -1.25, -1, -0.125, 1.25, -1, -0.125, -1.25, 1, -0.125, -1.25, -1, 0.125, -1.25, 1, -0.125, 1.25, -1, -0.125, 1.25, 1, 0.125, 1.25, -1, 0.125, 1.25, 1, -0.125, 1.25, 1, -0.125, -1.25, 1, -0.125, -1.25, 1, 0.125, -1.25, 1, 0.125, 1.25, 1, -0.125, 1.25, -1, 0.125, 1.25, -1, 0.125, -1.25, -1, 0.125, 1.25, 1, 0.125, 1.25, -1, -0.125, 1.25, 1, 0.125, -1.25, -1, 0.125, -1.25, 1, -0.125, -1.25, -1)
[sub_resource type="ArrayMesh" id="ArrayMesh_b88kk"]
_surfaces = [{
"aabb": AABB(-0.125, -1.5, -1.25, 0.25, 3, 2.5),
"attribute_data": PackedByteArray("AAAAAAAAAACrqqo9ZmZmP6uqqj3NzMw9AACAPwAAAACrqqo9zczMPauqaj/NzMw9AAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAACAPwAAgD+rqmo/zczMPauqaj9mZmY/AACAPwAAgD+rqmo/ZmZmPwAAAAAAAIA/AAAAAAAAAACrqqo9zczMPQAAgD8AAAAAAAAAAAAAAACrqqo9ZmZmP6uqqj3NzMw9AAAAAAAAgD+rqmo/ZmZmP6uqqj1mZmY/AAAAAAAAgD+rqqo9ZmZmPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AACAPwAAAACrqmo/zczMPQAAgD8AAIA/AACAPwAAgD+rqmo/zczMPauqaj9mZmY/AACAPwAAgD+rqmo/ZmZmPwAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAACrqmo/zczMPQAAgD8AAIA/AACAPwAAAACrqqo9zczMPauqaj/NzMw9AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAgD+rqmo/ZmZmP6uqqj1mZmY/AAAAAAAAgD+rqqo9ZmZmPwAAAAAAAAAAAAAAAAAAAACrqqo9zczMPQAAgD8AAAAAAADAPgAAAAAAACA/AAAAAAAAID8AAIA/AAAAAAAAwD4AAIA/AADAPgAAAAAAACA/AACAPwAAID8AAAAAAAAgPwAAgD8AAMA+AADAPgAAAAAAACA/AAAAAAAAID8AAIA/AAAgPwAAgD8AAMA+AACAPwAAwD4AAAAAAAAgPwAAgD8AAMA+AACAPwAAwD4AAAAAAAAAAAAAwD4AAIA/AADAPgAAAAAAACA/AACAPwAAID8AAAAAAAAgPwAAgD8AAMA+"),
"format": 34359738391,
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 96,
"vertex_data": PackedByteArray("AAAAPgAAwD8AAKA/AAAAPgAAoD8AAIC/AAAAPgAAoD8AAIA/AAAAvgAAwL8AAKC/AAAAvgAAoD8AAIC/AAAAvgAAoL8AAIC/AAAAvgAAwL8AAKA/AAAAPgAAwL8AAKC/AAAAvgAAwL8AAKC/AAAAPgAAwL8AAKC/AAAAvgAAwD8AAKC/AAAAvgAAwL8AAKC/AAAAvgAAwL8AAKA/AAAAvgAAoL8AAIC/AAAAvgAAoL8AAIA/AAAAvgAAwL8AAKA/AAAAvgAAoL8AAIA/AAAAvgAAwD8AAKA/AAAAvgAAwD8AAKC/AAAAvgAAoD8AAIC/AAAAvgAAwL8AAKC/AAAAvgAAwD8AAKC/AAAAvgAAoD8AAIA/AAAAvgAAoD8AAIC/AAAAvgAAwD8AAKA/AAAAvgAAoL8AAIA/AAAAvgAAoD8AAIA/AAAAvgAAwD8AAKA/AAAAvgAAoD8AAIA/AAAAvgAAwD8AAKC/AAAAvgAAwD8AAKA/AAAAPgAAwD8AAKA/AAAAvgAAwL8AAKA/AAAAvgAAwD8AAKC/AAAAPgAAwD8AAKA/AAAAvgAAwD8AAKA/AAAAvgAAwL8AAKC/AAAAvgAAoL8AAIC/AAAAvgAAwL8AAKA/AAAAPgAAwL8AAKC/AAAAPgAAoL8AAIA/AAAAPgAAoL8AAIC/AAAAPgAAwL8AAKC/AAAAPgAAoL8AAIC/AAAAPgAAwD8AAKC/AAAAvgAAwL8AAKA/AAAAPgAAwL8AAKA/AAAAPgAAwL8AAKC/AAAAPgAAwD8AAKA/AAAAPgAAwL8AAKA/AAAAvgAAwL8AAKA/AAAAPgAAwL8AAKA/AAAAPgAAoL8AAIA/AAAAPgAAwL8AAKC/AAAAPgAAwL8AAKA/AAAAPgAAoD8AAIA/AAAAPgAAoL8AAIA/AAAAPgAAwL8AAKC/AAAAPgAAwD8AAKC/AAAAvgAAwD8AAKC/AAAAPgAAwD8AAKC/AAAAPgAAwD8AAKA/AAAAvgAAwD8AAKC/AAAAPgAAwD8AAKC/AAAAPgAAoL8AAIC/AAAAPgAAoD8AAIC/AAAAPgAAwD8AAKC/AAAAPgAAoD8AAIC/AAAAPgAAwD8AAKA/AAAAPgAAwD8AAKA/AAAAPgAAoD8AAIA/AAAAPgAAwL8AAKA/AAAAPgAAoL8AAIC/AAAAvgAAoL8AAIC/AAAAvgAAoD8AAIC/AAAAvgAAoL8AAIA/AAAAvgAAoL8AAIC/AAAAPgAAoL8AAIA/AAAAvgAAoD8AAIC/AAAAvgAAoD8AAIA/AAAAPgAAoD8AAIC/AAAAPgAAoD8AAIA/AAAAvgAAoD8AAIA/AAAAvgAAoL8AAIA/AAAAvgAAoL8AAIA/AAAAPgAAoL8AAIA/AAAAPgAAoD8AAIA/AAAAvgAAoD8AAIC/AAAAPgAAoD8AAIC/AAAAPgAAoL8AAIC/AAAAPgAAoD8AAIA/AAAAPgAAoD8AAIC/AAAAvgAAoD8AAIA/AAAAPgAAoL8AAIC/AAAAPgAAoL8AAIA/AAAAvgAAoL8AAIC/////f/9//n////9//3/+f////3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5//38AAP//AAD/fwAA//8AAP9/AAD//wAA/////wAA/z//////AAD/P/////8AAP8/AAD/f/9//n8AAP9//3/+fwAA/3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5/AAD/f/9//n8AAP9//3/+fwAA/3//f/5//3//fwAA/z//f/9/AAD/P/9//38AAP8//3//////AAD/f/////8AAP9//////wAAAAD/f/9//n8AAP9//3/+fwAA/3//f/5/////f/9//n////9//3/+f////3//f/5/////f/9//n////9//3/+f////3//f/5//38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8/////f/9//n////9//3/+f////3//f/5/////f/9//n////9//3/+f////3//f/5//////wAA/z//////AAD/P/////8AAP8//3//////AAD/f/////8AAP9//////wAA////f/9//n////9//3/+f////3//f/5/////f/9//n////9//3/+f////3//f/5/////f/9//n////9//3/+f////3//f/5//3//fwAA/7//f/9/AAD/v/9//38AAP+//3//////////f/////////9//////////38AAP//////fwAA//////9/AAD//////////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//3//fwAA/7//f/9/AAD/v/9//38AAP+//38AAP//////fwAA//////9/AAD//////3//////////f/////////9/////////")
}]
[sub_resource type="BoxMesh" id="BoxMesh_pvdtj"]
material = ExtResource("6_2ffpc")
[sub_resource type="ArrayMesh" id="ArrayMesh_pccqs"]
_surfaces = [{
"aabb": AABB(-1, -1.25, -0.1, 2, 2.5, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD/NzEw9CtcjPTMzcz8K1yM9zcxMPY/CdT8zM3M/j8J1Pw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AACAvwAAoD8AAAAAAACAPwAAoD8AAAAAAACAvwAAoL8AAAAAAACAPwAAoL8AAAAAZmZmvzMzkz/NzMy9ZmZmPzMzkz/NzMy9ZmZmvzMzk7/NzMy9ZmZmPzMzk7/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[sub_resource type="SphereMesh" id="SphereMesh_pccqs"]
material = ExtResource("8_dhtg5")
[sub_resource type="ArrayMesh" id="ArrayMesh_pvdtj"]
_surfaces = [{
"aabb": AABB(-1, -1.25, -0.1, 2, 2.5, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD/NzEw9CtcjPTMzcz8K1yM9zcxMPY/CdT8zM3M/j8J1Pw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AACAvwAAoD8AAAAAAACAPwAAoD8AAAAAAACAvwAAoL8AAAAAAACAPwAAoL8AAAAAZmZmvzMzkz/NzMy9ZmZmPzMzkz/NzMy9ZmZmvzMzk7/NzMy9ZmZmPzMzk7/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[node name="World" type="Node3D"]
script = ExtResource("1_pccqs")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0)
shadow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_b88kk")
[node name="PortalEnvironmentAdapter" parent="." node_paths=PackedStringArray("base") instance=ExtResource("1_eoaoo")]
base = NodePath("../WorldEnvironment")
[node name="HUD" parent="." instance=ExtResource("4_t21k5")]
offset_right = 219.0
offset_bottom = 77.0
[node name="TransportToGreen" type="Button" parent="HUD"]
layout_mode = 2
text = "Transport to green"
[node name="TransportToOrange" type="Button" parent="HUD"]
layout_mode = 2
text = "Transport to orange"
[node name="Player" parent="." instance=ExtResource("3_ysrn6")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.68722, 0.942887, -13.7212)
[node name="Orange" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -12)
[node name="Room" type="Node3D" parent="Orange"]
[node name="Wall" type="StaticBody3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
[node name="CSGBakedCollisionShape3D" type="CollisionShape3D" parent="Orange/Room/Wall"]
visible = false
shape = SubResource("ConcavePolygonShape3D_7nftg")
[node name="CSGBakedMeshInstance3D" type="MeshInstance3D" parent="Orange/Room/Wall"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
visible = false
material_override = ExtResource("1_v6nyh")
mesh = SubResource("ArrayMesh_v6nyh")
[node name="Ground" type="StaticBody3D" parent="Orange/Room"]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Orange/Room/Ground"]
material_override = ExtResource("2_5nkxg")
mesh = SubResource("BoxMesh_ysrn6")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Orange/Room/Ground"]
shape = SubResource("ConvexPolygonShape3D_5nkxg")
[node name="PortalFrame" type="StaticBody3D" parent="Orange/Room"]
[node name="PortalFrame" type="CollisionShape3D" parent="Orange/Room/PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
shape = SubResource("ConcavePolygonShape3D_eoaoo")
[node name="PortalFrameCollision" type="MeshInstance3D" parent="Orange/Room/PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
material_override = ExtResource("1_v6nyh")
mesh = SubResource("ArrayMesh_b88kk")
[node name="Cube" type="MeshInstance3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.5, 1, -3.5)
mesh = SubResource("BoxMesh_pvdtj")
skeleton = NodePath("../..")
[node name="Cube2" type="MeshInstance3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 1, -6.5)
mesh = SubResource("BoxMesh_pvdtj")
skeleton = NodePath("../..")
[node name="Cube3" type="MeshInstance3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.5, 1, -1)
mesh = SubResource("BoxMesh_pvdtj")
skeleton = NodePath("../..")
[node name="Cube4" type="MeshInstance3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1, 1)
mesh = SubResource("BoxMesh_pvdtj")
skeleton = NodePath("../..")
[node name="Cube5" type="MeshInstance3D" parent="Orange/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 1, 3)
mesh = SubResource("BoxMesh_pvdtj")
skeleton = NodePath("../..")
[node name="OrangePortal" type="MeshInstance3D" parent="Orange" node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(1.31134e-07, 0, -1, 0, 1, 0, 1, 0, 1.31134e-07, 0, 2, 0)
mesh = SubResource("ArrayMesh_pccqs")
skeleton = NodePath("../..")
script = ExtResource("7_pvdtj")
exit_portal = NodePath("../../Green/GreenPortal")
[node name="Green" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 12.5)
[node name="Room" type="Node3D" parent="Green"]
[node name="Wall" type="StaticBody3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
[node name="CSGBakedCollisionShape3D" type="CollisionShape3D" parent="Green/Room/Wall"]
visible = false
shape = SubResource("ConcavePolygonShape3D_7nftg")
[node name="CSGBakedMeshInstance3D" type="MeshInstance3D" parent="Green/Room/Wall"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
visible = false
material_override = ExtResource("1_v6nyh")
mesh = SubResource("ArrayMesh_v6nyh")
[node name="Ground" type="StaticBody3D" parent="Green/Room"]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Green/Room/Ground"]
material_override = ExtResource("6_b88kk")
mesh = SubResource("BoxMesh_ysrn6")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Green/Room/Ground"]
shape = SubResource("ConvexPolygonShape3D_5nkxg")
[node name="PortalFrame" type="StaticBody3D" parent="Green/Room"]
[node name="PortalFrame" type="CollisionShape3D" parent="Green/Room/PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
shape = SubResource("ConcavePolygonShape3D_eoaoo")
[node name="PortalFrameCollision" type="MeshInstance3D" parent="Green/Room/PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
material_override = ExtResource("1_v6nyh")
mesh = SubResource("ArrayMesh_b88kk")
[node name="Ball6" type="MeshInstance3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.5, 1, -3.5)
mesh = SubResource("SphereMesh_pccqs")
skeleton = NodePath("../../../Orange")
[node name="Ball7" type="MeshInstance3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 1, -6.5)
mesh = SubResource("SphereMesh_pccqs")
skeleton = NodePath("../../../Orange")
[node name="Ball8" type="MeshInstance3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.5, 1, -1)
mesh = SubResource("SphereMesh_pccqs")
skeleton = NodePath("../../../Orange")
[node name="Ball9" type="MeshInstance3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1, 1)
mesh = SubResource("SphereMesh_pccqs")
skeleton = NodePath("../../../Orange")
[node name="Ball10" type="MeshInstance3D" parent="Green/Room"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 1, 3)
mesh = SubResource("SphereMesh_pccqs")
skeleton = NodePath("../../../Orange")
[node name="GreenPortal" type="MeshInstance3D" parent="Green" node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, 2, 0)
mesh = SubResource("ArrayMesh_pvdtj")
skeleton = NodePath("../..")
script = ExtResource("7_pvdtj")
exit_portal = NodePath("../../Orange/OrangePortal")
[node name="ProceduralMeshMaker" parent="." node_paths=PackedStringArray("portal") instance=ExtResource("9_dhtg5")]
portal = NodePath("../Orange/OrangePortal")
height = 2.5
width = 2.0
[connection signal="pressed" from="HUD/TransportToGreen" to="." method="_on_transport_to_green_pressed"]
[connection signal="pressed" from="HUD/TransportToOrange" to="." method="_on_transport_to_orange_pressed"]

View File

@ -0,0 +1,159 @@
[gd_scene load_steps=19 format=4 uid="uid://b2c27cvkqvhbi"]
[ext_resource type="Material" uid="uid://bx6qeabdhq2s" path="res://addons/kenney_prototype_tools/materials/dark/material_01.tres" id="1_kvwhs"]
[ext_resource type="PackedScene" uid="uid://b5x7fmpwck335" path="res://hud.tscn" id="2_hpe2j"]
[ext_resource type="PackedScene" uid="uid://cgdlowfuuorvi" path="res://player.tscn" id="3_mc50s"]
[ext_resource type="Script" uid="uid://d2bvvjsibau8c" path="res://addons/simple-portal-system/scripts/portal.gd" id="4_hg00i"]
[ext_resource type="PackedScene" uid="uid://d1dtxvwk86ple" path="res://procedural_mesh_maker.tscn" id="5_ka6qt"]
[ext_resource type="PackedScene" uid="uid://cxopylew5786r" path="res://portal_environment_adapter.tscn" id="6_ka6qt"]
[ext_resource type="PackedScene" uid="uid://dn8qt0qwx4sfs" path="res://addons/kenney_prototype_tools/scenes/orange/orange_02.tscn" id="7_o2k5d"]
[ext_resource type="Material" uid="uid://uylhy3ucrinn" path="res://addons/kenney_prototype_tools/materials/purple/material_04.tres" id="8_25cs0"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_sjb6i"]
sky_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
ground_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
[sub_resource type="Sky" id="Sky_o2k5d"]
sky_material = SubResource("ProceduralSkyMaterial_sjb6i")
[sub_resource type="Environment" id="Environment_25cs0"]
background_mode = 2
sky = SubResource("Sky_o2k5d")
tonemap_mode = 2
glow_enabled = true
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_fdix6"]
points = PackedVector3Array(-10, -0.5, -10, -10, 0.5, -10, 10, -0.5, -10, -10, -0.5, 10, -10, 0.5, 10, 10, 0.5, -10, 10, -0.5, 10, 10, 0.5, 10)
[sub_resource type="BoxMesh" id="BoxMesh_hpe2j"]
size = Vector3(20, 1, 20)
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_hg00i"]
data = PackedVector3Array(-1, -1.125, -0.25, -1, -1.125, 0.25, -0.75, -1.125, -0.25, 0.75, 0.875, 0.25, 1, 1.125, 0.25, 0.75, -1.125, 0.25, -1, -1.125, 0.25, -1, -1.125, -0.25, -1, 1.125, -0.25, -0.75, -1.125, -0.25, -1, -1.125, 0.25, -0.75, -1.125, 0.25, -0.75, -1.125, 0.25, -1, -1.125, 0.25, -0.75, 0.875, 0.25, -0.75, 0.875, -0.25, -1, 1.125, -0.25, -0.75, -1.125, -0.25, -0.75, 0.875, -0.25, 1, 1.125, -0.25, -1, 1.125, -0.25, -1, 1.125, -0.25, -1, 1.125, 0.25, -1, -1.125, 0.25, -1, 1.125, 0.25, -0.75, 0.875, 0.25, -1, -1.125, 0.25, -1, 1.125, -0.25, 1, 1.125, 0.25, -1, 1.125, 0.25, -0.75, 0.875, 0.25, -1, 1.125, 0.25, 0.75, 0.875, 0.25, 1, -1.125, -0.25, 0.75, -1.125, -0.25, 1, -1.125, 0.25, -1, -1.125, -0.25, -0.75, -1.125, -0.25, -1, 1.125, -0.25, 0.75, -1.125, -0.25, 1, -1.125, -0.25, 0.75, 0.875, -0.25, 1, -1.125, 0.25, 0.75, -1.125, -0.25, 0.75, -1.125, 0.25, 1, -1.125, 0.25, 1, 1.125, 0.25, 1, -1.125, -0.25, 1, -1.125, 0.25, 0.75, -1.125, 0.25, 1, 1.125, 0.25, 0.75, 0.875, -0.25, 1, 1.125, -0.25, -0.75, 0.875, -0.25, 1, 1.125, -0.25, 1, 1.125, 0.25, -1, 1.125, -0.25, 1, 1.125, -0.25, 0.75, 0.875, -0.25, 1, -1.125, -0.25, 1, 1.125, 0.25, 1, 1.125, -0.25, 1, -1.125, -0.25, 0.75, 0.875, 0.25, -1, 1.125, 0.25, 1, 1.125, 0.25, -0.75, 0.875, 0.25, -0.75, -1.125, -0.25, -0.75, -1.125, 0.25, -0.75, -1.125, -0.25, -0.75, 0.875, 0.25, -0.75, 0.875, -0.25, 0.75, 0.875, -0.25, 0.75, -1.125, 0.25, 0.75, -1.125, -0.25, 0.75, 0.875, 0.25, 0.75, 0.875, -0.25, -0.75, 0.875, -0.25, 0.75, -1.125, 0.25, 0.75, 0.875, -0.25, 0.75, 0.875, 0.25, -0.75, 0.875, -0.25, -0.75, 0.875, 0.25, 0.75, 0.875, 0.25)
[sub_resource type="ArrayMesh" id="ArrayMesh_ka6qt"]
_surfaces = [{
"aabb": AABB(-1, -1.125, -0.25, 2, 2.25, 0.5),
"attribute_data": PackedByteArray("AACAPwAAAAAAAAAAAAAAAAAAgD8AAAA+AAAAPjmO4z0AAAAAAAAAAAAAAD4AAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAAD4AAAAAAAAAAAAAAAAAAAA+AABgPwAAgD8AAIA/AACAPwAAYD85juM9AABgPzmOYz8AAIA/AACAPwAAYD8AAAAAAABgPzmOYz8AAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAGA/OY7jPQAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AABgPzmO4z0AAIA/AAAAAAAAAD45juM9AACAPwAAgD8AAIA/AABgPwAAAAAAAIA/AACAPwAAAAAAAGA/AAAAAAAAgD8AAIA/AAAAPgAAAAAAAAAAAAAAAAAAAD45jmM/AAAAAAAAgD8AAIA/AABgPwAAAAAAAGA/AACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAgD8AAAA+AACAPwAAAAAAAAAAAAAAPjmOYz8AAAAAAACAPwAAYD85jmM/AACAPwAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAgD8AAAA+OY5jPwAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAPjmO4z0AAIA/AAAAAAAAAAAAAAAAAAAAAAAAQD8AAIA/AACAPgAAgD8AAEA/AACAPwAAgD4AAAAAAABAPwAAAAAAAIA+AAAAAAAAQD8AAIA/AACAPgAAgD8AAEA/AACAPgAAAAAAAEA/AAAAAAAAQD8AAIA/AACAPwAAgD4AAAAAAABAPwAAAAAAAIA+AABAPwAAgD8AAIA+AACAPwAAgD4AAAAA"),
"format": 34359738391,
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 84,
"vertex_data": PackedByteArray("AACAvwAAkL8AAIC+AACAvwAAkL8AAIA+AABAvwAAkL8AAIC+AABAPwAAYD8AAIA+AACAPwAAkD8AAIA+AABAPwAAkL8AAIA+AACAvwAAkL8AAIA+AACAvwAAkL8AAIC+AACAvwAAkD8AAIC+AABAvwAAkL8AAIC+AACAvwAAkL8AAIA+AABAvwAAkL8AAIA+AABAvwAAkL8AAIA+AACAvwAAkL8AAIA+AABAvwAAYD8AAIA+AABAvwAAYD8AAIC+AACAvwAAkD8AAIC+AABAvwAAkL8AAIC+AABAvwAAYD8AAIC+AACAPwAAkD8AAIC+AACAvwAAkD8AAIC+AACAvwAAkD8AAIC+AACAvwAAkD8AAIA+AACAvwAAkL8AAIA+AACAvwAAkD8AAIA+AABAvwAAYD8AAIA+AACAvwAAkL8AAIA+AACAvwAAkD8AAIC+AACAPwAAkD8AAIA+AACAvwAAkD8AAIA+AABAvwAAYD8AAIA+AACAvwAAkD8AAIA+AABAPwAAYD8AAIA+AACAPwAAkL8AAIC+AABAPwAAkL8AAIC+AACAPwAAkL8AAIA+AACAvwAAkL8AAIC+AABAvwAAkL8AAIC+AACAvwAAkD8AAIC+AABAPwAAkL8AAIC+AACAPwAAkL8AAIC+AABAPwAAYD8AAIC+AACAPwAAkL8AAIA+AABAPwAAkL8AAIC+AABAPwAAkL8AAIA+AACAPwAAkL8AAIA+AACAPwAAkD8AAIA+AACAPwAAkL8AAIC+AACAPwAAkL8AAIA+AABAPwAAkL8AAIA+AACAPwAAkD8AAIA+AABAPwAAYD8AAIC+AACAPwAAkD8AAIC+AABAvwAAYD8AAIC+AACAPwAAkD8AAIC+AACAPwAAkD8AAIA+AACAvwAAkD8AAIC+AACAPwAAkD8AAIC+AABAPwAAYD8AAIC+AACAPwAAkL8AAIC+AACAPwAAkD8AAIA+AACAPwAAkD8AAIC+AACAPwAAkL8AAIC+AABAPwAAYD8AAIA+AACAvwAAkD8AAIA+AACAPwAAkD8AAIA+AABAvwAAYD8AAIA+AABAvwAAkL8AAIC+AABAvwAAkL8AAIA+AABAvwAAkL8AAIC+AABAvwAAYD8AAIA+AABAvwAAYD8AAIC+AABAPwAAYD8AAIC+AABAPwAAkL8AAIA+AABAPwAAkL8AAIC+AABAPwAAYD8AAIA+AABAPwAAYD8AAIC+AABAvwAAYD8AAIC+AABAPwAAkL8AAIA+AABAPwAAYD8AAIC+AABAPwAAYD8AAIA+AABAvwAAYD8AAIC+AABAvwAAYD8AAIA+AABAPwAAYD8AAIA+/38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8/AAD/f/9//n8AAP9//3/+fwAA/3//f/5//38AAP//AAD/fwAA//8AAP9/AAD//wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8//////wAA/z//////AAD/P/////8AAP8//////wAA/z//////AAD/P/////8AAP8/AAD/f/9//n8AAP9//3/+fwAA/3//f/5//3//fwAA/z//f/9/AAD/P/9//38AAP8//3//////AAD/f/////8AAP9//////wAA/3//fwAA/z//f/9/AAD/P/9//38AAP8//38AAP//AAD/fwAA//8AAP9/AAD//wAA/////wAA/z//////AAD/P/////8AAP8//////wAA/z//////AAD/P/////8AAP8//38AAP//AAD/fwAA//8AAP9/AAD//wAA////f/9//n////9//3/+f////3//f/5//3//fwAA/z//f/9/AAD/P/9//38AAP8//////wAA/z//////AAD/P/////8AAP8//3//////AAD/f/////8AAP9//////wAA/////wAA/z//////AAD/P/////8AAP8/////f/9//n////9//3/+f////3//f/5//3//fwAA/z//f/9/AAD/P/9//38AAP8/////f/9/AID///9//38AgP///3//fwCA////f/9/AID///9//38AgP///3//fwCAAAD/f/9/AIAAAP9//38AgAAA/3//fwCA/38AAP//////fwAA//////9/AAD/////AAD/f/9/AIAAAP9//38AgAAA/3//fwCA/38AAP//////fwAA//////9/AAD/////")
}]
[sub_resource type="ArrayMesh" id="ArrayMesh_hg00i"]
_surfaces = [{
"aabb": AABB(-0.75, -1, -0.1, 1.5, 2, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD+JiIg9zcxMPe/ubj/NzEw9iYiIPTMzcz/v7m4/MzNzPw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AABAvwAAgD8AAAAAAABAPwAAgD8AAAAAAABAvwAAgL8AAAAAAABAPwAAgL8AAAAAZmYmv2ZmZj/NzMy9ZmYmP2ZmZj/NzMy9ZmYmv2ZmZr/NzMy9ZmYmP2ZmZr/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[sub_resource type="ArrayMesh" id="ArrayMesh_sjb6i"]
_surfaces = [{
"aabb": AABB(-0.75, -1, -0.1, 1.5, 2, 0.1),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD+JiIg9zcxMPe/ubj/NzEw9iYiIPTMzcz/v7m4/MzNzPw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AABAvwAAgD8AAAAAAABAPwAAgD8AAAAAAABAvwAAgL8AAAAAAABAPwAAgL8AAAAAZmYmv2ZmZj/NzMy9ZmYmP2ZmZj/NzMy9ZmYmv2ZmZr/NzMy9ZmYmP2ZmZr/NzMy9/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[sub_resource type="SphereMesh" id="SphereMesh_xuajm"]
[node name="level_test_portal_delay" type="Node3D"]
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_25cs0")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0)
shadow_enabled = true
[node name="StaticBody3D" type="StaticBody3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
shape = SubResource("ConvexPolygonShape3D_fdix6")
[node name="Ground" type="MeshInstance3D" parent="StaticBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
material_override = ExtResource("1_kvwhs")
mesh = SubResource("BoxMesh_hpe2j")
skeleton = NodePath("../..")
[node name="HUD" parent="." instance=ExtResource("2_hpe2j")]
[node name="Player" parent="." instance=ExtResource("3_mc50s")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.96416, 0, 3.38931)
[node name="PortalFrame" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.374685, 0)
[node name="CSGBakedCollisionShape3D" type="CollisionShape3D" parent="PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
shape = SubResource("ConcavePolygonShape3D_hg00i")
[node name="CSGBakedMeshInstance3D" type="MeshInstance3D" parent="PortalFrame"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
material_override = ExtResource("1_kvwhs")
cast_shadow = 0
mesh = SubResource("ArrayMesh_ka6qt")
skeleton = NodePath("../..")
[node name="Portal_A" type="MeshInstance3D" parent="PortalFrame" node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.37468, 0)
cast_shadow = 0
mesh = SubResource("ArrayMesh_hg00i")
skeleton = NodePath("../..")
script = ExtResource("4_hg00i")
exit_portal = NodePath("../../PortalFrame2/Portal_B")
[node name="PortalFrame2" type="StaticBody3D" parent="."]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3, -0.375, -2.5)
[node name="CSGBakedCollisionShape3D" type="CollisionShape3D" parent="PortalFrame2"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
shape = SubResource("ConcavePolygonShape3D_hg00i")
[node name="CSGBakedMeshInstance3D" type="MeshInstance3D" parent="PortalFrame2"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
material_override = ExtResource("1_kvwhs")
cast_shadow = 0
mesh = SubResource("ArrayMesh_ka6qt")
skeleton = NodePath("../..")
[node name="Portal_B" type="MeshInstance3D" parent="PortalFrame2" node_paths=PackedStringArray("exit_portal")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.375, 0)
cast_shadow = 0
mesh = SubResource("ArrayMesh_sjb6i")
skeleton = NodePath("../..")
script = ExtResource("4_hg00i")
exit_portal = NodePath("../../PortalFrame/Portal_A")
[node name="ProceduralMeshMaker" parent="." node_paths=PackedStringArray("portal") instance=ExtResource("5_ka6qt")]
portal = NodePath("../PortalFrame2/Portal_B")
width = 1.5
[node name="PortalEnvironmentAdapter" parent="." node_paths=PackedStringArray("base") instance=ExtResource("6_ka6qt")]
base = NodePath("../WorldEnvironment")
[node name="Cube" parent="." instance=ExtResource("7_o2k5d")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, -4)
[node name="Mesh" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 3)
material_override = ExtResource("8_25cs0")
mesh = SubResource("SphereMesh_xuajm")
skeleton = NodePath("")

View File

@ -0,0 +1,520 @@
[gd_scene load_steps=21 format=4 uid="uid://ci81nttn6foio"]
[ext_resource type="Material" uid="uid://b7kc8jfs4fowj" path="res://addons/kenney_prototype_tools/materials/green/material_02.tres" id="1_ofsgw"]
[ext_resource type="PackedScene" uid="uid://dve8bvx87r1mm" path="res://models/kenney-house/wall-doorway-square.glb" id="2_4aydi"]
[ext_resource type="PackedScene" uid="uid://bfgvxrgm0dkgi" path="res://models/kenney-house/wall.glb" id="3_37grx"]
[ext_resource type="PackedScene" uid="uid://d3qx51q66eftg" path="res://models/kenney-house/roof-flat-corner.glb" id="4_e3d5x"]
[ext_resource type="PackedScene" uid="uid://b0k0k4heruf3t" path="res://models/kenney-house/wall-window-square-detailed.glb" id="5_soise"]
[ext_resource type="PackedScene" uid="uid://d347ojn6kwgn2" path="res://models/kenney-house/floor.glb" id="6_p5xd2"]
[ext_resource type="PackedScene" uid="uid://yqsv32xecxbr" path="res://models/kenney-house/roof-flat-side.glb" id="7_km368"]
[ext_resource type="PackedScene" uid="uid://d3yk6et3d4yw3" path="res://models/kenney-house/border.glb" id="8_rmadb"]
[ext_resource type="PackedScene" uid="uid://dsogp3m6bedxp" path="res://models/kenney-house/column.glb" id="9_jpxld"]
[ext_resource type="PackedScene" uid="uid://b4mndlgalycyh" path="res://models/kenney-house/roof-flat-center.glb" id="10_5h2gx"]
[sub_resource type="BoxShape3D" id="BoxShape3D_w2gbp"]
size = Vector3(40, 1, 40)
[sub_resource type="BoxMesh" id="BoxMesh_blkr4"]
material = ExtResource("1_ofsgw")
size = Vector3(40, 1, 40)
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_soise"]
sky_top_color = Color(0.220994, 0.465185, 0.685758, 1)
sky_horizon_color = Color(0.775585, 0.617199, 0.525157, 1)
ground_bottom_color = Color(0.0327392, 0.0238974, 0.0155985, 1)
ground_horizon_color = Color(0.67988, 0.550619, 0.418075, 1)
[sub_resource type="Sky" id="Sky_m1tf4"]
sky_material = SubResource("ProceduralSkyMaterial_soise")
[sub_resource type="Environment" id="Environment_p5xd2"]
background_mode = 2
sky = SubResource("Sky_m1tf4")
tonemap_mode = 1
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_soise"]
albedo_color = Color(1, 0.6, 0.235294, 1)
[sub_resource type="PrismMesh" id="PrismMesh_p5xd2"]
material = SubResource("StandardMaterial3D_soise")
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p5xd2"]
shading_mode = 0
albedo_color = Color(0, 0, 0, 1)
[sub_resource type="ArrayMesh" id="ArrayMesh_km368"]
_surfaces = [{
"aabb": AABB(-0.51069, -0.511952, -0.512309, 1.02138, 1.02626, 1.02462),
"attribute_data": PackedByteArray("q6oqPgAAAABWVVU/AAAAAKuqKj4AAAAAVlVVPwAAAAAAAAAAAAAAP6uqKj8AAAA/q6qqPgAAAD8AAIA/AAAAP6uqqj4AAAAAAAAAAAAAAD+rqio/AAAAAKuqqj4AAAA/q6qqPgAAAD8AAAAAAACAP6uqKj8AAAA/q6qqPgAAgD+rqio/AAAAPwAAgD8AAAA/q6oqPwAAgD8AAIA/AACAPw=="),
"format": 34359742487,
"index_count": 24,
"index_data": PackedByteArray("AgAEAAYAAwAFAAcACAAMAAoACgAMAA4ACQANAAsACwANAA8AEAASABEAEQASABMA"),
"material": SubResource("StandardMaterial3D_p5xd2"),
"name": "Outline",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 20,
"vertex_data": PackedByteArray("VHXYu/ypAz+xJgM/U3XYu/ypAz+xJgO/VHXYu/ypAz+xJgM/U3XYu/ypAz+xJgO/nLwCv04PA79ODwM/nLwCP04PA79ODwO/nLwCP04PA79ODwM/nLwCv04PA79ODwO/VHXYu/ypAz+xJgM/U3XYu/ypAz+xJgO/U3XYu/ypAz+xJgO/VHXYu/ypAz+xJgM/nLwCP04PA79ODwM/nLwCv04PA79ODwO/nLwCP04PA79ODwO/nLwCv04PA79ODwM/nLwCv04PA79ODwM/nLwCP04PA79ODwM/nLwCv04PA79ODwO/nLwCP04PA79ODwO//3//f////7//////AAD/v/9//3////+//////wAA/7//f/9/////v/////8AAP+//3//f////7//////AAD/v1TVqqr/////qiqqqv9//79U1aqq/////6oqqqr/f/+/VNWqqv////+qKqqq/3//v1TVqqr/////qiqqqv9//78AgAAA////vwCAAAD///+/AIAAAP///78AgAAA////vw==")
}]
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_soise"]
data = PackedVector3Array(0, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0, 0.5, 0.5, 0, 0.5, -0.5, 0.5, -0.5, 0.5, 0, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, -0.5, -0.5, -0.5, 0, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5)
[node name="room_hermione_inside" type="Node3D"]
[node name="StaticBody3D" type="StaticBody3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
shape = SubResource("BoxShape3D_w2gbp")
[node name="Ground" type="MeshInstance3D" parent="StaticBody3D"]
mesh = SubResource("BoxMesh_blkr4")
skeleton = NodePath("../..")
metadata/_edit_lock_ = true
[node name="House" type="Node3D" parent="."]
[node name="wall-doorway-square2" parent="House" instance=ExtResource("2_4aydi")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.5, 0.5, 0.5)
[node name="wall-window-square-detailed2" parent="House" instance=ExtResource("5_soise")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.5, 0.5, 2.5)
[node name="floor2" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 0.5, 0.5)
[node name="floor3" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 0.5, 2.5)
[node name="floor4" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0.5, 0.5)
[node name="floor5" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0.5, 2.5)
[node name="floor7" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.245437, 0.5, 0.5)
[node name="floor8" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.245437, 0.5, 2.5)
[node name="floor6" parent="House" instance=ExtResource("6_p5xd2")]
transform = Transform3D(6, 0, 0, 0, 1, 0, 0, 0, 6, -6.5, 0.5, 1.5)
[node name="wall2" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 2.5, 0.5, 3.5)
[node name="wall3" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 0.5, 3.5)
[node name="wall20" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 2.5, 0.5, -0.5)
[node name="wall21" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 0.5, -0.5)
[node name="wall4" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 4.5)
[node name="wall5" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 6.5)
[node name="wall22" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 4.5)
[node name="wall23" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 6.5)
[node name="wall24" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 0.5)
[node name="wall25" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 2.5)
[node name="wall26" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, -3.5)
[node name="wall27" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, -1.5)
[node name="wall18" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, -3.5)
[node name="wall19" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, -1.5)
[node name="wall6" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -1.5, 0.5, 7.5)
[node name="wall7" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -3.5, 0.5, 7.5)
[node name="wall8" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -5.5, 0.5, 7.5)
[node name="wall9" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -7.5, 0.5, 7.5)
[node name="wall10" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -9.5, 0.5, 7.5)
[node name="wall11" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -11.5, 0.5, 7.5)
[node name="wall12" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -1.5, 0.5, -4.5)
[node name="wall13" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -3.5, 0.5, -4.5)
[node name="wall14" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -5.5, 0.5, -4.5)
[node name="wall15" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -7.5, 0.5, -4.5)
[node name="wall16" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -9.5, 0.5, -4.5)
[node name="wall17" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -11.5, 0.5, -4.5)
[node name="wall32" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, 4.5)
[node name="wall33" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, 6.5)
[node name="wall54" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, 0.5)
[node name="wall55" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, 2.5)
[node name="wall34" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 4.5)
[node name="wall35" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 6.5)
[node name="wall36" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 0.5)
[node name="wall37" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 2.5)
[node name="wall38" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, -3.5)
[node name="wall39" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, -1.5)
[node name="wall40" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, -3.5)
[node name="wall41" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, -1.5)
[node name="wall42" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -1.5, 2.9, 7.5)
[node name="wall43" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -3.5, 2.9, 7.5)
[node name="wall44" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -5.5, 2.9, 7.5)
[node name="wall45" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -7.5, 2.9, 7.5)
[node name="wall46" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -9.5, 2.9, 7.5)
[node name="wall47" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -11.5, 2.9, 7.5)
[node name="wall48" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -1.5, 2.9, -4.5)
[node name="wall49" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -3.5, 2.9, -4.5)
[node name="wall50" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -5.5, 2.9, -4.5)
[node name="wall51" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -7.5, 2.9, -4.5)
[node name="wall52" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -9.5, 2.9, -4.5)
[node name="wall53" parent="House" instance=ExtResource("3_37grx")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -11.5, 2.9, -4.5)
[node name="roof-flat-corner2" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 2.5, 2.9, 0.5)
[node name="roof-flat-corner3" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 2.9, 2.5)
[node name="roof-flat-side2" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.5, 2.9, 0.5)
[node name="roof-flat-side3" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, -1, 0, 1, 0, 1, 0, 1.31134e-07, 0.5, 2.9, 2.5)
[node name="border2" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, 1)
[node name="border3" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, 2.5)
[node name="border4" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, -2.5)
[node name="border9" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, -3.5)
[node name="border5" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, -1)
[node name="border6" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, 4)
[node name="border7" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, 5.5)
[node name="border8" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 3, 6.5)
[node name="border10" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -7.0625, 3, 7.5625)
[node name="border11" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -5.5625, 3, 7.5625)
[node name="border12" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -10.5625, 3, 7.5625)
[node name="border13" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -11.5625, 3, 7.5625)
[node name="border14" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -9.0625, 3, 7.5625)
[node name="border15" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -4.0625, 3, 7.5625)
[node name="border16" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -2.5625, 3, 7.5625)
[node name="border17" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -1.5625, 3, 7.5625)
[node name="border18" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, 1)
[node name="border19" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, 2.5)
[node name="border20" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, -2.5)
[node name="border21" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, -3.5)
[node name="border22" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, -1)
[node name="border23" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, 4)
[node name="border24" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, 5.5)
[node name="border25" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -12.5, 3, 6.5)
[node name="border26" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -5.9375, 3, -4.4375)
[node name="border27" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -7.4375, 3, -4.4375)
[node name="border28" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -2.4375, 3, -4.4375)
[node name="border29" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -1.4375, 3, -4.4375)
[node name="border30" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -3.9375, 3, -4.4375)
[node name="border31" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -8.9375, 3, -4.4375)
[node name="border32" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -10.4375, 3, -4.4375)
[node name="border33" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-2.18557e-07, 0, -1, 0, 1, 0, 1, 0, -2.18557e-07, -11.4375, 3, -4.4375)
[node name="border34" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.5, 3, 2.125)
[node name="border35" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.5, 3, 0.625)
[node name="border36" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.500001, 3, 5.625)
[node name="border37" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.500001, 3, 6.625)
[node name="border38" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.5, 3, 4.125)
[node name="border39" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.5, 3, -0.875)
[node name="border40" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.499999, 3, -2.375)
[node name="border41" parent="House" instance=ExtResource("8_rmadb")]
transform = Transform3D(-1, 0, 2.62268e-07, 0, 1, 0, -2.62268e-07, 0, -1, -0.499999, 3, -3.375)
[node name="column2" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, -4.5)
[node name="column3" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, -4.5)
[node name="column4" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 2.9, 7.5)
[node name="column5" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 7.5)
[node name="column6" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 7.5)
[node name="column7" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 7.5)
[node name="column8" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, -4.5)
[node name="column9" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, -4.5)
[node name="column10" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.5, 2.9, -4.5)
[node name="column11" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.5, 0.5, -4.5)
[node name="column12" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.5, 2.9, 7.5)
[node name="column13" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.5, 0.5, 7.5)
[node name="column14" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 2.9, 1.5)
[node name="column15" parent="House" instance=ExtResource("9_jpxld")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 1.5)
[node name="roof-flat-corner4" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 5.3, 7)
[node name="roof-flat-corner5" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1, 5.3, -4)
[node name="roof-flat-corner6" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, -12, 5.3, -4)
[node name="roof-flat-corner7" parent="House" instance=ExtResource("4_e3d5x")]
transform = Transform3D(1.31134e-07, 0, -1, 0, 1, 0, 1, 0, 1.31134e-07, -12, 5.3, 7)
[node name="roof-flat-side4" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -10.5, 5.3, 7)
[node name="roof-flat-side5" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -8.5, 5.3, 7)
[node name="roof-flat-side6" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -6.5, 5.3, 7)
[node name="roof-flat-side7" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -4.5, 5.3, 7)
[node name="roof-flat-side8" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -2.5, 5.3, 7)
[node name="roof-flat-side9" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -12, 5.3, -3)
[node name="roof-flat-side10" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -12, 5.3, -1)
[node name="roof-flat-side11" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -12, 5.3, 1)
[node name="roof-flat-side12" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -12, 5.3, 3)
[node name="roof-flat-side13" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -12, 5.3, 5)
[node name="roof-flat-side14" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -2.5, 5.3, -4)
[node name="roof-flat-side15" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -4.5, 5.3, -4)
[node name="roof-flat-side16" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -6.5, 5.3, -4)
[node name="roof-flat-side17" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -8.5, 5.3, -4)
[node name="roof-flat-side18" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1.31134e-07, 0, 1, 0, 1, 0, -1, 0, 1.31134e-07, -10.5, 5.3, -4)
[node name="roof-flat-side19" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -1, 5.3, 5)
[node name="roof-flat-side20" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -1, 5.3, 3)
[node name="roof-flat-side21" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -1, 5.3, 1)
[node name="roof-flat-side22" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -1, 5.3, -1)
[node name="roof-flat-side23" parent="House" instance=ExtResource("7_km368")]
transform = Transform3D(1, 0, -1.74846e-07, 0, 1, 0, 1.74846e-07, 0, 1, -1, 5.3, -3)
[node name="roof-flat-center2" parent="House" instance=ExtResource("10_5h2gx")]
transform = Transform3D(5, 0, 0, 0, 1, 0, 0, 0, 5, -6.5, 5.3, 1.5)
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_p5xd2")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.69407, -0.512887, 0.505188, 0.0341743, 0.724421, 0.68851, -0.719096, -0.46061, 0.520327, 6.21356, 1.32592, -0.575947)
shadow_enabled = true
[node name="Prism" type="MeshInstance3D" parent="."]
transform = Transform3D(0.679275, 0, 0.733884, 0, 1, 0, -0.733884, 0, 0.679275, 6.21356, 1.32592, -0.575947)
mesh = SubResource("PrismMesh_p5xd2")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Prism"]
mesh = SubResource("ArrayMesh_km368")
[node name="StaticBody3D" type="StaticBody3D" parent="Prism"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Prism/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_soise")

View File

@ -0,0 +1,124 @@
[gd_scene load_steps=15 format=4 uid="uid://drhaqr78kv1o2"]
[ext_resource type="Material" uid="uid://b7kc8jfs4fowj" path="res://addons/kenney_prototype_tools/materials/green/material_02.tres" id="1_2frux"]
[ext_resource type="PackedScene" uid="uid://dve8bvx87r1mm" path="res://models/kenney-house/wall-doorway-square.glb" id="2_hytsl"]
[ext_resource type="PackedScene" uid="uid://bfgvxrgm0dkgi" path="res://models/kenney-house/wall.glb" id="3_m1tf4"]
[ext_resource type="PackedScene" uid="uid://d3qx51q66eftg" path="res://models/kenney-house/roof-flat-corner.glb" id="4_iniy3"]
[ext_resource type="PackedScene" uid="uid://b0k0k4heruf3t" path="res://models/kenney-house/wall-window-square-detailed.glb" id="5_tbp4y"]
[ext_resource type="PackedScene" uid="uid://d347ojn6kwgn2" path="res://models/kenney-house/floor.glb" id="6_hytsl"]
[ext_resource type="PackedScene" uid="uid://birikia38m0g7" path="res://skybox_world_environment.tscn" id="7_m1tf4"]
[sub_resource type="BoxMesh" id="BoxMesh_blkr4"]
material = ExtResource("1_2frux")
size = Vector3(20, 1, 20)
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_2frux"]
data = PackedVector3Array(-10, 0.5, 10, 10, 0.5, 10, -10, -0.5, 10, 10, 0.5, 10, 10, -0.5, 10, -10, -0.5, 10, 10, 0.5, -10, -10, 0.5, -10, 10, -0.5, -10, -10, 0.5, -10, -10, -0.5, -10, 10, -0.5, -10, 10, 0.5, 10, 10, 0.5, -10, 10, -0.5, 10, 10, 0.5, -10, 10, -0.5, -10, 10, -0.5, 10, -10, 0.5, -10, -10, 0.5, 10, -10, -0.5, -10, -10, 0.5, 10, -10, -0.5, 10, -10, -0.5, -10, 10, 0.5, 10, -10, 0.5, 10, 10, 0.5, -10, -10, 0.5, 10, -10, 0.5, -10, 10, 0.5, -10, -10, -0.5, 10, 10, -0.5, 10, -10, -0.5, -10, 10, -0.5, 10, 10, -0.5, -10, -10, -0.5, -10)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m1tf4"]
albedo_color = Color(0.733333, 0.552941, 1, 1)
[sub_resource type="BoxMesh" id="BoxMesh_iniy3"]
material = SubResource("StandardMaterial3D_m1tf4")
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tbp4y"]
shading_mode = 0
albedo_color = Color(0, 0, 0, 1)
[sub_resource type="ArrayMesh" id="ArrayMesh_b8r5k"]
_surfaces = [{
"aabb": AABB(-0.511547, -0.511547, -0.511547, 1.02309, 1.02309, 1.02309),
"attribute_data": PackedByteArray("AAAAAAAAAACrqio/AAAAAKuqqj4AAAAAAACAPwAAAAAAAAAAAAAAP6uqKj8AAAA/q6qqPgAAAD8AAIA/AAAAP6uqqj4AAAAAAAAAAAAAAD+rqio/AAAAAKuqqj4AAAA/q6qqPgAAAD8AAAAAAACAP6uqKj8AAAA/q6qqPgAAgD+rqqo+AAAAP6uqKj8AAAA/q6oqPwAAAD8AAIA/AAAAP6uqqj4AAIA/q6oqPwAAgD+rqio/AACAPwAAgD8AAIA/"),
"format": 34359742487,
"index_count": 36,
"index_data": PackedByteArray("AAAEAAIAAgAEAAYAAQAFAAMAAwAFAAcACAAMAAoACgAMAA4ACQANAAsACwANAA8AEAAUABIAEgAUABYAEQAVABMAEwAVABcA"),
"material": SubResource("StandardMaterial3D_tbp4y"),
"name": "Outline",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 24,
"vertex_data": PackedByteArray("v/QCv7/0Aj+/9AI/v/QCP7/0Aj+/9AK/v/QCP7/0Aj+/9AI/v/QCv7/0Aj+/9AK/v/QCv7/0Ar+/9AI/v/QCP7/0Ar+/9AK/v/QCP7/0Ar+/9AI/v/QCv7/0Ar+/9AK/v/QCP7/0Aj+/9AI/v/QCv7/0Aj+/9AK/v/QCP7/0Aj+/9AK/v/QCv7/0Aj+/9AI/v/QCP7/0Ar+/9AI/v/QCv7/0Ar+/9AK/v/QCP7/0Ar+/9AK/v/QCv7/0Ar+/9AI/v/QCP7/0Aj+/9AI/v/QCv7/0Ar+/9AI/v/QCv7/0Aj+/9AI/v/QCP7/0Ar+/9AI/v/QCP7/0Aj+/9AK/v/QCv7/0Ar+/9AK/v/QCv7/0Aj+/9AK/v/QCP7/0Ar+/9AK//3//f////7//////AAD/v/9//3////+//////wAA/7//f/9/////v/////8AAP+//3//f////7//////AAD/v///AID/////AAAAgP9//7///wCA/////wAAAID/f/+///8AgP////8AAACA/3//v///AID/////AAAAgP9//78AgP//AAD/vwCAAAD///+/AID//wAA/78AgAAA////vwCA//8AAP+/AIAAAP///78AgP//AAD/vwCAAAD///+/")
}]
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_m1tf4"]
data = PackedVector3Array(-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5)
[node name="room_hermione_outside" type="Node3D"]
[node name="Ground" type="MeshInstance3D" parent="."]
mesh = SubResource("BoxMesh_blkr4")
metadata/_edit_lock_ = true
[node name="StaticBody3D" type="StaticBody3D" parent="Ground"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_2frux")
[node name="House" type="Node3D" parent="."]
[node name="wall-doorway-square2" parent="House" instance=ExtResource("2_hytsl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.5, 0.5, 0.5)
[node name="wall3" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 2.5)
[node name="wall7" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, 0.5)
[node name="wall4" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 2.5, 0.5, 3.5)
[node name="wall8" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 0.5, 3.5)
[node name="wall5" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 2.5, 0.5, -0.5)
[node name="wall6" parent="House" instance=ExtResource("3_m1tf4")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 0.5, -0.5)
[node name="roof-flat-corner2" parent="House" instance=ExtResource("4_iniy3")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 2.88135, 2.5)
[node name="roof-flat-corner3" parent="House" instance=ExtResource("4_iniy3")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 2.5, 2.88135, 0.5)
[node name="roof-flat-corner4" parent="House" instance=ExtResource("4_iniy3")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, 0.5, 2.88135, 0.5)
[node name="roof-flat-corner5" parent="House" instance=ExtResource("4_iniy3")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 2.88135, 2.5)
[node name="wall-window-square-detailed2" parent="House" instance=ExtResource("5_tbp4y")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.5, 0.5, 2.5)
[node name="floor2" parent="." instance=ExtResource("6_hytsl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 0.5, 0.5)
[node name="floor3" parent="." instance=ExtResource("6_hytsl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 0.5, 2.5)
[node name="floor4" parent="." instance=ExtResource("6_hytsl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0.5, 0.5)
[node name="floor5" parent="." instance=ExtResource("6_hytsl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0.5, 2.5)
[node name="WorldEnvironment2" parent="." instance=ExtResource("7_m1tf4")]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.999197, -0.0103569, -0.0386982, 0.0341743, 0.724421, 0.68851, 0.0209029, -0.68928, 0.724194, 0, 0, 0)
shadow_enabled = true
[node name="Cube" type="MeshInstance3D" parent="."]
transform = Transform3D(0.823869, 0, 0.56678, 0, 1, 0, -0.56678, 0, 0.823869, 6.09669, 1.73711, 3.18691)
mesh = SubResource("BoxMesh_iniy3")
metadata/_edit_group_ = true
[node name="MeshInstance3D" type="MeshInstance3D" parent="Cube"]
mesh = SubResource("ArrayMesh_b8r5k")
[node name="StaticBody3D" type="StaticBody3D" parent="Cube"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Cube/StaticBody3D"]
shape = SubResource("ConcavePolygonShape3D_m1tf4")

View File

@ -0,0 +1,48 @@
@tool
extends Node3D
func _add_inspector_buttons() -> Array:
var buttons: Array = []
buttons.push_back({
"name": "Regular cube mesh",
"pressed": _add_regular_cube_mesh
})
buttons.push_back({
"name": "Internal cube mesh",
"pressed": _add_internal_cube_mesh
})
buttons.push_back({
"name": "Delete all children",
"pressed": func(): for child in get_children(true): child.queue_free()
})
return buttons
func _add_regular_cube_mesh() -> void:
var m = MeshInstance3D.new()
var b = BoxMesh.new()
m.mesh = b
add_child(m, true)
m.owner = self
m.position.x = 1.5 * get_child_count(true)
func _add_internal_cube_mesh() -> void:
var m = MeshInstance3D.new()
var b = BoxMesh.new()
m.mesh = b
add_child(m, true, Node.INTERNAL_MODE_BACK)
var mat = StandardMaterial3D.new()
mat.albedo_color = Color("ff4c4e")
b.material = mat
# Lock the node in editor. Prevents selection (here for internal nodes)
# UNDOCUMENTED
# https://github.com/godotengine/godot-proposals/issues/3046
m.set_meta("_edit_lock_", true)
m.owner = self
m.position.x = 1.5 * get_child_count(true)

View File

@ -0,0 +1 @@
uid://ouk76qr5gpq0

View File

@ -0,0 +1,40 @@
[gd_scene load_steps=8 format=3 uid="uid://bnrph4k6wpruy"]
[ext_resource type="Script" uid="uid://ouk76qr5gpq0" path="res://levels/test_internal_nodes.gd" id="1_glqbe"]
[sub_resource type="BoxMesh" id="BoxMesh_glqbe"]
[sub_resource type="BoxMesh" id="BoxMesh_dodl2"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wgeau"]
albedo_color = Color(1, 0.298039, 0.305882, 1)
[sub_resource type="BoxMesh" id="BoxMesh_j0q2q"]
material = SubResource("StandardMaterial3D_wgeau")
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_47wcs"]
albedo_color = Color(1, 0.298039, 0.305882, 1)
[sub_resource type="BoxMesh" id="BoxMesh_bkhqo"]
material = SubResource("StandardMaterial3D_47wcs")
[node name="test_internal_nodes" type="Node3D"]
script = ExtResource("1_glqbe")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.5, 0, 0)
mesh = SubResource("BoxMesh_glqbe")
[node name="MeshInstance3D4" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, 0)
mesh = SubResource("BoxMesh_dodl2")
[node name="MeshInstance3D2" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0)
mesh = SubResource("BoxMesh_j0q2q")
metadata/_edit_lock_ = true
[node name="MeshInstance3D3" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.5, 0, 0)
mesh = SubResource("BoxMesh_bkhqo")
metadata/_edit_lock_ = true

View File

@ -0,0 +1,77 @@
[gd_scene load_steps=8 format=4 uid="uid://c0ieh1abu1xne"]
[ext_resource type="Material" uid="uid://bv36triwinl2f" path="res://textures/uv-checker-material.tres" id="1_dn1le"]
[ext_resource type="Script" uid="uid://d2bvvjsibau8c" path="res://addons/simple-portal-system/scripts/portal.gd" id="1_ksg6r"]
[ext_resource type="PackedScene" uid="uid://d1dtxvwk86ple" path="res://procedural_mesh_maker.tscn" id="2_4vena"]
[sub_resource type="ArrayMesh" id="ArrayMesh_1w8eh"]
_surfaces = [{
"aabb": AABB(-1, -1.3, -0.133, 2, 2.6, 0.133),
"attribute_data": PackedByteArray("AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAgD8nMYg9soZRPdv5bj+yhlE9JzGIPZXncj/b+W4/ledyPw=="),
"format": 34359742487,
"index_count": 30,
"index_data": PackedByteArray("AAABAAQABAABAAUAAQADAAUABQADAAcAAwACAAcABwACAAYAAgAAAAYABgAAAAQABAAFAAYABgAFAAcA"),
"material": ExtResource("1_dn1le"),
"name": "Portal Material",
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AACAv2Zmpj8AAAAAAACAP2Zmpj8AAAAAAACAv2Zmpr8AAAAAAACAP2Zmpr8AAAAAtvNdv0FglT8nMQi+tvNdP0FglT8nMQi+tvNdv0Fglb8nMQi+tvNdP0Fglb8nMQi+/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgP9//3//fwCA/3//f/9/AID/f/9//38AgA==")
}]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_82kw5"]
[sub_resource type="ArrayMesh" id="ArrayMesh_dn1le"]
_surfaces = [{
"aabb": AABB(-1.02429, -1.3, -0.2, 2.04857, 2.60001, 0.20001),
"format": 34896613377,
"index_count": 30,
"index_data": PackedByteArray("BwAFAAQABwAEAAYAAQAHAAMAAQAFAAcAAgAEAAAAAgAGAAQAAwAGAAIAAwAHAAYAAAAFAAEAAAAEAAUA"),
"lods": [0.156674, PackedByteArray("AwAFAAAAAQAFAAMAAwAAAAIAAAAFAAEA")],
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 8,
"vertex_data": PackedByteArray("AAD+//v/AAAAAAAA+/8AAP///v/7/wAA/v8AAPv/AACZGWXmAAAAAJkZmRkAAAAAZeZl5gAAAABl5pkZAAAAAA==")
}]
blend_shape_mode = 0
[sub_resource type="ArrayMesh" id="ArrayMesh_u54xs"]
resource_name = "room_Plane_001"
_surfaces = [{
"aabb": AABB(-1.02429, -1.3, -0.2, 2.04857, 2.60001, 0.20001),
"attribute_data": PackedByteArray("AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//"),
"format": 34896613399,
"index_count": 30,
"index_data": PackedByteArray("EQALAAgAEQAIAA4AAgASAAYAAgAMABIABAAJAAAABAAPAAkABwAQAAUABwATABAAAQANAAMAAQAKAA0A"),
"lods": [0.156674, PackedByteArray("BgAWAAAAAgAWAAYABgAAAAQAFAAXABUA")],
"material": SubResource("StandardMaterial3D_82kw5"),
"primitive": 3,
"uv_scale": Vector4(0, 0, 0, 0),
"vertex_count": 24,
"vertex_data": PackedByteArray("AAD+//v/SGUAAP7/+/8AagAAAAD7/0hlAAAAAPv/AGr///7/+/9IZf///v/7/wBq/v8AAPv/SGX+/wAA+/8AapkZZeYAAP5/mRll5gAASGWZGWXmAAAAapkZmRkAAP5/mRmZGQAASGWZGZkZAAAAamXmZeYAAP5/ZeZl5gAASGVl5mXmAAAAamXmmRkAAP5/ZeaZGQAASGVl5pkZAAAAagAA/v/7/wBqAAAAAPv/AGqZGZkZAAD1b5kZmRkAAABqAAD/f/9/AAD///9//38AAAAA/3//f///////f/9/////f///AAD/f/9/AAD/f///////f/9/AAD/f///AAD/f/9/////f///////f/9/////fwAA/38AAP///3//fwAA")
}]
blend_shape_mode = 0
shadow_mesh = SubResource("ArrayMesh_dn1le")
[node name="ProceduralPortal" type="Node3D"]
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.4625e-05, -0.0007523, 0.000824571)
mesh = SubResource("ArrayMesh_1w8eh")
script = ExtResource("1_ksg6r")
[node name="ProceduralMeshMaker" parent="." node_paths=PackedStringArray("portal") instance=ExtResource("2_4vena")]
height = 2.6
width = 2.0
indent = 0.133
portal = NodePath("../MeshInstance3D")
portal_material = ExtResource("1_dn1le")
[node name="OmniLight3D" type="OmniLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.52963, 0, 1.51112)
metadata/_edit_lock_ = true
[node name="OfficialPortal" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.5, 0, 0)
mesh = SubResource("ArrayMesh_u54xs")
metadata/_edit_lock_ = true

20
menu.gd
View File

@ -1,17 +1,23 @@
extends Control
const LEVEL_5_ROOMS = preload("res://levels/level_5rooms.tscn")
const LEVEL_3_ROOMS = preload("res://levels/level_3_rooms.tscn")
const LEVEL_PLATFORMER = preload("res://levels/level_platformer.tscn")
const LEVEL_SEMAPHORE_LIGHTS = preload("res://levels/level_semaphore_lights.tscn")
const LEVEL_5_ROOMS: PackedScene = preload("res://levels/level_5rooms.tscn")
const LEVEL_3_ROOMS: PackedScene = preload("res://levels/level_3_rooms.tscn")
const LEVEL_PLATFORMER: PackedScene = preload("res://levels/level_platformer.tscn")
const LEVEL_SEMAPHORE_LIGHTS: PackedScene = preload("res://levels/level_semaphore_lights.tscn")
const LEVEL_CUBE_PORTALS: PackedScene = preload("res://levels/level_cube_portals.tscn")
const LEVEL_HERMIONE: PackedScene = preload("res://levels/level_hermione.tscn")
const LEVEL_TEST_PORTAL_DELAY: PackedScene = preload("res://levels/level_test_portal_delay.tscn")
@onready var items_container: VBoxContainer = $CenterContainer/ItemsContainer
var levels = {
var levels: Dictionary = {
"Semaphore": LEVEL_3_ROOMS,
"Semaphore - Lights": LEVEL_SEMAPHORE_LIGHTS,
"Semaphore - Lights Demo": LEVEL_SEMAPHORE_LIGHTS,
"5 rooms": LEVEL_5_ROOMS,
"Infinite fall": LEVEL_PLATFORMER
"Platform": LEVEL_PLATFORMER,
"Recurisve portals - WIP": LEVEL_CUBE_PORTALS,
"Multiple Worlds - WIP": LEVEL_HERMIONE,
"No Portal Delay?": LEVEL_TEST_PORTAL_DELAY
}
func _ready() -> void:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dnphrf6dekgvn"
path.s3tc="res://.godot/imported/colormap.png-be25d4a14434f049e9335c9189c05045.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://models/kenney-house/Textures/colormap.png"
dest_files=["res://.godot/imported/colormap.png-be25d4a14434f049e9335c9189c05045.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b57f1w1ffvjfl"
path="res://.godot/imported/border-corner.glb-0619254f56d70d0adb4dd42ae782ecba.scn"
[deps]
source_file="res://models/kenney-house/border-corner.glb"
dest_files=["res://.godot/imported/border-corner.glb-0619254f56d70d0adb4dd42ae782ecba.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:border-corner": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://d3yk6et3d4yw3"
path="res://.godot/imported/border.glb-a1fe17af1c6910d583cef042a5a9701c.scn"
[deps]
source_file="res://models/kenney-house/border.glb"
dest_files=["res://.godot/imported/border.glb-a1fe17af1c6910d583cef042a5a9701c.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:border": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://dsogp3m6bedxp"
path="res://.godot/imported/column.glb-657830aafa2c47310bb1b8ff06063167.scn"
[deps]
source_file="res://models/kenney-house/column.glb"
dest_files=["res://.godot/imported/column.glb-657830aafa2c47310bb1b8ff06063167.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:column": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,44 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://re7f0x1ke0md"
path="res://.godot/imported/door-rotate-square-c.glb-c1417ec31599a90af74fc57ed5f2acb5.scn"
[deps]
source_file="res://models/kenney-house/door-rotate-square-c.glb"
dest_files=["res://.godot/imported/door-rotate-square-c.glb-c1417ec31599a90af74fc57ed5f2acb5.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:door-rotate-square-c/door": {
"generate/physics": true,
"physics/body_type": 1
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://d347ojn6kwgn2"
path="res://.godot/imported/floor.glb-e753c3bd35066eef24427a939bbbfb1d.scn"
[deps]
source_file="res://models/kenney-house/floor.glb"
dest_files=["res://.godot/imported/floor.glb-e753c3bd35066eef24427a939bbbfb1d.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:floor": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b4mndlgalycyh"
path="res://.godot/imported/roof-flat-center.glb-8f23942169210678242eb92cebea49e3.scn"
[deps]
source_file="res://models/kenney-house/roof-flat-center.glb"
dest_files=["res://.godot/imported/roof-flat-center.glb-8f23942169210678242eb92cebea49e3.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:roof-flat-center": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://d3qx51q66eftg"
path="res://.godot/imported/roof-flat-corner.glb-a0c084a0d7800dcdcdbe5f633c05990c.scn"
[deps]
source_file="res://models/kenney-house/roof-flat-corner.glb"
dest_files=["res://.godot/imported/roof-flat-corner.glb-a0c084a0d7800dcdcdbe5f633c05990c.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:roof-flat-corner": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://yqsv32xecxbr"
path="res://.godot/imported/roof-flat-side.glb-ab557049d2eaf7cef25c926db44909ce.scn"
[deps]
source_file="res://models/kenney-house/roof-flat-side.glb"
dest_files=["res://.godot/imported/roof-flat-side.glb-ab557049d2eaf7cef25c926db44909ce.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:roof-flat-side": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://cy4givcixjenc"
path="res://.godot/imported/wall-corner.glb-1a25d3bf79cf2659eaabd5fbcdb07105.scn"
[deps]
source_file="res://models/kenney-house/wall-corner.glb"
dest_files=["res://.godot/imported/wall-corner.glb-1a25d3bf79cf2659eaabd5fbcdb07105.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:wall-corner": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://dve8bvx87r1mm"
path="res://.godot/imported/wall-doorway-square.glb-7714b1be5989e7155fddd458ccfec05b.scn"
[deps]
source_file="res://models/kenney-house/wall-doorway-square.glb"
dest_files=["res://.godot/imported/wall-doorway-square.glb-7714b1be5989e7155fddd458ccfec05b.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:wall-doorway-square": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,46 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b0k0k4heruf3t"
path="res://.godot/imported/wall-window-square-detailed.glb-7ae5d3f7bbc0fc7ff27a838bc27dee6b.scn"
[deps]
source_file="res://models/kenney-house/wall-window-square-detailed.glb"
dest_files=["res://.godot/imported/wall-window-square-detailed.glb-7ae5d3f7bbc0fc7ff27a838bc27dee6b.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:wall-window-square-detailed": {
"generate/physics": true
},
"PATH:wall-window-square-detailed/(_ignore)": {
"import/skip_import": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

View File

@ -0,0 +1,43 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bfgvxrgm0dkgi"
path="res://.godot/imported/wall.glb-1123b951cefd776d3d2bae84553f3095.scn"
[deps]
source_file="res://models/kenney-house/wall.glb"
dest_files=["res://.godot/imported/wall.glb-1123b951cefd776d3d2bae84553f3095.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
_subresources={
"nodes": {
"PATH:wall": {
"generate/physics": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=1

105
models/portal_mesh.gd Normal file
View File

@ -0,0 +1,105 @@
@tool
extends ArrayMesh
class_name PortalMesh
@export_range(0.1, 10, 0.01) var height: float = 2.0:
set(new_val):
height = new_val
generate_portal_mesh()
@export_range(0.1, 10, 0.01) var width: float = 1.0:
set(new_val):
width = new_val
generate_portal_mesh()
## Player camera's NEAR clip distance
@export_range(0, 0.2, 0.001) var indent: float = 0.1:
set(new_val):
indent = new_val
generate_portal_mesh()
func _init() -> void:
if Engine.is_editor_hint():
generate_portal_mesh()
func generate_portal_mesh() -> void:
print("[PortalMesh] Creating mesh")
var _start_time: int = Time.get_ticks_usec()
clear_surfaces() # Reset
var surface_array: Array = []
surface_array.resize(Mesh.ARRAY_MAX)
var verts: PackedVector3Array = PackedVector3Array()
var uvs: PackedVector2Array = PackedVector2Array()
var normals: PackedVector3Array = PackedVector3Array()
var indices: PackedInt32Array = PackedInt32Array()
# Just to save some chars
var w: float = width / 2
var h: float = height / 2
# Outside rect
var TOP_LEFT: Vector3 = Vector3(-w, h, 0)
var TOP_RIGHT: Vector3 = Vector3(w, h, 0)
var BOTTOM_LEFT: Vector3 = Vector3(-w, -h, 0)
var BOTTOM_RIGHT: Vector3 = Vector3(w, -h, 0)
# Inside rect, indented
var INDENT_TL: Vector3 = TOP_LEFT + Vector3(indent, -indent, -indent)
var INDENT_TR: Vector3 = TOP_RIGHT + Vector3(-indent, -indent, -indent)
var INDENT_BL: Vector3 = BOTTOM_LEFT + Vector3(indent, indent, -indent)
var INDENT_BR: Vector3 = BOTTOM_RIGHT + Vector3(-indent, indent, -indent)
verts.append_array([
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
INDENT_TL, INDENT_TR, INDENT_BL, INDENT_BR
])
var ix: float = indent / width
var iy: float = indent / height
uvs.append_array([
Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), # Outside UVs
Vector2(ix, iy), Vector2(1-ix, iy), Vector2(ix, 1-iy), Vector2(1-ix, 1-iy) # Indented UVs
])
# We are going for a flat-surface look here. Portals should be unshaded anyways.
normals.append_array([
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK,
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK
])
# 0 ----------- 1
# | \ / |
# | 4-------5 |
# | | | |
# | | | |
# | 6-------7 |
# | / \ |
# 2 ----------- 3
# Triangles are clockwise!
indices.append_array([
0, 1, 4,
4, 1, 5, # Top section done
1, 3, 5,
5, 3, 7, # right section done
3, 2, 7,
7, 2, 6, # bottom section done
2, 0, 6,
6, 0, 4, # left section done
4, 5, 6,
6, 5, 7, # middle sectiondone
])
surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices
add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
print("[PortalMesh] Done in %f ms" % [(Time.get_ticks_usec() - _start_time) / 1000.0])

View File

@ -0,0 +1 @@
uid://s5kb624h26hs

View File

@ -1,6 +1,6 @@
extends CharacterBody3D
@onready var camera: Camera3D = $Camera3D
@onready var camera: Camera3D = $PlayerCamera
const SPEED = 5.0
const JUMP_VELOCITY = 4.5

View File

@ -17,7 +17,7 @@ height = 1.75
script = ExtResource("1_4flbx")
metadata/teleportable = false
[node name="Camera3D" type="Camera3D" parent="."]
[node name="PlayerCamera" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.32153, 0)
cull_mask = 1048571

View File

@ -16,3 +16,4 @@ func _ready() -> void:
for p in get_tree().get_nodes_in_group("portals"):
if p is Portal:
p.exit_environment = adapted_env

View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cxopylew5786r"]
[ext_resource type="Script" uid="uid://cili3lyodjqel" path="res://portal_environment_adapter.gd" id="1_5srpn"]
[node name="PortalEnvironmentAdapter" type="Node"]
script = ExtResource("1_5srpn")

132
procedural_mesh_maker.gd Normal file
View File

@ -0,0 +1,132 @@
@tool
extends Node
@export_tool_button("Generate Portal Mesh")
var _generate_portal_mesh: Callable = generate_portal_mesh
@export_tool_button("Remove Mesh")
var _remove_mesh: Callable = func(): portal.mesh = null
@export var portal: Portal
@export_range(0.1, 10, 0.01) var height: float = 2.0:
set(v):
height = v
if Engine.is_editor_hint(): generate_portal_mesh()
@export_range(0.1, 10, 0.01) var width: float = 1.0:
set(v):
width = v
if Engine.is_editor_hint(): generate_portal_mesh()
## Player camera's NEAR clip distance
@export_range(0, 0.2, 0.001) var indent: float = 0.1:
set(v):
indent = v
generate_portal_mesh()
@export var portal_material: BaseMaterial3D
func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []
if portal == null:
warnings.append("Assign a portal to generate the mesh for")
return warnings
func generate_portal_mesh() -> void:
if portal == null:
push_error("No portal")
return
if portal.mesh != null:
push_warning("The portal %s already has a mesh! Replacing." % portal.name)
portal.mesh = null
var mesh = ArrayMesh.new()
print("[PMM] Creating mesh")
var surface_array: Array = []
surface_array.resize(Mesh.ARRAY_MAX)
var verts: PackedVector3Array = PackedVector3Array()
var uvs: PackedVector2Array = PackedVector2Array()
var normals: PackedVector3Array = PackedVector3Array()
var indices: PackedInt32Array = PackedInt32Array()
# Just to save some chars
var w: float = width / 2
var h: float = height / 2
# Outside rect
var TOP_LEFT: Vector3 = Vector3(-w, h, 0)
var TOP_RIGHT: Vector3 = Vector3(w, h, 0)
var BOTTOM_LEFT: Vector3 = Vector3(-w, -h, 0)
var BOTTOM_RIGHT: Vector3 = Vector3(w, -h, 0)
# Inside rect, indented
var INDENT_TL: Vector3 = TOP_LEFT + Vector3(indent, -indent, -indent)
var INDENT_TR: Vector3 = TOP_RIGHT + Vector3(-indent, -indent, -indent)
var INDENT_BL: Vector3 = BOTTOM_LEFT + Vector3(indent, indent, -indent)
var INDENT_BR: Vector3 = BOTTOM_RIGHT + Vector3(-indent, indent, -indent)
verts.append_array([
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
INDENT_TL, INDENT_TR, INDENT_BL, INDENT_BR
])
var ix: float = indent / width
var iy: float = indent / height
uvs.append_array([
Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), # Outside UVs
Vector2(ix, iy), Vector2(1-ix, iy), Vector2(ix, 1-iy), Vector2(1-ix, 1-iy) # Indented UVs
])
# We are going for a flat-surface look here. Portals should be unshaded anyways.
normals.append_array([
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK,
Vector3.BACK, Vector3.BACK, Vector3.BACK, Vector3.BACK
])
# 0 ----------- 1
# | \ / |
# | 4-------5 |
# | | | |
# | | | |
# | 6-------7 |
# | / \ |
# 2 ----------- 3
# Triangles are clockwise!
indices.append_array([
0, 1, 4,
4, 1, 5, # Top section done
1, 3, 5,
5, 3, 7, # right section done
3, 2, 7,
7, 2, 6, # bottom section done
2, 0, 6,
6, 0, 4, # left section done
4, 5, 6,
6, 5, 7, # middle sectiondone
])
surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
if portal_material:
mesh.surface_set_material(0, portal_material)
mesh.surface_set_name(0, "Portal Material")
portal.mesh = mesh
print("[PMM] Mesh assigned")

View File

@ -0,0 +1 @@
uid://xt85yw2lp6dw

View File

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://d1dtxvwk86ple"]
[ext_resource type="Script" uid="uid://xt85yw2lp6dw" path="res://procedural_mesh_maker.gd" id="1_1a4ua"]
[node name="ProceduralMeshMaker" type="Node"]
script = ExtResource("1_1a4ua")

View File

@ -14,12 +14,23 @@ config/name="DP Konzultace"
run/main_scene="uid://cim3ul77o0ipr"
config/features=PackedStringArray("4.4", "Forward Plus")
config/icon="res://icon.svg"
config/tags=PackedStringArray("dp")
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
[editor_plugins]
enabled=PackedStringArray("res://addons/inspector_buttons/plugin.cfg")
[file_customization]
folder_colors={
"res://addons/": "blue"
}
[input]
move_left={
@ -42,6 +53,11 @@ move_back={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
]
}
debug_teleport={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null)
]
}
[layer_names]

100
scripts/my_portal.gd Normal file
View File

@ -0,0 +1,100 @@
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

1
scripts/my_portal.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://dh8miiv7xc4ps

View File

@ -0,0 +1,25 @@
shader_type spatial;
render_mode unshaded;
uniform sampler2D albedo: hint_default_black, source_color;
varying float pixel_distance;
void vertex() {
// Calculate the world-space distance between the pixel and camera.
// Pass the distance to the fragment shader using a varying attribute.
vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
vec3 camera_position = (INV_VIEW_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
pixel_distance = distance(world_position, camera_position);
}
void fragment() {
// The portal color is simply the screen-space color of the exit camera render target.
// This is because the exit camera views the exit portal from the perspective of the player watching
// the entrance portal, meaning the exit portal will occupy the same screen-space as the entrance portal.
vec3 portal_color = texture(albedo, SCREEN_UV).rgb;
ALBEDO = portal_color;
}

View File

@ -0,0 +1 @@
uid://b6cs66n3vj4di

View File

@ -0,0 +1,7 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://cwobk5ik5k5aj"]
[ext_resource type="Shader" uid="uid://b6cs66n3vj4di" path="res://scripts/my_portal.gdshader" id="1_3tu08"]
[resource]
render_priority = 0
shader = ExtResource("1_3tu08")

View File

@ -0,0 +1,19 @@
[gd_scene load_steps=5 format=3 uid="uid://birikia38m0g7"]
[ext_resource type="Texture2D" uid="uid://cvxwlhcjdg7u7" path="res://textures/kloppenheim_06_puresky_2k.exr" id="1_5twt8"]
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_ghyw7"]
panorama = ExtResource("1_5twt8")
[sub_resource type="Sky" id="Sky_jfr1b"]
sky_material = SubResource("PanoramaSkyMaterial_ghyw7")
[sub_resource type="Environment" id="Environment_jdap8"]
background_mode = 2
sky = SubResource("Sky_jfr1b")
tonemap_mode = 1
tonemap_exposure = 0.53
glow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment"]
environment = SubResource("Environment_jdap8")

Binary file not shown.

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cvxwlhcjdg7u7"
path.bptc="res://.godot/imported/kloppenheim_06_puresky_2k.exr-160a1911b7cbaf5d31339e358952146a.bptc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/kloppenheim_06_puresky_2k.exr"
dest_files=["res://.godot/imported/kloppenheim_06_puresky_2k.exr-160a1911b7cbaf5d31339e358952146a.bptc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@ -0,0 +1,7 @@
[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bv36triwinl2f"]
[ext_resource type="Texture2D" uid="uid://ya8afistbdec" path="res://textures/uv-checker.png" id="1_xdbe0"]
[resource]
shading_mode = 0
albedo_texture = ExtResource("1_xdbe0")

BIN
textures/uv-checker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ya8afistbdec"
path.s3tc="res://.godot/imported/uv-checker.png-26b18af46d2dfdb0ee67624bb4da1f2d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/uv-checker.png"
dest_files=["res://.godot/imported/uv-checker.png-26b18af46d2dfdb0ee67624bb4da1f2d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0