diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 984709907..d2c7df934 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -123,7 +123,7 @@ jobs:
cc: "cl"
cxx: "cl"
configure-options: -DCMAKE_TOOLCHAIN_FILE='${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake'
- -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_HEADLESS=ON -G Ninja
+ -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_EDITOR=OFF -DATLAS_HEADLESS=ON -G Ninja
parallel: 16
build-type: ${{ matrix.build-type }}
@@ -256,7 +256,7 @@ jobs:
cc: "gcc"
cxx: "g++"
configure-options: -DCMAKE_TOOLCHAIN_FILE='${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake'
- -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_HEADLESS=ON -G Ninja
+ -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_EDITOR=OFF -DATLAS_HEADLESS=ON -G Ninja
parallel: 16
build-type: ${{ matrix.build-type }}
@@ -385,7 +385,7 @@ jobs:
cc: "clang"
cxx: "clang++"
configure-options: -DCMAKE_TOOLCHAIN_FILE='${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake'
- -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_HEADLESS=ON -G Ninja
+ -DATLAS_TESTS=ON -DATLAS_BINDLESS=OFF -DATLAS_EDITOR=OFF -DATLAS_HEADLESS=ON -G Ninja
parallel: 16
build-type: ${{ matrix.build-type }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b3b6fff5a..c1c2dfeaf 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,6 +33,15 @@ jobs:
with:
committish: 5786fcb0cb5eb08d1931a230dad9701e7a6c37f0
+ - name: Delete MSVC tool version
+ shell: pwsh
+ # Add additional scripting steps here
+ run: |
+ cd 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build'
+ Get-ChildItem -Recurse *
+ Remove-Item * -Include 'Microsoft.VCToolsVersion.v143.default.props','Microsoft.VCToolsVersion.v143.default.txt' -Force | Out-Null
+ Get-ChildItem -Recurse *
+
- name: Setup Microsoft Visual C++ CLI
uses: ilammy/msvc-dev-cmd@v1
diff --git a/.gitignore b/.gitignore
index b03b87f67..58377fdad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,6 @@ data/emissive mesh
data/flying world
data/living room
data/mis
+data/ancient
+data/farm
+data/town
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3c963aeea..555202012 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,7 +54,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if (CYGWIN OR MINGW)
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -O3 -std=gnu++11" )
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -O3 -std=gnu++20" )
endif()
if (ANDROID)
@@ -91,6 +91,8 @@ find_package(glslang CONFIG REQUIRED)
find_package(SPIRV-Tools-opt CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(unofficial-joltphysics CONFIG REQUIRED)
+find_package(Lua REQUIRED)
+find_package(sol2 CONFIG REQUIRED)
if (ATLAS_TESTS)
find_package(GTest CONFIG REQUIRED)
diff --git a/README.md b/README.md
index 031cec409..80ba5b16e 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,8 @@

*Realtime Sponza scene with raytraced GI, AO and reflections (model from [Intel Graphics Research Sample Library](https://www.intel.com/content/www/us/en/developer/topic-technology/graphics-research/samples.html))*
## Introduction
This is a cross platform toy engine developed in my spare time that is available on Linux, Windows and MacOS.
+>**Note:**
+>The current version (0.2.0) contains many API changes and is still an active WIP
## Requirements
- Vulkan SDK
- C++20 compatible compiler
@@ -22,8 +24,6 @@ or while doing the build configuration with CMake. To use vcpkg together with CM
### Compiling the demo application
Run CMake with the option ATLAS_DEMO=ON to include the demo application in the project. For easier use, the vsbuild.bat does exactly
that and launches Visual Studio afterwards. After launching the IDE, set AtlasEngineDemo as your target.
->**Note:**
->In order to start the application properly you might need to change the asset directory in the [demo source file](https://github.com/tippesi/Atlas-Engine/blob/master/src/demo/App.cpp).
### Including the library into your own project
It is possible to compile the engine either as a shared or static library. Set the ATLAS_BUILD_SHARED option accordingly. To make
the library work with its dependencies, the root CMakeLists.txt of this repository has to be added as a subdirectory. As an entry
@@ -66,10 +66,14 @@ in the LICENSE.md file in the dependency directory.
>The files in the data folder (except the shaders) use a different license.
## Code Example
For a code example have a look at the [demo application](https://github.com/tippesi/Atlas-Engine/tree/master/src/demo).
+## Latest executables
+The latest non-release executables can be found in the latest run of the [build pipeline](https://github.com/tippesi/Atlas-Engine/actions/workflows/build.yml?query=branch%3Amaster). They contain both the demo application and the editor.
## Screenshots
-
-*Rasterized image using real time global illumination*
+
+*Sponza demo scene opened in the editor*
+
+*Rasterized image using real time global illumination*

*Path traced scene*
-
-*Island demo scene using the terrain and ocean systems*
+
+*Island demo scene using the terrain and ocean systems*
diff --git a/THIRDPARTY.md b/THIRDPARTY.md
index f7ede9e92..0964aa752 100644
--- a/THIRDPARTY.md
+++ b/THIRDPARTY.md
@@ -279,6 +279,38 @@ nlohmann-json
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+Lua
+---------------------------------------------------------------------------------
+ Copyright © 1994–2016 Lua.org, PUC-Rio.
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+sol2
+---------------------------------------------------------------------------------
+ The MIT License (MIT)
+
+ Copyright (c) 2013-2022 Rapptz, ThePhD, and contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ the Software, and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
JoltPhysics
---------------------------------------------------------------------------------
Copyright 2021 Jorrit Rouwe
diff --git a/data/scenes/sponza.aescene b/data/scenes/sponza.aescene
index 36a8421a6..52ad6f8e1 100644
--- a/data/scenes/sponza.aescene
+++ b/data/scenes/sponza.aescene
@@ -1 +1 @@
-{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":0,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.0,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/sponza.obj","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":0,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/sponza.obj","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000003576278687,"y":1.0000003576278687,"z":1.0000005960464478}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.4756942391395569,"y":0.0001188219030154869,"z":-0.879611074924469},"j1":{"w":0.0,"x":0.5917150974273682,"y":-0.7398717403411865,"z":-0.3200998306274414},"j2":{"w":0.0,"x":-0.6508373618125916,"y":-0.6727486848831177,"z":0.35188230872154236},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500687122344971,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":3,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":1.0,"z":0.9999988079071045}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"id":6,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0475580133497715,"y":-8.188627589333919e-07,"z":0.06712339073419571},"j1":{"w":0.0,"x":-3.60343005922914e-06,"y":-0.1039920523762703,"z":1.2844517414123402e-06},"j2":{"w":0.0,"x":0.8159534335136414,"y":-3.541418118402362e-05,"z":-0.5781162977218628},"j3":{"w":1.0,"x":-9.601022720336914,"y":1.530970811843872,"z":-0.44825008511543274}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.800071716308594,"y":-0.2541283667087555},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":7,"mesh":{"dontCull":false,"resourcePath":"capsule.gltf","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-3.5021371841430664,"y":-0.030071139335632324,"z":-0.5684388279914856}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"stream":{"loop":false,"pitch":0.9998736278143617,"resourcePath":"/music.wav","time":16.005325020665758,"volume":0.0025881417095661163},"volume":1.0},"id":8,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":10,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752945274114609,"z":-0.49586528539657593}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424561738967896,"z":-2.4032680988311768}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399212688207626,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399219393730164,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.36356258392333984,"z":-1.7112126350402832}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037128012627363205,"y":-0.00020931441395077854,"z":0.08226257562637329},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.190154747149791e-07,"z":0.0004693435621447861},"j2":{"w":0.0,"x":-4.589554009726271e-06,"y":-0.9999959468841553,"z":-0.002544400980696082},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.3534649610519409,"z":-2.4043333530426025}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637528181076,"y":0.10399219393730164,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320755144581199,"y":-0.0055144052021205425,"z":0.08206621557474136},"j1":{"w":0.0,"x":-0.10396077483892441,"y":-0.0019217761000618339,"z":0.0016849995590746403},"j2":{"w":0.0,"x":0.017349572852253914,"y":-0.9975795745849609,"z":-0.0673345997929573},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094054222106934,"z":-2.3293323516845703}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.1374287605285645,"z":-2.286043643951416}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9848830308765173e-05,"y":-0.00011465383431641385,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.10399205982685089,"y":-5.103151488583535e-05,"z":-3.7807207263540477e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013935555471107364},"j3":{"w":1.0,"x":5.269709587097168,"y":0.35375744104385376,"z":-2.396353006362915}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399534553289413,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.45395728945732117,"y":1.9912066459655762,"z":-2.3605315685272217}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139379024505615,"z":-2.3714351654052734}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999988079071045}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0064202528446912766,"y":-0.002519079018384218,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.0044377571903169155,"z":0.008247978053987026},"j2":{"w":0.0,"x":-0.044952504336833954,"y":-0.9986188411712646,"z":-0.027167029678821564},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027955055236816,"z":-2.4178249835968018}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399165004491806,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.01507602445781231,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":33,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527723789215088,"z":0.6787291169166565}}}}],"id":9,"name":{"name":"Staircase"},"root":false},{"id":34,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":29,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":37,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":32,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554489850997925,"y":0.03446338698267937,"z":0.2931373119354248},"j1":{"w":0.0,"x":-0.09065437316894531,"y":0.9794195890426636,"z":0.18033011257648468},"j2":{"w":0.0,"x":-0.28088968992233276,"y":-0.19887040555477142,"z":0.9389097690582275},"j3":{"w":1.0,"x":-1.6795064210891724,"y":-0.4496800899505615,"z":6.649222373962402}}}}],"id":36,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.7511735558509827,"y":0.22571858763694763,"z":-0.6203140616416931},"j1":{"w":0.0,"x":-0.39222922921180725,"y":0.6032152771949768,"z":0.6944692730903625},"j2":{"w":0.0,"x":0.5309374332427979,"y":0.7649720907211304,"z":-0.3645859360694885},"j3":{"w":1.0,"x":-11.71251392364502,"y":4.754361152648926,"z":-4.003150939941406}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.6672989130020142,"y":0.0363946259021759,"z":0.7439002990722656},"j1":{"w":0.0,"x":0.5453938245773315,"y":0.7040697336196899,"z":0.45478731393814087},"j2":{"w":0.0,"x":-0.5072058439254761,"y":0.7091977000236511,"z":-0.48967432975769043},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":true,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":23.738000869750977,"y":18.340999603271484,"z":17.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"sharpness":50.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"enable":true,"gi":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"rt":true,"spatialFilterStrength":10.0,"temporalWeight":0.9520000219345093,"textureLevel":4,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"probeResolution":128},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"irradianceLimit":10.0,"opacityCheck":false,"radius":1.0,"rayCount":2,"rt":false,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896}}
\ No newline at end of file
+{"aabb":{"max":{"x":128.0,"y":128.0,"z":128.0},"min":{"x":-128.0,"y":-128.0,"z":-128.0}},"ao":{"enable":false,"opacityCheck":false,"radius":3.0,"rt":true,"sampleCount":16,"strength":1.0},"depth":5.0,"entities":[{"entities":[{"id":1,"light":{"color":{"x":1.0,"y":0.9254902005195618,"z":0.8196078538894653},"intensity":10.0,"isMain":true,"mobility":0,"properties":{"direction":{"x":0.0,"y":-1.0,"z":0.2800000011920929}},"shadow":{"allowDynamicEntities":false,"allowTerrain":true,"bias":0.800000011920929,"cascadeBlendDistance":2.5,"center":{"x":0.0,"y":0.0,"z":0.0},"distance":75.0,"edgeSoftness":0.05000000074505806,"followMainCamera":false,"isCascaded":false,"longRange":false,"longRangeDistance":1024.0,"resolution":2048,"splitCorrection":0.0,"useCubemap":false,"viewCount":1,"views":[{"farDistance":75.0,"frustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"nearDistance":0.0,"orthoSize":{"w":43.0,"x":-50.0,"y":50.0,"z":-41.0},"projectionMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"terrainFrustumMatrix":{"j0":{"w":0.0,"x":0.019999999552965164,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":-0.02380952425301075,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":-0.0002500000118743628},"j3":{"w":1.0,"x":0.0,"y":0.02380952425301075,"z":0.5}},"viewMatrix":{"j0":{"w":0.0,"x":-1.0,"y":0.0,"z":-0.0},"j1":{"w":0.0,"x":0.0,"y":0.26962992548942566,"z":0.9629640579223633},"j2":{"w":0.0,"x":0.0,"y":0.9629640579223633,"z":-0.26962992548942566},"j3":{"w":1.0,"x":-0.0,"y":-0.0,"z":0.0}}}]},"type":0,"volumetric":true},"name":{"name":"Directional light"}},{"id":2,"mesh":{"dontCull":false,"resourcePath":"sponza/sponza.obj","visible":true},"name":{"name":"Sponza"},"rigidBody":{"bodyIndex":32,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"sponza/sponza.obj","scale":{"x":0.012193998321890831,"y":0.012000000104308128,"z":0.012193998321890831}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.012193998321890831,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.012000000104308128,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.012193998321890831},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}},{"id":3,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":0,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0000003576278687,"y":1.0000003576278687,"z":1.0000005960464478}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.4756948947906494,"y":0.00011953715875279158,"z":-0.8796106576919556},"j1":{"w":0.0,"x":0.5917145013809204,"y":-0.739871621131897,"z":-0.32010072469711304},"j2":{"w":0.0,"x":-0.6508373022079468,"y":-0.6727486252784729,"z":0.3518824875354767},"j3":{"w":1.0,"x":-15.995047569274902,"y":0.9694054126739502,"z":0.2113814800977707}}}},{"id":4,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Wall"},"rigidBody":{"bodyIndex":1,"creationSettings":{"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":1.0,"scale":{"x":0.1481112539768219,"y":0.17914418876171112,"z":2.874448299407959}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.12404608726501465,"y":-7.875383403188607e-07,"z":0.08092907071113586},"j1":{"w":0.0,"x":-6.167340416141087e-07,"y":0.17914418876171112,"z":2.688605945877498e-06},"j2":{"w":0.0,"x":-1.5706194639205933,"y":-4.1537619836162776e-05,"z":2.407406806945801},"j3":{"w":1.0,"x":7.4162163734436035,"y":-0.04500603675842285,"z":-0.9572893381118774}}}},{"id":5,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":2,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":0.9999986290931702,"y":1.0,"z":0.9999988079071045}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.30071619153022766,"y":0.9535101652145386,"z":0.01963132992386818},"j1":{"w":0.0,"x":-0.02151578664779663,"y":-0.013796210289001465,"z":0.9996733665466309},"j2":{"w":0.0,"x":0.9534696936607361,"y":-0.3010404407978058,"z":0.016366761177778244},"j3":{"w":1.0,"x":4.233027935028076,"y":0.966492235660553,"z":1.2846850156784058}}}},{"id":6,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":3,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0475580133497715,"y":-8.188627589333919e-07,"z":0.06712339073419571},"j1":{"w":0.0,"x":-3.60343005922914e-06,"y":-0.1039920523762703,"z":1.2844517414123402e-06},"j2":{"w":0.0,"x":0.8159534335136414,"y":-3.541418118402362e-05,"z":-0.5781162977218628},"j3":{"w":1.0,"x":-9.601022720336914,"y":1.530970811843872,"z":-0.44825008511543274}}}},{"camera":{"aspectRatio":2.0,"exposure":1.0,"farPlane":400.0,"fieldOfView":55.20000076293945,"isMain":true,"location":{"x":0.0,"y":1.2000000476837158,"z":0.0},"nearPlane":1.0,"rotation":{"x":51.511505126953125,"y":0.15597067773342133},"thirdPerson":true,"thirdPersonDistance":3.0,"useEntityRotation":true,"useEntityTranslation":true},"id":7,"mesh":{"dontCull":false,"resourcePath":"capsule.gltf","visible":true},"name":{"name":"Player"},"player":{"allowInput":true,"creationSettings":{"shape":{"capsuleShapeSettings":{"density":1.0,"height":1.2000000476837158,"radius":0.30000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"fastVelocity":4.0,"jumpVelocity":4.0,"slowVelocity":1.600000023841858},"text":{"halfSize":{"x":0.5,"y":1.0},"outlineColor":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"outlineFactor":0.0,"position":{"x":0.0,"y":1.600000023841858,"z":0.0},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"This is the player","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.07999999821186066},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-10.923478126525879,"y":-0.030071211978793144,"z":-1.5454801321029663}}}},{"audio":{"cutoff":0.0010000000474974513,"falloffFactor":0.10000000149011612,"falloffPower":2.0,"stream":{"loop":false,"pitch":1.0,"resourcePath":"/music.wav","time":0.0,"volume":0.006747064646333456},"volume":1.0},"id":8,"name":{"name":"WelcomeText"},"text":{"halfSize":{"x":1.899999976158142,"y":1.0},"outlineColor":{"w":1.0,"x":1.0,"y":0.0,"z":0.0},"outlineFactor":0.15000000596046448,"position":{"x":0.0,"y":0.0,"z":1.2999999523162842},"resourcePath":"font/roboto.ttf","rotation":{"w":1.0,"x":0.0,"y":0.0,"z":0.0},"text":"Welcome to this demo scene!","textColor":{"w":1.0,"x":1.0,"y":1.0,"z":1.0},"textScale":0.1899999976158142},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.01578390598297119,"y":0.00355260306969285,"z":0.9998670816421509},"j1":{"w":0.0,"x":0.40691956877708435,"y":0.9134560227394104,"z":0.003178075887262821},"j2":{"w":0.0,"x":-0.913324773311615,"y":0.4069172441959381,"z":-0.015863558277487755},"j3":{"w":1.0,"x":2.9802322387695313e-08,"y":4.168000221252441,"z":-0.02871951460838318}}}},{"entities":[{"id":10,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":4,"creationSettings":{"angularVelocity":{"x":0.3400594890117645,"y":0.002075438853353262,"z":-0.2711464762687683},"linearVelocity":{"x":0.027797559276223183,"y":-0.06926704198122025,"z":0.03678030148148537},"motionQuality":1,"objectLayer":1,"restitution":-0.0,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226305991411209,"y":0.10399112105369568,"z":0.24259740114212036}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.06749320030212402,"y":-0.0013515298487618566,"z":0.04701119661331177},"j1":{"w":0.0,"x":-0.05943548306822777,"y":-5.547449109144509e-05,"z":-0.08533213287591934},"j2":{"w":0.0,"x":0.003344531636685133,"y":-0.2425646185874939,"z":-0.0021718384232372046},"j3":{"w":1.0,"x":-6.993166923522949,"y":0.07752954214811325,"z":-0.49586528539657593}}}},{"id":11,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":5,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226487040519714,"y":0.10399449616670609,"z":1.000009298324585}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.001214503077790141,"y":4.0089940739562735e-05,"z":0.08225589245557785},"j1":{"w":0.0,"x":-0.10398011654615402,"y":-0.000795417174231261,"z":0.0015356455696746707},"j2":{"w":0.0,"x":0.0076551553793251514,"y":-0.9999799728393555,"z":0.00037435046397149563},"j3":{"w":1.0,"x":-0.18109244108200073,"y":1.1424553394317627,"z":-2.4032680988311768}}}},{"id":12,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":6,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399212688207626,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004975396674126387,"y":-3.6774740692635532e-06,"z":0.0821131020784378},"j1":{"w":0.0,"x":-0.10380175709724426,"y":-6.8306521825434174e-06,"z":-0.006289551965892315},"j2":{"w":0.0,"x":6.824726733611897e-05,"y":-0.9999992847442627,"z":-4.065033863298595e-05},"j3":{"w":1.0,"x":0.49817052483558655,"y":0.3519432246685028,"z":-2.3503992557525635}}}},{"id":13,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":7,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.10399219393730164,"z":0.9999990463256836}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006919844541698694,"y":0.0009341590339317918,"z":0.08196679502725601},"j1":{"w":0.0,"x":-0.10362283140420914,"y":-0.00030928864725865424,"z":0.008751623332500458},"j2":{"w":0.0,"x":0.003919091075658798,"y":-0.9999301433563232,"z":0.011065145023167133},"j3":{"w":1.0,"x":2.0737833976745605,"y":0.3635621964931488,"z":-1.7112125158309937}}}},{"id":14,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":8,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226367831230164,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.00037123600486665964,"y":-0.00020935118664056063,"z":0.08226258307695389},"j1":{"w":0.0,"x":-0.10399100184440613,"y":-7.686027743147861e-07,"z":0.000469290855107829},"j2":{"w":0.0,"x":-4.082914983882802e-06,"y":-0.9999959468841553,"z":-0.0025448778178542852},"j3":{"w":1.0,"x":3.7019379138946533,"y":0.35346531867980957,"z":-2.4043333530426025}}}},{"id":15,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":9,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.0822637528181076,"y":0.10399219393730164,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0014320656191557646,"y":-0.005514409858733416,"z":0.08206624537706375},"j1":{"w":0.0,"x":-0.1039608046412468,"y":-0.0019218007801100612,"z":0.0016850243555381894},"j2":{"w":0.0,"x":0.01734951324760914,"y":-0.9975799322128296,"z":-0.06733495742082596},"j3":{"w":1.0,"x":1.3664464950561523,"y":1.2094060182571411,"z":-2.3293323516845703}}}},{"id":16,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":10,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007250844966620207,"y":-0.00029188839835114777,"z":0.08194299042224884},"j1":{"w":0.0,"x":-0.10357026010751724,"y":0.0019194179913029075,"z":-0.009157725609838963},"j2":{"w":0.0,"x":-0.01807291805744171,"y":-0.9998225569725037,"z":-0.005160685162991285},"j3":{"w":1.0,"x":3.177853584289551,"y":1.137428641319275,"z":-2.286043643951416}}}},{"id":17,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":11,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999994039535522}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007074753753840923,"y":-0.0009124425705522299,"z":0.08195383846759796},"j1":{"w":0.0,"x":-0.10360674560070038,"y":2.178741397074191e-06,"z":-0.008943937718868256},"j2":{"w":0.0,"x":0.0009330803295597434,"y":-0.999937891960144,"z":-0.01105236355215311},"j3":{"w":1.0,"x":4.739034652709961,"y":1.1431937217712402,"z":-2.344177484512329}}}},{"id":18,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":12,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-2.9814507797709666e-05,"y":-0.00011468570301076397,"z":0.08226361125707626},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-5.103151488583535e-05,"z":-3.7763817090308294e-05},"j2":{"w":0.0,"x":0.0004912313306704164,"y":-0.9999982118606567,"z":-0.0013939131749793887},"j3":{"w":1.0,"x":5.269709587097168,"y":0.3537576496601105,"z":-2.396353006362915}}}},{"id":19,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":13,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226397633552551,"y":0.10399534553289413,"z":1.0000017881393433}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0029943662229925394,"y":-0.004902660381048918,"z":0.08206314593553543},"j1":{"w":0.0,"x":-0.1038932278752327,"y":-0.00239846995100379,"z":-0.0039341989904642105},"j2":{"w":0.0,"x":0.025261566042900085,"y":-0.9979578852653503,"z":-0.05869881808757782},"j3":{"w":1.0,"x":0.4539576470851898,"y":1.9912066459655762,"z":-2.3605332374572754}}}},{"id":20,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":14,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0047220797277987,"y":-0.006254853215068579,"z":0.08188952505588531},"j1":{"w":0.0,"x":-0.10381996631622314,"y":0.000815314007923007,"z":-0.005924399942159653},"j2":{"w":0.0,"x":-0.0034728916361927986,"y":-0.9970735311508179,"z":-0.0763583704829216},"j3":{"w":1.0,"x":2.0099921226501465,"y":1.9823397397994995,"z":-2.1112253665924072}}}},{"id":21,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":15,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0015184117946773767,"y":-0.001873633824288845,"z":0.08222834020853043},"j1":{"w":0.0,"x":-0.10390593856573105,"y":0.0038146909791976213,"z":-0.0018317853100597858},"j2":{"w":0.0,"x":-0.036265525966882706,"y":-0.9990666508674622,"z":-0.02343420498073101},"j3":{"w":1.0,"x":3.611302614212036,"y":1.9326788187026978,"z":-2.369572162628174}}}},{"id":22,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":16,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370811462402,"y":0.10399207472801208,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.0011607652995735407,"y":-0.005252636969089508,"z":0.08208763599395752},"j1":{"w":0.0,"x":-0.1039327085018158,"y":-0.003092399565503001,"z":-0.0016675429651513696},"j2":{"w":0.0,"x":0.03069702349603176,"y":-0.9975154995918274,"z":-0.06339509040117264},"j3":{"w":1.0,"x":0.911769449710846,"y":2.8139381408691406,"z":-2.3714351654052734}}}},{"id":23,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":17,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399208217859268,"z":0.9999988079071045}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.002328230533748865,"y":-0.01567736454308033,"z":0.08072245121002197},"j1":{"w":0.0,"x":-0.10387608408927917,"y":0.0032992407213896513,"z":0.0036367876455187798},"j2":{"w":0.0,"x":-0.03779618442058563,"y":-0.9811586737632751,"z":-0.189463809132576},"j3":{"w":1.0,"x":2.5983128547668457,"y":2.8227591514587402,"z":-2.0519001483917236}}}},{"id":24,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":18,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.006420230958610773,"y":-0.0025190962478518486,"z":0.0819740742444992},"j1":{"w":0.0,"x":-0.10356941819190979,"y":0.004437707830220461,"z":0.008247951045632362},"j2":{"w":0.0,"x":-0.04495199769735336,"y":-0.9986188411712646,"z":-0.027167268097400665},"j3":{"w":1.0,"x":4.155186176300049,"y":2.7027957439422607,"z":-2.4178249835968018}}}},{"id":25,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":19,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399205982685089,"z":0.9999993443489075}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.007614439819008112,"y":-0.014711390249431133,"z":0.08057859539985657},"j1":{"w":0.0,"x":-0.1032203733921051,"y":-0.006378653459250927,"z":-0.010918588377535343},"j2":{"w":0.0,"x":0.07885781675577164,"y":-0.9819651246070862,"z":-0.17182737588882446},"j3":{"w":1.0,"x":1.3723328113555908,"y":3.7512500286102295,"z":-2.243227481842041}}}},{"id":26,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":20,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226370066404343,"y":0.10399207472801208,"z":0.9999992847442627}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.005531982518732548,"y":-0.015606719069182873,"z":0.08058004826307297},"j1":{"w":0.0,"x":-0.10365156084299088,"y":0.005922866519540548,"z":-0.005968747194856405},"j2":{"w":0.0,"x":-0.0449003241956234,"y":-0.9801850318908691,"z":-0.19292448461055756},"j3":{"w":1.0,"x":3.1063742637634277,"y":3.642221689224243,"z":-2.205120325088501}}}},{"id":27,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":21,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.10399165004491806,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.009233793243765831,"y":-2.8461645484867404e-08,"z":-0.08174382150173187},"j1":{"w":0.0,"x":5.111483005748596e-07,"y":-0.10399164259433746,"z":-2.153150546746474e-08},"j2":{"w":0.0,"x":-0.9936796426773071,"y":-4.907456968794577e-06,"z":0.11224624514579773},"j3":{"w":1.0,"x":5.397507667541504,"y":1.5309886932373047,"z":-0.8703097105026245}}}},{"id":28,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":22,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226369321346283,"y":0.1039920523762703,"z":0.9999992251396179}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.004304870497435331,"y":-0.016259904950857162,"z":0.08052577078342438},"j1":{"w":0.0,"x":-0.10374186187982559,"y":0.0035653808154165745,"z":0.006265922449529171},"j2":{"w":0.0,"x":-0.04547032341361046,"y":-0.9796709418296814,"z":-0.19538608193397522},"j3":{"w":1.0,"x":3.7071003913879395,"y":4.404808521270752,"z":-2.0641326904296875}}}},{"id":29,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":23,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226374536752701,"y":0.1039920300245285,"z":1.0000001192092896}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.004521988797932863,"y":-0.014796562492847443,"z":0.08079565316438675},"j1":{"w":0.0,"x":-0.10348106175661087,"y":-0.007410035468637943,"z":-0.0071486919187009335},"j2":{"w":0.0,"x":0.0823487713932991,"y":-0.9811068177223206,"z":-0.17506666481494904},"j3":{"w":1.0,"x":1.740257740020752,"y":4.569649696350098,"z":-2.0765440464019775}}}},{"id":30,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":24,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"script":{"resourcePath":"scripts/example.lua","scriptProperties":{"duplicateEntityName":{"type":"string","value":""}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0822434350848198,"y":-3.559059393865027e-07,"z":-0.0018298403592780232},"j1":{"w":0.0,"x":6.938781211829337e-07,"y":0.1486254185438156,"z":2.2790266029915074e-06},"j2":{"w":0.0,"x":0.021798700094223022,"y":-1.5125399841053877e-05,"z":0.97975754737854},"j3":{"w":1.0,"x":-0.42584455013275146,"y":-0.042439818382263184,"z":0.7894344925880432}}}},{"id":31,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":25,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.01507602445781231,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.07320480048656464,"y":4.977956632501446e-05,"z":-0.03752845898270607},"j1":{"w":0.0,"x":0.006859811022877693,"y":-0.0011024783598259091,"z":0.013379612006247044},"j2":{"w":0.0,"x":-0.032167207449674606,"y":-0.9773759245872498,"z":-0.0640433058142662},"j3":{"w":1.0,"x":2.4300098419189453,"y":0.3631786108016968,"z":1.207587718963623}}}},{"id":32,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":26,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.06837532669305801,"y":-0.0017373006558045745,"z":-0.04570697247982025},"j1":{"w":0.0,"x":0.05685741454362869,"y":0.11100539565086365,"z":0.08083657920360565},"j2":{"w":0.0,"x":0.39542150497436523,"y":-0.6513306498527527,"z":0.6162874698638916},"j3":{"w":1.0,"x":3.135746955871582,"y":0.2095150351524353,"z":-1.027677297592163}}}},{"id":33,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":27,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226379007101059,"y":0.1486254185438156,"z":0.9800000190734863}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.0716107115149498,"y":-4.5638077494913887e-07,"z":-0.040487490594387054},"j1":{"w":0.0,"x":0.0005247447988949716,"y":0.14862160384655,"z":0.0009264472755603492},"j2":{"w":0.0,"x":0.4823108911514282,"y":-0.007020606193691492,"z":0.8530691862106323},"j3":{"w":1.0,"x":2.5021331310272217,"y":-0.04527640342712402,"z":0.6787291169166565}}}}],"id":9,"name":{"name":"Staircase"},"root":false},{"id":34,"mesh":{"dontCull":false,"resourcePath":"metallicwall.gltf","visible":true},"name":{"name":"Entity 7"},"rigidBody":{"bodyIndex":28,"creationSettings":{"motionQuality":1,"objectLayer":1,"shape":{"boundingBoxSettings":{"aabb":{"max":{"x":7.46401834487915,"y":15.011363983154297,"z":0.4019695222377777},"min":{"x":-7.46401834487915,"y":0.0833272933959961,"z":-0.4019695222377777}},"density":20.139999389648438,"scale":{"x":0.08226368576288223,"y":0.1039920523762703,"z":0.9999991655349731}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-3.9226383705681656e-06,"y":0.0,"z":0.08226368576288223},"j1":{"w":0.0,"x":-0.1039920523762703,"y":-2.479363736540563e-08,"z":-4.958727458870271e-06},"j2":{"w":0.0,"x":2.384183801495965e-07,"y":-0.9999991655349731,"z":0.0},"j3":{"w":1.0,"x":3.1176745891571045,"y":5.388330459594727,"z":-4.729436874389648}}}},{"entities":[{"entities":[{"id":37,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":31,"creationSettings":{"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":0.9999997615814209,"z":1.0}}}},"layer":1},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.9554481506347656,"y":0.03446343168616295,"z":0.2931368052959442},"j1":{"w":0.0,"x":-0.090654656291008,"y":0.9794187545776367,"z":0.18033011257648468},"j2":{"w":0.0,"x":-0.28088951110839844,"y":-0.1988704651594162,"z":0.9389098882675171},"j3":{"w":0.9999997019767761,"x":-1.679507851600647,"y":-0.44968080520629883,"z":6.649218559265137}}}}],"id":36,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":30,"creationSettings":{"angularVelocity":{"x":-0.003580757649615407,"y":-0.0010163785191252828,"z":-0.001152479788288474},"linearVelocity":{"x":0.0011589848436415195,"y":-0.276141881942749,"z":-0.003600968746468425},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.751174807548523,"y":0.22571837902069092,"z":-0.6203150153160095},"j1":{"w":0.0,"x":-0.39222919940948486,"y":0.6032152771949768,"z":0.6944692730903625},"j2":{"w":0.0,"x":0.5309374332427979,"y":0.7649720907211304,"z":-0.3645859360694885},"j3":{"w":1.0,"x":-11.712514877319336,"y":4.754337310791016,"z":-4.003152370452881}}}}],"id":35,"mesh":{"dontCull":false,"resourcePath":"chromesphere.gltf","visible":true},"name":{"name":"Sphere"},"rigidBody":{"bodyIndex":29,"creationSettings":{"angularVelocity":{"x":0.16539807617664337,"y":0.1814352571964264,"z":-0.11671467125415802},"linearVelocity":{"x":0.11671468615531921,"y":2.4347741600649897e-09,"z":0.16539809107780457},"objectLayer":1,"restitution":0.8999999761581421,"shape":{"sphereSettings":{"density":1.0,"radius":1.0000001192092896,"scale":{"x":1.0,"y":1.0,"z":1.0}}}},"layer":1},"root":false,"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":-0.6672989130020142,"y":0.0363946259021759,"z":0.7439002990722656},"j1":{"w":0.0,"x":0.5453938245773315,"y":0.7040697336196899,"z":0.45478731393814087},"j2":{"w":0.0,"x":-0.5072058439254761,"y":0.7091977000236511,"z":-0.48967432975769043},"j3":{"w":1.0,"x":-12.277113914489746,"y":0.9699291586875916,"z":-0.5359781384468079}}}},{"id":38,"name":{"name":"Entity 39"},"script":{"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":0.0,"y":9.527641296386719,"z":0.0}}}},{"id":39,"name":{"name":"Entity 39"},"script":{"resourcePath":"scripts/entitySpawner.lua","scriptProperties":{"spawnEntityName":{"type":"string","value":"Sphere"},"spawnRate":{"type":"double","value":1.0}}},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":1.0,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":1.0,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":1.0},"j3":{"w":1.0,"x":-5.397964000701904,"y":12.993012428283691,"z":0.0}}}},{"entities":[{"id":41,"mesh":{"dontCull":false,"resourcePath":"tree.obj","visible":true},"name":{"name":"Tree base"},"rigidBody":{"bodyIndex":32,"creationSettings":{"angularDampening":0.0,"linearDampening":0.0,"shape":{"meshSettings":{"resourcePath":"tree.obj","scale":{"x":0.15000003576278687,"y":0.15000003576278687,"z":0.15000003576278687}}}},"layer":0},"transform":{"isStatic":false,"matrix":{"j0":{"w":0.0,"x":0.15000003576278687,"y":0.0,"z":0.0},"j1":{"w":0.0,"x":0.0,"y":0.15000003576278687,"z":0.0},"j2":{"w":0.0,"x":0.0,"y":0.0,"z":0.15000003576278687},"j3":{"w":1.0,"x":0.0,"y":0.0,"z":0.0}}}}],"id":40,"name":{"name":"Trees"},"root":false}],"id":0,"name":{"name":"Root"},"root":false}],"fog":{"ambientFactor":0.009999999776482582,"density":0.0005000000237487257,"enable":true,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"height":0.0,"heightFalloff":0.0284000001847744,"rayMarchStepCount":10,"rayMarching":true,"scatteringAnisotropy":-0.6000000238418579,"scatteringFactor":2.0,"volumetricIntensity":1.0},"irradianceVolume":{"aabb":{"max":{"x":23.738000869750977,"y":18.340999603271484,"z":17.85099983215332},"min":{"x":-38.63600158691406,"y":-9.817999839782715,"z":-21.163000106811523}},"bias":0.30000001192092896,"enable":true,"gamma":5.0,"hysteresis":0.9800000190734863,"lowerResMoments":true,"opacityCheck":false,"optimizeProbes":true,"probeCount":{"x":20,"y":20,"z":20},"rayCount":100,"rayCountInactive":32,"sampleEmissives":false,"sharpness":50.0,"strength":1.0,"useShadowMap":false},"name":"sponza","physicsWorld":null,"postProcessing":{"chromaticAberration":{"colorsReversed":false,"enable":false,"strength":1.0},"contrast":1.0,"filmGrain":{"enable":false,"strength":0.10000000149011612},"filmicTonemapping":false,"fsr2":true,"paperWhiteLuminance":150.0,"saturation":1.0,"screenMaxLuminance":1600.0,"sharpen":{"enable":true,"factor":0.15000000596046448},"taa":{"enable":true,"jitterRange":0.9900000095367432},"tint":{"x":1.0,"y":1.0,"z":1.0},"vignette":{"color":{"x":0.0,"y":0.0,"z":0.0},"enable":false,"offset":0.0,"power":0.0,"strength":0.0}},"reflection":{"bias":0.0,"currentClipFactor":2.0,"enable":true,"gi":true,"historyClipMax":1.0,"opacityCheck":false,"radianceLimit":10.0,"rt":true,"spatialFilterStrength":10.0,"temporalWeight":0.9520000219345093,"textureLevel":4,"useShadowMap":false},"sky":{"atmosphere":{"height":100000.0,"probeResolution":128},"clouds":{"castShadow":false,"coverageResolution":512,"coverageScale":0.25,"coverageSpeed":5.0,"darkEdgeAmbient":0.10000000149011612,"darkEdgeFocus":2.0,"densityMultiplier":0.800000011920929,"detailResolution":32,"detailScale":16.0,"detailSpeed":10.0,"detailStrength":0.15000000596046448,"distanceLimit":8000.0,"enable":true,"heightStretch":0.5,"maxHeight":1700.0,"minHeight":1400.0,"occlusionSampleCount":5,"sampleCount":64,"scattering":{"eccentricityFirstPhase":0.0,"eccentricitySecondPhase":-0.5,"extinctionCoefficients":{"w":1.0,"x":0.9300000071525574,"y":0.9649999737739563,"z":1.0},"extinctionFactor":0.1599999964237213,"phaseAlpha":0.5,"scatteringFactor":2.0},"shadowResolution":512,"shadowSampleFraction":4,"shapeResolution":128,"shapeScale":2.0,"shapeSpeed":5.0,"stochasticOcclusionSampling":true},"planetCenter":{"x":0.0,"y":-650000.0,"z":0.0},"planetRadius":649000.0},"ssgi":{"aoStrength":1.0,"enable":true,"enableAo":true,"irradianceLimit":10.0,"opacityCheck":false,"radius":1.0,"rayCount":2,"rt":false,"sampleCount":8},"sss":{"enable":true,"maxLength":0.4970000088214874,"sampleCount":8,"thickness":0.30000001192092896}}
\ No newline at end of file
diff --git a/data/scripts/cameraAnimation.lua b/data/scripts/cameraAnimation.lua
new file mode 100644
index 000000000..438c4cd68
--- /dev/null
+++ b/data/scripts/cameraAnimation.lua
@@ -0,0 +1,54 @@
+-- This is a comment
+
+ScriptProperties = {
+ animationLength = { type = "double", value = 30.0 },
+ animationActive = { type = "boolean", value = false }
+}
+
+animationTime = 0.0
+
+function Update(delta)
+
+ local entity = GetThisEntity()
+ local scene = GetThisScene()
+
+ if scene:HasMainCamera() ~= true or ScriptProperties.animationActive.value ~= true then
+ return
+ end
+
+ local camera = scene:GetMainCamera()
+ local hierarchy = entity:GetHierarchyComponent()
+
+ local children = hierarchy:GetChildren()
+
+ if children == nil then
+ return
+ end
+
+ if #children <= 1 then
+ return
+ end
+
+ animationTime = animationTime + Atlas.Clock.GetDelta()
+
+ local animationProgress = animationTime / ScriptProperties.animationLength.value
+ if animationProgress >= 1.0 then
+ return
+ end
+
+ local childProgress = animationProgress * (#children - 1.0)
+
+ local lowerChildIndex = math.floor(childProgress)
+ local upperChildIndex = math.ceil(childProgress)
+ local childFraction = childProgress - lowerChildIndex
+
+ local lowerChildEntity = children[lowerChildIndex + 1]
+ local upperChildEntity = children[upperChildIndex + 1]
+
+ local lowerChildCamera = lowerChildEntity:GetCameraComponent()
+ local upperChildCamera = upperChildEntity:GetCameraComponent()
+
+ camera.location = Glm.Mix(lowerChildCamera:GetLocation(), upperChildCamera:GetLocation(), childFraction)
+ camera.rotation = Glm.Mix(lowerChildCamera.rotation, upperChildCamera.rotation, childFraction)
+
+end
\ No newline at end of file
diff --git a/data/scripts/entitySpawner.lua b/data/scripts/entitySpawner.lua
new file mode 100644
index 000000000..8c588a022
--- /dev/null
+++ b/data/scripts/entitySpawner.lua
@@ -0,0 +1,61 @@
+-- This is a comment
+
+ScriptProperties = {
+ spawnEntityName = { type = "string", value = "" },
+ spawnRate = { type = "double", value = 1.0 }
+}
+
+lastSpawn = 0.0
+
+function Update(delta)
+
+ local entity = GetThisEntity()
+ local scene = GetThisScene()
+ local spawnEntity = scene:GetEntityByName(ScriptProperties.spawnEntityName.value)
+
+ if not spawnEntity:IsValid() then
+ return
+ end
+
+ transform = entity:GetTransformComponent()
+
+ spawnTransform = spawnEntity:GetTransformComponent()
+ spawnRigidBody = spawnEntity:GetRigidBodyComponent()
+
+ if spawnTransform == nil or spawnRigidBody == nil or transform == nil then
+ return
+ end
+
+ local time = Atlas.Clock.Get()
+ local spawnFraction = 1.0 / ScriptProperties.spawnRate.value
+
+ if time - lastSpawn > spawnFraction then
+ local decomp = Atlas.MatrixDecomposition(transform.globalMatrix)
+
+ local spawnCenter = decomp.translation
+
+ local deg = math.random(0.0, 1.0) * 2.0 * 3.14159
+ local dist = math.random(0.0, 1.0) + math.random(0.0, 1.0)
+
+ if dist > 1.0 then
+ dist = 2.0 - dist
+ end
+
+ local dir = Glm.Vec3(math.cos(deg), 0.0, math.sin(deg)) * dist * 5.0
+
+ local spawnPoint = dir + spawnCenter
+ local matrix = Glm.Translate(spawnPoint)
+
+ local newEntity = scene:DuplicateEntity(spawnEntity)
+
+ local newTransform = newEntity:GetTransformComponent()
+ local newRigidBody = newEntity:GetRigidBodyComponent()
+
+ newRigidBody:SetLinearVelocity(dir)
+ newTransform:Set(matrix)
+
+ lastSpawn = time
+
+ Atlas.Log.Warning("New spawn")
+ end
+end
\ No newline at end of file
diff --git a/data/scripts/example.lua b/data/scripts/example.lua
new file mode 100644
index 000000000..c0d1af858
--- /dev/null
+++ b/data/scripts/example.lua
@@ -0,0 +1,27 @@
+-- This is a comment
+
+ScriptProperties = {
+ duplicateEntityName = { type = "string", value = "" }
+}
+
+function Update(delta)
+ entity = GetThisEntity()
+
+ transform = entity:GetTransformComponent()
+ rigidBody = entity:GetRigidBodyComponent()
+
+ local time = Atlas.Clock.Get()
+
+ local offset = Glm.Vec3(0.0, math.sin(time), 0.0) + Glm.Vec3(0.0, 5.0, 0.0)
+ local matrix = Glm.Translate(offset)
+
+ Atlas.Log.Warning(tostring(offset.y))
+
+ transform:Set(matrix)
+
+ -- ~= is equal to != in most other languages
+ if rigidBody ~= nil then
+ rigidBody:SetLinearVelocity(Glm.Vec3(0.0))
+ rigidBody:SetAngularVelocity(Glm.Vec3(0.0))
+ end
+end
\ No newline at end of file
diff --git a/data/scripts/thirdPersonPlayer.lua b/data/scripts/thirdPersonPlayer.lua
new file mode 100644
index 000000000..3cb2065d0
--- /dev/null
+++ b/data/scripts/thirdPersonPlayer.lua
@@ -0,0 +1,34 @@
+-- This is a comment
+
+ScriptProperties = {
+ spawnEntityName = { type = "string", value = "" },
+ spawnRate = { type = "double", value = 1.0 }
+}
+
+lastSpawn = 0.0
+
+function Update(delta)
+
+ -- Only update the player rotation if there is input
+ local playerInput = (Atlas.KeyboardMap.IsKeyPressed(Atlas.Keycode.KeyW, true) or
+ Atlas.KeyboardMap.IsKeyPressed(Atlas.Keycode.KeyA, true) or
+ Atlas.KeyboardMap.IsKeyPressed(Atlas.Keycode.KeyS, true) or
+ Atlas.KeyboardMap.IsKeyPressed(Atlas.Keycode.KeyD, true))
+
+ if playerInput ~= true then
+ return
+ end
+
+ local entity = GetThisEntity()
+ local scene = GetThisScene()
+
+ local camera = entity:GetCameraComponent()
+ local transform = entity:GetTransformComponent()
+ local player = entity:GetPlayerComponent()
+
+ local rotationMatrix = Glm.Rotate(Glm.Mat4(1.0), camera.rotation.x, Glm.Vec3(0.0, 1.0, 0.0))
+ local recomposed = Atlas.MatrixDecomposition(rotationMatrix)
+
+ player:SetRotation(Glm.Quat(recomposed.rotation))
+
+end
\ No newline at end of file
diff --git a/data/shader/deferred/direct.csh b/data/shader/deferred/direct.csh
index 8552c0ee2..2f71f6c2e 100644
--- a/data/shader/deferred/direct.csh
+++ b/data/shader/deferred/direct.csh
@@ -63,7 +63,7 @@ void main() {
// for transmissive materials
vec3 shadowNormal = surface.material.transmissive ? dot(-uniforms.light.direction.xyz, geometryNormal) < 0.0 ?
-geometryNormal : geometryNormal : geometryNormal;
- shadowFactor = CalculateCascadedShadow(uniforms.light.shadow, cascadeMaps, surface.P,
+ shadowFactor = CalculateCascadedShadow(uniforms.light.shadow, cascadeMaps, surface.P, vec3(vec2(pixel) + 0.5, 0.0),
shadowNormal, saturate(dot(-uniforms.light.direction.xyz, shadowNormal)));
#endif
#ifdef SCREEN_SPACE_SHADOWS
diff --git a/data/shader/fsr2/ffx_fsr2_upsample.h b/data/shader/fsr2/ffx_fsr2_upsample.h
index 119ebbf67..58a19d23f 100644
--- a/data/shader/fsr2/ffx_fsr2_upsample.h
+++ b/data/shader/fsr2/ffx_fsr2_upsample.h
@@ -177,10 +177,6 @@ FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams p
Deringing(clippingBox, fColorAndWeight.xyz);
}
- #if FFX_FSR2_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF && FFX_HALF
- #include "ffx_fsr2_force16_end.h"
- #endif
-
return fColorAndWeight;
}
diff --git a/data/shader/pathtracer/temporal.csh b/data/shader/pathtracer/temporal.csh
index 4802f5083..e3de1f27e 100644
--- a/data/shader/pathtracer/temporal.csh
+++ b/data/shader/pathtracer/temporal.csh
@@ -399,7 +399,7 @@ void main() {
historyRadiance, currentRadiance);
float adjClipBlend = clamp(clipBlend, 0.0, pushConstants.historyClipMax);
currentRadiance = clamp(currentRadiance, currentNeighbourhoodMin, currentNeighbourhoodMax);
- //historyRadiance = mix(historyRadiance, currentRadiance, adjClipBlend);
+ // historyRadiance = mix(historyRadiance, currentRadiance, adjClipBlend);
historyRadiance = YCoCgToRGB(historyRadiance);
currentRadiance = YCoCgToRGB(currentRadiance);
diff --git a/data/shader/postprocessing.fsh b/data/shader/postprocessing.fsh
index 673e85a45..08cd7a055 100644
--- a/data/shader/postprocessing.fsh
+++ b/data/shader/postprocessing.fsh
@@ -25,7 +25,7 @@ layout(set = 3, binding = 4) uniform UniformBuffer {
float vignettePower;
float vignetteStrength;
vec4 vignetteColor;
-
+ vec4 tintColor;
} Uniforms;
const float gamma = 1.0 / 2.2;
@@ -65,7 +65,7 @@ float ToneMap(float luminance) {
vec3 saturate(vec3 color, float factor) {
const vec3 luma = vec3(0.299, 0.587, 0.114);
- vec3 pixelLuminance = vec3(dot(color, luma));
+ vec3 pixelLuminance = max(vec3(dot(color, luma)), vec3(0.0));
return mix(pixelLuminance, color, factor);
}
@@ -180,6 +180,8 @@ void main() {
#endif
#endif
+ color = color * Uniforms.tintColor.rgb;
+
color = clamp(saturate(color, Uniforms.saturation), vec3(0.0), vec3(1.0));
color = ((color - 0.5) * max(Uniforms.contrast, 0.0)) + 0.5;
diff --git a/data/shader/shadow.hsh b/data/shader/shadow.hsh
index f2e915708..1ebf61ae9 100644
--- a/data/shader/shadow.hsh
+++ b/data/shader/shadow.hsh
@@ -2,6 +2,10 @@
#extension GL_EXT_texture_shadow_lod : require
#endif
+#include
+#include
+#include
+
// Shadow cascades
struct Cascade {
@@ -21,11 +25,11 @@ struct Shadow {
float distance;
float bias;
+ float edgeSoftness;
float cascadeBlendDistance;
int cascadeCount;
- float aligment0;
float aligment1;
vec2 resolution;
@@ -34,6 +38,18 @@ struct Shadow {
};
+vec2 VogelDiskSample(int sampleIndex, int samplesCount, float phi) {
+ const float goldenAngle = 2.4;
+
+ float r = sqrt(float(sampleIndex) + 0.5) / sqrt(float(samplesCount));
+ float theta = float(sampleIndex) * goldenAngle + phi;
+
+ float sine = sin(theta);
+ float cosine = cos(theta);
+
+ return vec2(r * cosine, r * sine);
+}
+
// Filtering based on http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/
float offsetLookup(sampler2DArrayShadow cascadeMaps, vec2 flooredUV, float u, float v, float cascadeIndex,
@@ -52,13 +68,35 @@ float offsetLookup(sampler2DArrayShadow cascadeMaps, vec2 flooredUV, float u, fl
}
-float cascadeLookup(Shadow shadow, sampler2DArrayShadow cascadeMaps, float cascadeIndex, mat4 cascadeTransform, vec3 fragmentPosition, float bias, bool fade) {
+float offsetLookup(sampler2DArrayShadow cascadeMaps, vec2 uv, float cascadeIndex, float edgeSoftness,
+ vec2 texelSize, vec2 invResolution, vec3 fragmentPosition, int lookupIndex, float depth, float bias) {
+
+ uv = 0.5 * (uv * invResolution) + 0.5;
+ vec2 samplingSpread = edgeSoftness * invResolution / texelSize;
+
+ float phi = 2.0 * PI * GetInterleavedGradientNoise(fragmentPosition.xy);
+ vec2 offset = VogelDiskSample(lookupIndex, 16, phi) * samplingSpread;
+
+#ifdef AE_TEXTURE_SHADOW_LOD
+ // This fixes issues that can occur at cascade borders
+ return textureLod(cascadeMaps,
+ vec4(uv + offset, cascadeIndex, depth + bias), 0);
+#else
+ return texture(cascadeMaps,
+ vec4(uv + offset, cascadeIndex, depth + bias));
+#endif
+
+}
+
+
+float cascadeLookup(Shadow shadow, sampler2DArrayShadow cascadeMaps, float cascadeIndex, mat4 cascadeTransform,
+ vec3 fragmentPosition, vec3 position, float bias, bool fade) {
vec4 shadowCoords = cascadeTransform * vec4(fragmentPosition, 1.0);
shadowCoords.xyz /= shadowCoords.w;
- float fadeout = fade ? clamp((-fragmentPosition.z + 2.0 - shadow.distance) * 0.5, 0.0, 1.0) : 0.0;
-
+ float fadeout = fade ? clamp((-fragmentPosition.z + 2.0 - shadow.distance) * 0.5, 0.0, 1.0) : 0.0;
+
//shadowCoords.z = shadowCoords.z * 0.5 + 0.5;
if (abs(fadeout - 1.0) < 1e-6)
@@ -176,6 +214,19 @@ float cascadeLookup(Shadow shadow, sampler2DArrayShadow cascadeMaps, float casca
visibility /= 2704.0;
#endif
+#define SHADOW_FILTER_VOGEL
+
+#ifdef SHADOW_FILTER_VOGEL
+ visibility = 0.0;
+
+ vec2 texelSize = vec2(shadow.cascades[int(cascadeIndex)].texelSize);
+ for (int i = 0; i < 16; i++) {
+ visibility += offsetLookup(cascadeMaps, uv, float(cascadeIndex), shadow.edgeSoftness, texelSize, resInv, position, i, shadowCoords.z, bias);
+ }
+
+ visibility /= 16.0;
+#endif
+
// Fade out shadow in the distance
return clamp(visibility + fadeout, 0.0, 1.0);
@@ -217,7 +268,89 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v
fragmentPosition += bias;
float visibility = cascadeLookup(shadow, cascadeMaps, float(cascadeIndex),
- cascadeMatrix, fragmentPosition, 0.0, true);
+ cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true);
+
+#ifdef SHADOW_CASCADE_BLENDING
+ if (cascadeIndex < shadow.cascadeCount - 1) {
+
+ float cascadeDistance = shadow.cascades[0].distance;
+ cascadeDistance = cascadeIndex > 0 ? shadow.cascades[1].distance : cascadeDistance;
+ cascadeDistance = cascadeIndex > 1 ? shadow.cascades[2].distance : cascadeDistance;
+ cascadeDistance = cascadeIndex > 2 ? shadow.cascades[3].distance : cascadeDistance;
+ cascadeDistance = cascadeIndex > 3 ? shadow.cascades[4].distance : cascadeDistance;
+
+ float blend = (cascadeDistance - distance)
+ / shadow.cascadeBlendDistance;
+ blend = clamp(blend, 0.0, 1.0);
+
+ if (blend <= 1.0) {
+
+ cascadeIndex += 1;
+ fragmentPosition -= bias;
+
+ mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace;
+ cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix;
+
+ float texelSize = shadow.cascades[0].texelSize;
+ texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize;
+ texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize;
+ texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize;
+ texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize;
+ texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize;
+
+ bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5);
+ fragmentPosition += bias;
+
+ visibility = mix(cascadeLookup(shadow, cascadeMaps, float(cascadeIndex),
+ cascadeMatrix, fragmentPosition, fragmentPosition, 0.0, true), visibility, blend);
+ }
+ }
+#endif
+
+ return visibility;
+}
+
+float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, vec3 fragmentPosition, vec3 position, vec3 normal, float cosTheta) {
+
+ // Note: The code below is actually the fastest code on every platform tested
+ // Some platforms have problems directly indexing the cascade array.
+ // We allow 6 cascades
+#ifdef SHADOW_CASCADE_BLENDING
+ float distance = -fragmentPosition.z - shadow.cascadeBlendDistance;
+#else
+ float distance = -fragmentPosition.z;
+#endif
+ int cascadeIndex = 0;
+ cascadeIndex = distance >= shadow.cascades[0].distance ? 1 : cascadeIndex;
+ cascadeIndex = distance >= shadow.cascades[1].distance ? 2 : cascadeIndex;
+ cascadeIndex = distance >= shadow.cascades[2].distance ? 3 : cascadeIndex;
+ cascadeIndex = distance >= shadow.cascades[3].distance ? 4 : cascadeIndex;
+ cascadeIndex = distance >= shadow.cascades[4].distance ? 5 : cascadeIndex;
+ cascadeIndex = min(shadow.cascadeCount - 1, cascadeIndex);
+
+ mat4 cascadeMatrix = shadow.cascades[0].cascadeSpace;
+ cascadeMatrix = cascadeIndex > 0 ? shadow.cascades[1].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 1 ? shadow.cascades[2].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 2 ? shadow.cascades[3].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 3 ? shadow.cascades[4].cascadeSpace : cascadeMatrix;
+ cascadeMatrix = cascadeIndex > 4 ? shadow.cascades[5].cascadeSpace : cascadeMatrix;
+
+ float texelSize = shadow.cascades[0].texelSize;
+ texelSize = cascadeIndex > 0 ? shadow.cascades[1].texelSize : texelSize;
+ texelSize = cascadeIndex > 1 ? shadow.cascades[2].texelSize : texelSize;
+ texelSize = cascadeIndex > 2 ? shadow.cascades[3].texelSize : texelSize;
+ texelSize = cascadeIndex > 3 ? shadow.cascades[4].texelSize : texelSize;
+ texelSize = cascadeIndex > 4 ? shadow.cascades[5].texelSize : texelSize;
+
+ vec3 bias = shadow.bias * texelSize * normal / max(cosTheta, 0.5);
+ fragmentPosition += bias;
+
+ float visibility = cascadeLookup(shadow, cascadeMaps, float(cascadeIndex),
+ cascadeMatrix, fragmentPosition, position, 0.0, true);
#ifdef SHADOW_CASCADE_BLENDING
if (cascadeIndex < shadow.cascadeCount - 1) {
@@ -255,7 +388,7 @@ float CalculateCascadedShadow(Shadow shadow, sampler2DArrayShadow cascadeMaps, v
fragmentPosition += bias;
visibility = mix(cascadeLookup(shadow, cascadeMaps, float(cascadeIndex),
- cascadeMatrix, fragmentPosition, 0.0, true), visibility, blend);
+ cascadeMatrix, fragmentPosition, position, 0.0, true), visibility, blend);
}
}
#endif
@@ -271,5 +404,5 @@ float CalculateShadowWorldSpace(Shadow shadow, sampler2DArrayShadow cascadeMaps,
position += bias;
return cascadeLookup(shadow, cascadeMaps, 0.0,
- cascadeMatrix, position, 0.0, false);
+ cascadeMatrix, position, position, 0.0, false);
}
\ No newline at end of file
diff --git a/data/shader/ssgi/ssgi.csh b/data/shader/ssgi/ssgi.csh
index 6c07fd14b..4c5a2df7b 100644
--- a/data/shader/ssgi/ssgi.csh
+++ b/data/shader/ssgi/ssgi.csh
@@ -134,17 +134,20 @@ void main() {
ivec2 stepPixel = ivec2(uvPos * vec2(resolution));
float stepDepth = texelFetch(depthTexture, stepPixel, 0).r;
- float stepLinearDepth = -ConvertDepthToViewSpaceDepth(stepDepth);
+ vec3 stepPos = ConvertDepthToViewSpace(stepDepth, uvPos);
+ float stepLinearDepth = -stepPos.z;
float rayDepth = -rayPos.z;
float depthDelta = rayDepth - stepLinearDepth;
vec3 worldNorm = normalize(vec3(globalData.ivMatrix * vec4(DecodeNormal(texelFetch(normalTexture, stepPixel, 0).rg), 0.0)));
- if (depthDelta > 0.0 && abs(depthDelta) < rayLength) {
+ // Check if we are now behind the depth buffer, use that hit as the source of radiance
+ if (stepLinearDepth < rayDepth && abs(depthDelta) < rayLength) {
float NdotL = dot(worldNorm, -ray.direction);
if (NdotL >= 0.0) {
vec3 rayIrradiance = texelFetch(directLightTexture, stepPixel * 2 + pixelOffset, 0).rgb;
- irradiance += rayIrradiance;
+ float dist = distance(viewPos, stepPos);
+ irradiance += rayIrradiance / max(0.01, dist);
}
hit = true;
diff --git a/data/shader/taa.csh b/data/shader/taa.csh
index ba7ca084d..05d9708ef 100644
--- a/data/shader/taa.csh
+++ b/data/shader/taa.csh
@@ -24,11 +24,12 @@ layout(push_constant) uniform constants {
} PushConstants;
const float minVelocityBlend = 0.05;
-const float maxVelocityBlend = 0.5;
+const float maxVelocityBlend = 0.2;
#define TAA_YCOCG
#define TAA_BICUBIC // Nearly always use the bicubic sampling for better quality and sharpness under movement
#define TAA_TONE // Somehow introduces more flickering as well
+#define TAA_CLIP
//#define TAA_DENOISE
#ifdef PATHTRACE
diff --git a/data/shader/volumetric/volumetric.hsh b/data/shader/volumetric/volumetric.hsh
index 0439c7e99..8aec38c03 100644
--- a/data/shader/volumetric/volumetric.hsh
+++ b/data/shader/volumetric/volumetric.hsh
@@ -38,11 +38,19 @@ vec3 ApplyVolumetrics(Fog fog, vec3 inputColor, vec4 volumetricFog, vec4 volumet
inputColor = alpha * inputColor;
#endif
+#ifdef FOG
vec3 outputColor = fog.density > 0.0 ? inputColor * fogExtinction + volumetricFog.rgb : inputColor;
+#else
+ vec3 outputColor = inputColor;
+#endif
#ifdef CLOUDS
fogExtinction = intersectDists.x < 0.0 ? fogExtinction : 1.0;
+#ifdef FOG
outputColor += volumetricClouds.rgb * fogExtinction;
+#else
+ outputColor += volumetricClouds.rgb;
+#endif
#endif
return outputColor;
diff --git a/libs/ImguiExtension/ImguiWrapper.cpp b/libs/ImguiExtension/ImguiWrapper.cpp
index d1e683530..8ac97357a 100644
--- a/libs/ImguiExtension/ImguiWrapper.cpp
+++ b/libs/ImguiExtension/ImguiWrapper.cpp
@@ -137,7 +137,7 @@ namespace Atlas::ImguiExtension {
commandList->EndCommands();
- device->SubmitCommandList(commandList, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
+ device->SubmitCommandList(commandList);
}
@@ -252,7 +252,7 @@ namespace Atlas::ImguiExtension {
ImGuiIO &io = ImGui::GetIO();
UpdateKeyModifiers(event.keyModifiers);
- ImGuiKey key = KeycodeToImGuiKey(event.keyCode);
+ ImGuiKey key = KeycodeToImGuiKey(static_cast(event.keyCode));
io.AddKeyEvent(key, event.down);
}
diff --git a/libs/ImguiExtension/panels/FogPanel.cpp b/libs/ImguiExtension/panels/FogPanel.cpp
index 764b63a86..ad8cb0776 100644
--- a/libs/ImguiExtension/panels/FogPanel.cpp
+++ b/libs/ImguiExtension/panels/FogPanel.cpp
@@ -22,7 +22,7 @@ namespace Atlas::ImguiExtension {
ImGui::Text("Volumetric");
ImGui::Checkbox("Raymarching", &fog->rayMarching);
ImGui::SliderInt("Raymarch step count", &fog->rayMarchStepCount, 1, 32);
- ImGui::SliderFloat("Intensity#", &fog->volumetricIntensity, 0.0f, 1.0f);
+ ImGui::SliderFloat("Intensity", &fog->volumetricIntensity, 0.0f, 1.0f);
ImGui::PopID();
diff --git a/libs/ImguiExtension/panels/PostProcessingPanel.cpp b/libs/ImguiExtension/panels/PostProcessingPanel.cpp
index 9de7b0fbe..04b4aea86 100644
--- a/libs/ImguiExtension/panels/PostProcessingPanel.cpp
+++ b/libs/ImguiExtension/panels/PostProcessingPanel.cpp
@@ -18,6 +18,7 @@ namespace Atlas::ImguiExtension {
ImGui::Separator();
ImGui::Text("Image effects");
ImGui::Checkbox("Filmic tonemapping", &postProcessing.filmicTonemapping);
+ ImGui::ColorEdit3("Tint", glm::value_ptr(postProcessing.tint));
ImGui::SliderFloat("Saturation", &postProcessing.saturation, 0.0f, 2.0f);
ImGui::SliderFloat("Contrast", &postProcessing.contrast, 0.0f, 2.0f);
ImGui::SliderFloat("Paper white luminance", &postProcessing.paperWhiteLuminance, 0.0f, 300.0f);
diff --git a/src/demo/App.cpp b/src/demo/App.cpp
index d8eaafd46..1774da86e 100644
--- a/src/demo/App.cpp
+++ b/src/demo/App.cpp
@@ -16,15 +16,6 @@ using namespace Atlas::ImguiExtension;
void App::LoadContent() {
- music = Atlas::ResourceManager::GetOrLoadResource("more.wav");
- audio = Atlas::ResourceManager::GetOrLoadResource("more.wav");
- // static auto audioStream = Atlas::Audio::AudioManager::CreateStream(audio);
-
- for (uint32_t i = 0; i < 10000; i++) {
- //audioStreams.push_back(Atlas::Audio::AudioManager::CreateStream(audio));
- //audioStreams.back()->SetVolume(0.0001);
- }
-
renderTarget = Atlas::CreateRef(1920, 1080);
pathTraceTarget = Atlas::CreateRef(1920, 1080);
@@ -49,16 +40,16 @@ void App::LoadContent() {
Atlas::Events::EventManager::KeyboardEventDelegate.Subscribe(
[this](Atlas::Events::KeyboardEvent event) {
- if (event.keyCode == AE_KEY_ESCAPE) {
+ if (event.keyCode == Keycode::KeyEscape) {
Exit();
}
- if (event.keyCode == AE_KEY_F11 && event.state == AE_BUTTON_RELEASED) {
+ if (event.keyCode == Keycode::KeyF11 && event.state == AE_BUTTON_RELEASED) {
renderUI = !renderUI;
}
- if (event.keyCode == AE_KEY_LSHIFT && event.state == AE_BUTTON_PRESSED) {
+ if (event.keyCode == Keycode::KeyLeftShift && event.state == AE_BUTTON_PRESSED) {
keyboardHandler.speed = cameraSpeed * 4.0f;
}
- if (event.keyCode == AE_KEY_LSHIFT && event.state == AE_BUTTON_RELEASED) {
+ if (event.keyCode == Keycode::KeyLeftShift && event.state == AE_BUTTON_RELEASED) {
keyboardHandler.speed = cameraSpeed;
}
});
@@ -77,7 +68,8 @@ void App::LoadContent() {
directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, 1.0f);
directionalLight.color = glm::vec3(255, 236, 209) / 255.0f;
- directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, glm::vec3(0.0f), glm::vec4(-100.0f, 100.0f, -70.0f, 120.0f));
+ directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, 0.125f,
+ glm::vec3(0.0f), glm::vec4(-100.0f, 100.0f, -70.0f, 120.0f));
directionalLight.isMain = true;
scene->ao = Atlas::CreateRef(16);
@@ -216,7 +208,6 @@ void App::Update(float deltaTime) {
};
auto& rigidBodyComponent = entity.AddComponent(bodySettings);
rigidBodyComponent.SetRestitution(sphereRestitution);
- entity.AddComponent(audio);
entities.push_back(entity);
lastSpawn = Atlas::Clock::Get();
@@ -241,8 +232,6 @@ void App::Update(float deltaTime) {
camera.direction * meshes.back()->data.radius * 2.0f));
auto entity = scene->CreatePrefab(meshes.back(), matrix, false);
- entity.AddComponent(audio);
-
auto bodySettings = Atlas::Physics::BodyCreationSettings {
.objectLayer = Atlas::Physics::Layers::MOVABLE,
.motionQuality = Atlas::Physics::MotionQuality::LinearCast,
@@ -280,15 +269,21 @@ void App::Render(float deltaTime) {
static float cloudDepthDebug = 0.0f;
+ graphicsDevice->WaitForPreviousFrameCompletion();
+
#ifndef AE_HEADLESS
auto windowFlags = window.GetFlags();
if (windowFlags & AE_WINDOW_HIDDEN || windowFlags & AE_WINDOW_MINIMIZED || !(windowFlags & AE_WINDOW_SHOWN)) {
+ // If we take the early way out we need to make sure that stuff is completed (usually main renderer takes care of that)
+ scene->WaitForAsyncWorkCompletion();
return;
}
#endif
if (!loadingComplete) {
DisplayLoadingScreen(deltaTime);
+ // If we take the early way out we need to make sure that stuff is completed
+ scene->WaitForAsyncWorkCompletion();
return;
}
@@ -490,6 +485,8 @@ void App::Render(float deltaTime) {
ImGui::SliderInt("Max accumulated frames##Pathtrace", &mainRenderer->pathTracingRenderer.historyLengthMax, 1, 256);
ImGui::SliderFloat("Current clip##Pathtrace", &mainRenderer->pathTracingRenderer.currentClipFactor, 0.1f, 4.0f);
ImGui::SliderFloat("Max history clip##Pathtrace", &mainRenderer->pathTracingRenderer.historyClipMax, 0.0f, 1.0f);
+
+ scene->rayTracingWorld->includeObjectHistory = pathTrace;
}
if (ImGui::CollapsingHeader("DDGI")) {
irradianceVolumePanel.Render(volume);
@@ -522,6 +519,7 @@ void App::Render(float deltaTime) {
}
}
ImGui::SliderFloat("Bias##Shadow", &shadow->bias, 0.0f, 2.0f);
+ ImGui::DragFloat("Edge softness##Shadow", &shadow->edgeSoftness, 0.005f, 0.0f, 1.0f);
}
if (ImGui::CollapsingHeader("Screen-space shadows")) {
ImGui::Checkbox("Debug##SSS", &debugSSS);
@@ -587,10 +585,6 @@ void App::Render(float deltaTime) {
if (ImGui::Button("Restore state##Physics")) {
scene->physicsWorld->RestoreState();
}
- ImGui::SameLine();
- if (ImGui::Button("Serialize##Physics")) {
- Atlas::Scene::SceneSerializer::SerializeScene(scene, "test.json");
- }
}
if (ImGui::CollapsingHeader("Materials")) {
int32_t id = 0;
@@ -896,7 +890,7 @@ bool App::LoadScene() {
scene->fog->volumetricIntensity = 0.0f;
}
else if (sceneSelection == FOREST) {
- auto otherScene = Atlas::Loader::ModelLoader::LoadScene("forest/forest.gltf");
+ auto otherScene = Atlas::Loader::ModelLoader::LoadScene("forest/forest.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5);
otherScene->Timestep(1.0f);
CopyActors(otherScene);
@@ -913,7 +907,7 @@ bool App::LoadScene() {
scene->fog->volumetricIntensity = 0.08f;
}
else if (sceneSelection == EMERALDSQUARE) {
- auto otherScene = Atlas::Loader::ModelLoader::LoadScene("emeraldsquare/square.gltf", false, 1024);
+ auto otherScene = Atlas::Loader::ModelLoader::LoadScene("emeraldsquare/square.gltf", -glm::vec3(2048.0f), glm::vec3(2048.0f), 5);
otherScene->Timestep(1.0f);
CopyActors(otherScene);
@@ -1074,6 +1068,8 @@ void App::CheckLoadScene() {
material->metalness = 0.0f;
}
+ graphicsDevice->WaitForPreviousFrameCompletion();
+
static std::future future;
auto buildRTStructure = [&]() {
diff --git a/src/demo/App.h b/src/demo/App.h
index 00c246f5a..5608fe7a3 100644
--- a/src/demo/App.h
+++ b/src/demo/App.h
@@ -67,9 +67,6 @@ class App : public Atlas::EngineInstance {
Ref scene;
- Atlas::ResourceHandle audio;
- Atlas::ResourceHandle music;
-
std::vector> meshes;
Atlas::Scene::Entity cameraEntity;
diff --git a/src/editor/App.cpp b/src/editor/App.cpp
index 8afbabab9..92816fc2d 100644
--- a/src/editor/App.cpp
+++ b/src/editor/App.cpp
@@ -1,7 +1,7 @@
#include "App.h"
#include "FileImporter.h"
#include "Singletons.h"
-#include "Serializer.h"
+#include "Serialization.h"
#include "Notifications.h"
#include "ui/panels/PopupPanels.h"
#include
@@ -38,16 +38,9 @@ namespace Atlas::Editor {
Singletons::imguiWrapper = CreateRef();
Singletons::imguiWrapper->Load(&window);
Singletons::config = CreateRef();
-
- Physics::SphereShapeSettings settings {
- .radius = 1.0f,
- .scale = vec3(0.9f),
- };
- auto shape = Physics::ShapesManager::CreateShape(settings);
-
- shape->Scale(vec3(0.8f));
+
- Serializer::DeserializeConfig();
+ Serialization::DeserializeConfig();
// Everything that needs the config comes afterwards
Singletons::icons = CreateRef();
@@ -70,10 +63,12 @@ namespace Atlas::Editor {
Singletons::imguiWrapper->Unload();
for (const auto& sceneWindow : sceneWindows) {
- Serializer::SerializeSceneWindow(sceneWindow);
+ if (sceneWindow->isPlaying)
+ sceneWindow->StopPlaying();
+ Serialization::SerializeSceneWindow(sceneWindow);
}
- Serializer::SerializeConfig();
+ Serialization::SerializeConfig();
Singletons::Destruct();
@@ -91,7 +86,7 @@ namespace Atlas::Editor {
std::swap(waitToLoadScenes[i], waitToLoadScenes.back());
// After the scene is loaded we can retrieve the window configuration and deserialize it
- sceneWindows.emplace_back(Serializer::DeserializeSceneWindow(waitToLoadScenes.back()));
+ sceneWindows.emplace_back(Serialization::DeserializeSceneWindow(waitToLoadScenes.back()));
waitToLoadScenes.pop_back();
i--;
}
@@ -135,7 +130,9 @@ namespace Atlas::Editor {
std::reverse(toBeDeletedSceneWindows.begin(), toBeDeletedSceneWindows.end());
for (auto sceneWindowIdx : toBeDeletedSceneWindows) {
// Serialize window before erasing it
- Serializer::SerializeSceneWindow(sceneWindows[sceneWindowIdx]);
+ if (sceneWindows[sceneWindowIdx]->isPlaying)
+ sceneWindows[sceneWindowIdx]->StopPlaying();
+ Serialization::SerializeSceneWindow(sceneWindows[sceneWindowIdx]);
sceneWindows.erase(sceneWindows.begin() + sceneWindowIdx);
}
@@ -152,7 +149,7 @@ namespace Atlas::Editor {
auto cameraEntity = activeSceneWindow->cameraEntity;
if (cameraEntity.IsValid() && activeSceneWindow->viewportPanel.isFocused && !lockMovement &&
- !ImGuizmo::IsUsing() && (!activeSceneWindow->isPlaying || !activeSceneWindow->hasPlayer)) {
+ !ImGuizmo::IsUsing() && !activeSceneWindow->isPlaying) {
auto& camera = cameraEntity.GetComponent();
mouseHandler.sensibility = activeSceneWindow->cameraRotationSpeed;
keyboardHandler.speed = activeSceneWindow->cameraMovementSpeed;
@@ -189,6 +186,10 @@ namespace Atlas::Editor {
ImGuizmo::Enable(activeSceneWindow->needGuizmoEnabled);
+ graphicsDevice->WaitForPreviousFrameCompletion();
+
+
+ // This crashes when we start with path tracing and do the bvh build async
// Launch BVH builds asynchronously
auto buildRTStructure = [&]() {
auto sceneMeshes = ResourceManager::GetResources();
@@ -209,11 +210,13 @@ namespace Atlas::Editor {
else if(bvhBuilderFuture.wait_for(std::chrono::microseconds(0)) == std::future_status::ready) {
bvhBuilderFuture.get();
}
-
+
}
void App::Render(float deltaTime) {
+ graphicsDevice->WaitForPreviousFrameCompletion();
+
auto windowFlags = window.GetFlags();
if (windowFlags & AE_WINDOW_HIDDEN || windowFlags & AE_WINDOW_MINIMIZED || !(windowFlags & AE_WINDOW_SHOWN)) {
return;
@@ -296,7 +299,8 @@ namespace Atlas::Editor {
contentBrowserWindow.Render();
logWindow.Render();
profilerWindow.Render();
- geometryBrushWindow.Render(sceneWindows[activeSceneIdx]);
+
+ geometryBrushWindow.Render(sceneWindows.empty() ? nullptr : sceneWindows[activeSceneIdx]);
for (auto& sceneWindow : sceneWindows) {
sceneWindow->Render();
diff --git a/src/editor/DataCreator.cpp b/src/editor/DataCreator.cpp
index e1141aa51..ef010e966 100644
--- a/src/editor/DataCreator.cpp
+++ b/src/editor/DataCreator.cpp
@@ -1,11 +1,14 @@
#include "DataCreator.h"
+#include "loader/ModelLoader.h"
+#include "volume/AABB.h"
+
namespace Atlas::Editor {
using namespace Scene::Components;
using namespace Scene::Prefabs;
- Ref DataCreator::CreateScene(const std::string &name, vec3 min, vec3 max, int32_t depth) {
+ Ref DataCreator::CreateScene(const std::string& name, vec3 min, vec3 max, int32_t depth) {
auto scene = CreateRef(name, min, max, depth);
@@ -20,7 +23,8 @@ namespace Atlas::Editor {
directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, 1.0f);
directionalLight.color = glm::vec3(255, 236, 209) / 255.0f;
directionalLight.intensity = 10.0f;
- directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, glm::vec3(0.0f), vec4(-100.0f, 100.0f, -70.0f, 120.0f));
+ directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, 0.05f,
+ glm::vec3(0.0f), vec4(-100.0f, 100.0f, -70.0f, 120.0f));
directionalLight.isMain = true;
mainHierarchy.AddChild(directionalLightEntity);
@@ -64,4 +68,110 @@ namespace Atlas::Editor {
}
+ Ref DataCreator::CreateSceneFromMesh(const std::string& filename, vec3 min, vec3 max,
+ int32_t depth, bool invertUVs, bool addRigidBodies, bool combineMeshes, bool makeMeshesStatic) {
+
+ auto scene = Loader::ModelLoader::LoadScene(filename, min, max, depth,
+ combineMeshes, makeMeshesStatic, false, 2048);
+
+ auto rootEntity = scene->GetEntityByName("Root");
+ auto& mainHierarchy = rootEntity.GetComponent();
+
+ auto directionalLightEntity = scene->CreateEntity();
+ directionalLightEntity.AddComponent("Directional light");
+ auto& directionalLight = directionalLightEntity.AddComponent(LightType::DirectionalLight);
+
+ directionalLight.properties.directional.direction = glm::vec3(0.0f, -1.0f, 1.0f);
+ directionalLight.color = glm::vec3(255, 236, 209) / 255.0f;
+ directionalLight.intensity = 10.0f;
+ directionalLight.AddDirectionalShadow(200.0f, 3.0f, 4096, 0.05f,
+ glm::vec3(0.0f), vec4(-100.0f, 100.0f, -70.0f, 120.0f));
+ directionalLight.isMain = true;
+
+ mainHierarchy.AddChild(directionalLightEntity);
+
+ scene->ao = CreateRef(16);
+ scene->ao->rt = true;
+ // Use SSGI by default
+ scene->ao->enable = false;
+ scene->reflection = CreateRef();
+ scene->reflection->useShadowMap = true;
+
+ scene->fog = CreateRef();
+ scene->fog->enable = true;
+ scene->fog->density = 0.0002f;
+ scene->fog->heightFalloff = 0.0284f;
+ scene->fog->height = 0.0f;
+
+ scene->sky.atmosphere = CreateRef();
+
+ scene->postProcessing.taa = PostProcessing::TAA(0.99f);
+ scene->postProcessing.sharpen.enable = true;
+ scene->postProcessing.sharpen.factor = 0.15f;
+
+ scene->irradianceVolume = CreateRef(Volume::AABB(min, max), ivec3(20));
+
+ scene->sss = CreateRef();
+
+ scene->ssgi = CreateRef();
+
+ scene->sky.clouds = CreateRef();
+ scene->sky.clouds->minHeight = 1400.0f;
+ scene->sky.clouds->maxHeight = 1700.0f;
+ scene->sky.clouds->castShadow = false;
+
+ scene->physicsWorld = CreateRef();
+ scene->physicsWorld->pauseSimulation = true;
+
+ scene->rayTracingWorld = CreateRef();
+ scene->postProcessing.fsr2 = true;
+
+ scene->Timestep(1.0f);
+
+ min = glm::vec3(std::numeric_limits::max());
+ max = glm::vec3(-std::numeric_limits::max());
+
+ Volume::AABB aabb(min, max);
+ auto meshSubset = scene->GetSubset();
+ for (auto entity : meshSubset) {
+ const auto& meshComponent = meshSubset.Get(entity);
+
+ aabb.Grow(meshComponent.aabb);
+ }
+
+ // Adjust settings based on calculated size
+ scene->irradianceVolume->SetAABB(aabb);
+
+ if (invertUVs) {
+ auto meshes = scene->GetMeshes();
+
+ for (const auto& mesh : meshes)
+ mesh->invertUVs = true;
+ }
+
+ if (addRigidBodies) {
+ for (auto entity : meshSubset) {
+ const auto& meshComponent = meshSubset.Get(entity);
+
+ auto transformComponent = entity.GetComponent();
+ Atlas::Physics::MeshShapeSettings settings = {
+ .mesh = meshComponent.mesh,
+ .scale = transformComponent.DecomposeGlobal().scale
+ };
+ auto shape = Atlas::Physics::ShapesManager::CreateShape(settings);
+
+ auto bodySettings = Atlas::Physics::BodyCreationSettings{
+ .objectLayer = Atlas::Physics::Layers::STATIC,
+ .shape = shape,
+ };
+ entity.AddComponent(bodySettings);
+ }
+ }
+
+ scene->physicsWorld->OptimizeBroadphase();
+
+ return scene;
+
+ }
+
}
\ No newline at end of file
diff --git a/src/editor/DataCreator.h b/src/editor/DataCreator.h
index b6459f60e..2e4e47493 100644
--- a/src/editor/DataCreator.h
+++ b/src/editor/DataCreator.h
@@ -9,6 +9,9 @@ namespace Atlas::Editor {
public:
static Ref CreateScene(const std::string& name, vec3 min, vec3 max, int32_t depth);
+ static Ref CreateSceneFromMesh(const std::string& filename,vec3 min, vec3 max, int32_t depth,
+ bool invertUVs, bool addRigidBodies, bool combineMeshes, bool makeMeshesStatic);
+
};
}
\ No newline at end of file
diff --git a/src/editor/FileImporter.cpp b/src/editor/FileImporter.cpp
index 2402178d1..06625bb0d 100644
--- a/src/editor/FileImporter.cpp
+++ b/src/editor/FileImporter.cpp
@@ -29,6 +29,7 @@ namespace Atlas::Editor {
case FileType::Audio: ImportFile(filename); break;
case FileType::Mesh: ImportFile(filename); break;
case FileType::Scene: ImportFile(filename); break;
+ case FileType::Script: ImportFile(filename); break;
case FileType::Font: ImportFile(filename); break;
default: break;
}
diff --git a/src/editor/FileImporter.h b/src/editor/FileImporter.h
index 75489f393..a5fcd1f5b 100644
--- a/src/editor/FileImporter.h
+++ b/src/editor/FileImporter.h
@@ -10,10 +10,11 @@
#include "mesh/Mesh.h"
#include "scene/Scene.h"
#include "audio/AudioData.h"
+#include "scripting/Script.h"
#include "Font.h"
#include "loader/ModelLoader.h"
-#include "scene/SceneSerializer.h"
+#include "Serializer.h"
namespace Atlas::Editor {
@@ -55,14 +56,15 @@ namespace Atlas::Editor {
}
else if constexpr (std::is_same_v) {
handle = ResourceManager::GetOrLoadResourceWithLoaderAsync(filename,
- ResourceOrigin::User, Loader::ModelLoader::LoadMesh, false, 8192);
+ ResourceOrigin::User, Loader::ModelLoader::LoadMesh, false, 2048);
}
else if constexpr (std::is_same_v) {
handle = ResourceManager::GetOrLoadResourceWithLoaderAsync(filename,
- ResourceOrigin::User, Scene::SceneSerializer::DeserializeScene);
+ ResourceOrigin::User, Serializer::DeserializeScene, false);
}
- else if constexpr (std::is_same_v) {
- // Load script here
+ else if constexpr (std::is_same_v) {
+ handle = ResourceManager::GetOrLoadResourceAsync(
+ filename, ResourceOrigin::User);
}
else if constexpr (std::is_same_v) {
handle = ResourceManager::GetOrLoadResourceAsync(filename,
@@ -93,7 +95,7 @@ namespace Atlas::Editor {
else if constexpr (std::is_same_v) {
return type == FileType::Scene;
}
- else if constexpr (std::is_same_v) {
+ else if constexpr (std::is_same_v) {
return type == FileType::Script;
}
else if constexpr (std::is_same_v) {
diff --git a/src/editor/Serializer.cpp b/src/editor/Serialization.cpp
similarity index 83%
rename from src/editor/Serializer.cpp
rename to src/editor/Serialization.cpp
index acc1fd21e..13e4e35a2 100644
--- a/src/editor/Serializer.cpp
+++ b/src/editor/Serialization.cpp
@@ -1,19 +1,19 @@
-#include "Serializer.h"
+#include "Serialization.h"
#include "Singletons.h"
#include "FileImporter.h"
#include "common/SerializationHelper.h"
-#include "scene/EntitySerializer.h"
+#include "scene/SceneSerializer.h"
#include "Log.h"
#include "loader/AssetLoader.h"
namespace Atlas::Editor {
- const std::string Serializer::configPath = ".config/";
- const std::string Serializer::configFilename = configPath + "config.json";
+ const std::string Serialization::configPath = ".config/";
+ const std::string Serialization::configFilename = configPath + "config.json";
- void Serializer::SerializeConfig() {
+ void Serialization::SerializeConfig() {
const auto& config = Singletons::config;
@@ -31,7 +31,7 @@ namespace Atlas::Editor {
}
- void Serializer::DeserializeConfig() {
+ void Serialization::DeserializeConfig() {
auto serialized = TryReadFromFile(configFilename);
@@ -57,14 +57,14 @@ namespace Atlas::Editor {
}
- void Serializer::SerializeSceneWindow(const Ref& sceneWindow) {
+ void Serialization::SerializeSceneWindow(const Ref& sceneWindow) {
if (!sceneWindow->scene.IsLoaded())
return;
json camera;
std::set insertedEntites;
- Scene::EntityToJson(camera, sceneWindow->cameraEntity, sceneWindow->scene.Get(), insertedEntites);
+ Scene::EntityToJson(camera, sceneWindow->cameraEntity, sceneWindow->scene.Get().get(), insertedEntites);
json j = {
{ "cameraMovementSpeed", sceneWindow->cameraMovementSpeed },
@@ -78,7 +78,7 @@ namespace Atlas::Editor {
}
- Ref Serializer::DeserializeSceneWindow(ResourceHandle handle) {
+ Ref Serialization::DeserializeSceneWindow(ResourceHandle handle) {
if (!handle.IsLoaded())
return nullptr;
@@ -104,7 +104,7 @@ namespace Atlas::Editor {
j.at("camera").get_to(camera);
sceneWindow->cameraEntity = sceneWindow->scene->CreateEntity();
- Scene::EntityFromJson(camera, sceneWindow->cameraEntity, sceneWindow->scene.Get());
+ Scene::EntityFromJson(camera, sceneWindow->cameraEntity, sceneWindow->scene.Get().get());
// When closing the application while playing the entity is saved in the wrong state
sceneWindow->cameraEntity.GetComponent().isMain = true;
@@ -113,7 +113,7 @@ namespace Atlas::Editor {
}
- void Serializer::TryWriteToFile(const std::string& filename, const std::string& content) {
+ void Serialization::TryWriteToFile(const std::string& filename, const std::string& content) {
auto fileStream = Loader::AssetLoader::WriteFile(filename, std::ios::out | std::ios::binary);
@@ -128,7 +128,7 @@ namespace Atlas::Editor {
}
- std::string Serializer::TryReadFromFile(const std::string& filename) {
+ std::string Serialization::TryReadFromFile(const std::string& filename) {
Loader::AssetLoader::UnpackFile(filename);
auto path = Loader::AssetLoader::GetFullPath(filename);
diff --git a/src/editor/Serializer.h b/src/editor/Serialization.h
similarity index 96%
rename from src/editor/Serializer.h
rename to src/editor/Serialization.h
index 7dde5009b..e962cf501 100644
--- a/src/editor/Serializer.h
+++ b/src/editor/Serialization.h
@@ -6,7 +6,7 @@
namespace Atlas::Editor {
- class Serializer {
+ class Serialization {
public:
static void SerializeConfig();
diff --git a/src/editor/ui/panels/EntityPropertiesPanel.cpp b/src/editor/ui/panels/EntityPropertiesPanel.cpp
index 7a4c7fe2d..9c29aed7e 100644
--- a/src/editor/ui/panels/EntityPropertiesPanel.cpp
+++ b/src/editor/ui/panels/EntityPropertiesPanel.cpp
@@ -57,6 +57,11 @@ namespace Atlas::Editor::UI {
entity, textComponentPanel, comp);
}
+ if (entity.HasComponent()) {
+ RenderComponentPanel("Lua script component", scene,
+ entity, luaScriptComponentPanel, entity.GetComponent());
+ }
+
if (entity.HasComponent()) {
auto comp = entity.GetComponent();
RenderComponentPanel("Rigid body component", scene,
@@ -101,6 +106,8 @@ namespace Atlas::Editor::UI {
entity.AddComponent();
if (!entity.HasComponent() && ImGui::MenuItem("Add text component"))
entity.AddComponent();
+ if (!entity.HasComponent() && ImGui::MenuItem("Add lua script component"))
+ entity.AddComponent();
// Just make the player component addable if there is a transform component
if (entity.HasComponent() &&
@@ -154,6 +161,8 @@ namespace Atlas::Editor::UI {
entity.RemoveComponent();
if (entity.HasComponent() && ImGui::MenuItem("Remove text component"))
entity.RemoveComponent();
+ if (entity.HasComponent() && ImGui::MenuItem("Remove lua script component"))
+ entity.RemoveComponent();
if (entity.HasComponent() && ImGui::MenuItem("Remove player component"))
entity.RemoveComponent();
if (entity.HasComponent() && ImGui::MenuItem("Remove rigid body component"))
diff --git a/src/editor/ui/panels/EntityPropertiesPanel.h b/src/editor/ui/panels/EntityPropertiesPanel.h
index 4e6591bd5..9cabb2d0a 100644
--- a/src/editor/ui/panels/EntityPropertiesPanel.h
+++ b/src/editor/ui/panels/EntityPropertiesPanel.h
@@ -9,6 +9,7 @@
#include "components/LightComponentPanel.h"
#include "components/AudioComponentPanel.h"
#include "components/AudioVolumeComponentPanel.h"
+#include "components/LuaScriptComponentPanel.h"
#include "components/RigidBodyComponentPanel.h"
#include "components/PlayerComponentPanel.h"
#include "components/CameraComponentPanel.h"
@@ -32,6 +33,7 @@ namespace Atlas::Editor::UI {
LightComponentPanel lightComponentPanel;
AudioComponentPanel audioComponentPanel;
AudioVolumeComponentPanel audioVolumeComponentPanel;
+ LuaScriptComponentPanel luaScriptComponentPanel;
RigidBodyComponentPanel rigidBodyComponentPanel;
PlayerComponentPanel playerComponentPanel;
CameraComponentPanel cameraComponentPanel;
diff --git a/src/editor/ui/panels/PopupPanels.cpp b/src/editor/ui/panels/PopupPanels.cpp
index 23164ec2a..6a10cdaf3 100644
--- a/src/editor/ui/panels/PopupPanels.cpp
+++ b/src/editor/ui/panels/PopupPanels.cpp
@@ -9,10 +9,14 @@
namespace Atlas::Editor::UI {
bool PopupPanels::isNewScenePopupVisible = false;
+ bool PopupPanels::isImportScenePopupVisible = false;
+
+ std::string PopupPanels::filename = "";
void PopupPanels::Render() {
RenderNewScenePopup();
+ RenderImportScenePopup();
}
@@ -28,13 +32,20 @@ namespace Atlas::Editor::UI {
SetupPopupSize(0.6f, 0.3f);
+ bool popupNew = false;
+
if (!ImGui::IsPopupOpen("New scene")) {
+ popupNew = true;
ImGui::OpenPopup("New scene");
}
if (ImGui::BeginPopupModal("New scene", nullptr, ImGuiWindowFlags_NoResize)) {
+ if (popupNew)
+ ImGui::SetKeyboardFocusHere();
+
ImGui::InputTextWithHint("Name", "Type scene name here", &name);
+
ImGui::DragFloat3("Min size", &minSize[0], 1.0f, -8192.0f, 8192.0f, "%.3f", ImGuiSliderFlags_Logarithmic);
ImGui::DragFloat3("Max size", &maxSize[0], 1.0f, -8192.0f, 8192.0f, "%.3f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderInt("Octree depth", &octreeDepth, 1, 12);
@@ -46,7 +57,7 @@ namespace Atlas::Editor::UI {
ImGui::SameLine();
- if (ImGui::Button("Ok")) {
+ if (ImGui::Button("Ok") || ImGui::IsKeyReleased(ImGuiKey_Enter)) {
auto scene = DataCreator::CreateScene(name, minSize, maxSize, octreeDepth);
bool alreadyExisted;
@@ -66,6 +77,79 @@ namespace Atlas::Editor::UI {
}
+ void PopupPanels::RenderImportScenePopup() {
+
+ if (!isImportScenePopupVisible)
+ return;
+
+ static std::string name;
+ static auto minSize = glm::vec3(-2048.0f);
+ static auto maxSize = glm::vec3(2048.0f);
+ static int32_t octreeDepth = 5;
+ static bool invertUVs = false;
+ static bool addRigidBodies = false;
+ static bool combineMeshes = false;
+ static bool makeMeshesStatic = false;
+
+ SetupPopupSize(0.6f, 0.3f);
+
+ bool popupNew = false;
+
+ if (!ImGui::IsPopupOpen("Import scene")) {
+ popupNew = true;
+ ImGui::OpenPopup("Import scene");
+ }
+
+ if (ImGui::BeginPopupModal("Import scene", nullptr, ImGuiWindowFlags_NoResize)) {
+
+ if (popupNew) {
+ ImGui::SetKeyboardFocusHere();
+ name = Common::Path::GetFileNameWithoutExtension(filename);
+ }
+
+ ImGui::Text("General properties");
+
+ ImGui::InputTextWithHint("Name", "Type scene name here", &name);
+
+ ImGui::DragFloat3("Min size", &minSize[0], 1.0f, -8192.0f, 8192.0f, "%.3f", ImGuiSliderFlags_Logarithmic);
+ ImGui::DragFloat3("Max size", &maxSize[0], 1.0f, -8192.0f, 8192.0f, "%.3f", ImGuiSliderFlags_Logarithmic);
+ ImGui::SliderInt("Octree depth", &octreeDepth, 1, 12);
+
+ ImGui::Text("Import properties");
+ ImGui::Checkbox("Invert UVs", &invertUVs);
+ ImGui::Checkbox("Attach mesh rigid body components", &addRigidBodies);
+ ImGui::Checkbox("Combine meshes", &combineMeshes);
+ ImGui::Checkbox("Make meshes static", &makeMeshesStatic);
+
+ if (ImGui::Button("Cancel")) {
+ isImportScenePopupVisible = false;
+ ImGui::CloseCurrentPopup();
+ }
+
+ ImGui::SameLine();
+
+ if (ImGui::Button("Ok") || ImGui::IsKeyReleased(ImGuiKey_Enter)) {
+ auto scene = DataCreator::CreateSceneFromMesh(filename, minSize, maxSize,
+ octreeDepth, invertUVs, addRigidBodies, combineMeshes, makeMeshesStatic);
+ scene->name = name;
+
+ bool alreadyExisted;
+ Atlas::ResourceManager::AddResource(name, scene, alreadyExisted);
+
+ if (alreadyExisted) {
+ Log::Warning("Scene couldn't be created due to scene with same name existing already");
+ }
+
+ isImportScenePopupVisible = false;
+ ImGui::CloseCurrentPopup();
+ }
+
+ ImGui::EndPopup();
+
+ }
+
+ }
+
void PopupPanels::SetupPopupSize(float horizontalFactor, float verticalFactor) {
auto viewport = ImGui::GetMainViewport();
diff --git a/src/editor/ui/panels/PopupPanels.h b/src/editor/ui/panels/PopupPanels.h
index dea8b7f2e..c1de77c67 100644
--- a/src/editor/ui/panels/PopupPanels.h
+++ b/src/editor/ui/panels/PopupPanels.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
namespace Atlas::Editor::UI {
class PopupPanels {
@@ -7,13 +9,18 @@ namespace Atlas::Editor::UI {
public:
static void Render();
+ static void SetupPopupSize(float horizontalFactor, float verticalFactor);
+
static bool isNewScenePopupVisible;
+ static bool isImportScenePopupVisible;
static bool isAddComponentPopupVisible;
+ static std::string filename;
+
private:
static void RenderNewScenePopup();
- static void SetupPopupSize(float horizontalFactor, float verticalFactor);
+ static void RenderImportScenePopup();
};
diff --git a/src/editor/ui/panels/SceneHierarchyPanel.cpp b/src/editor/ui/panels/SceneHierarchyPanel.cpp
index e1bad9308..31651a0c6 100644
--- a/src/editor/ui/panels/SceneHierarchyPanel.cpp
+++ b/src/editor/ui/panels/SceneHierarchyPanel.cpp
@@ -10,6 +10,9 @@ namespace Atlas::Editor::UI {
ImGui::Begin(GetNameID());
+ if (ImGui::IsDragDropActive() && ImGui::IsWindowHovered() && !ImGui::IsWindowFocused())
+ ImGui::SetWindowFocus();
+
isFocused = ImGui::IsWindowFocused();
if (scene != nullptr) {
@@ -38,7 +41,17 @@ namespace Atlas::Editor::UI {
ImGui::InputTextWithHint("Search", "Type to search for entity", &entitySearch);
- TraverseHierarchy(scene, root, inFocus);
+ // Search should be case-insensitive
+ transformedEntitySearch = entitySearch;
+ std::transform(transformedEntitySearch.begin(), transformedEntitySearch.end(),
+ transformedEntitySearch.begin(), ::tolower);
+
+ std::unordered_map matchMap;
+ matchMap.reserve(scene->GetEntityCount());
+ if (!transformedEntitySearch.empty())
+ SearchHierarchy(scene, root, matchMap, false);
+
+ TraverseHierarchy(scene, root, matchMap, inFocus);
RenderExtendedHierarchy(scene);
@@ -49,9 +62,9 @@ namespace Atlas::Editor::UI {
#else
controlDown = io.KeyCtrl;
#endif
- if (inFocus && controlDown && ImGui::IsKeyReleased(ImGuiKey_D))
+ if (inFocus && controlDown && ImGui::IsKeyPressed(ImGuiKey_D, false))
DuplicateSelectedEntity(scene);
- if (inFocus && ImGui::IsKeyReleased(ImGuiKey_Delete))
+ if (inFocus && ImGui::IsKeyPressed(ImGuiKey_Delete, false))
DeleteSelectedEntity(scene);
}
@@ -60,7 +73,8 @@ namespace Atlas::Editor::UI {
}
- void SceneHierarchyPanel::TraverseHierarchy(Ref& scene, Scene::Entity entity, bool inFocus) {
+ void SceneHierarchyPanel::TraverseHierarchy(Ref& scene, Scene::Entity entity,
+ std::unordered_map& matchMap, bool inFocus) {
ImGuiTreeNodeFlags baseFlags = ImGuiTreeNodeFlags_OpenOnArrow |
ImGuiTreeNodeFlags_OpenOnDoubleClick;
@@ -74,8 +88,11 @@ namespace Atlas::Editor::UI {
std::string nodeName = nameComponent ? nameComponent->name : "Entity " + std::to_string(entity);
+ // If the search term matches we want to display everything below this item in the hierarchy
+ bool validSearch = (transformedEntitySearch.empty() || matchMap[entity]);
+
// If we have a search term and the name doesn't match, return
- if (nodeName != "Root" && !entitySearch.empty() && nodeName.find(entitySearch) == std::string::npos)
+ if (nodeName != "Root" && !validSearch)
return;
auto nodeFlags = baseFlags;
@@ -130,7 +147,7 @@ namespace Atlas::Editor::UI {
auto children = hierarchyComponent->GetChildren();
for (auto childEntity : children) {
- TraverseHierarchy(scene, childEntity, inFocus);
+ TraverseHierarchy(scene, childEntity, matchMap, inFocus);
}
@@ -271,4 +288,33 @@ namespace Atlas::Editor::UI {
}
+ bool SceneHierarchyPanel::SearchHierarchy(Ref& scene, Scene::Entity entity,
+ std::unordered_map& matchMap, bool parentMatches) {
+
+ auto hierarchyComponent = entity.TryGetComponent();
+ auto nameComponent = entity.TryGetComponent();
+
+ std::string nodeName = nameComponent ? nameComponent->name : "Entity " + std::to_string(entity);
+ std::transform(nodeName.begin(), nodeName.end(), nodeName.begin(), ::tolower);
+
+ parentMatches |= nodeName.find(transformedEntitySearch) != std::string::npos;
+ bool matches = parentMatches;
+
+ if (hierarchyComponent) {
+
+ auto children = hierarchyComponent->GetChildren();
+ for (auto childEntity : children) {
+
+ matches |= SearchHierarchy(scene, childEntity, matchMap, parentMatches);
+
+ }
+
+ }
+
+ matchMap[entity] = matches;
+
+ return matches;
+
+ }
+
}
\ No newline at end of file
diff --git a/src/editor/ui/panels/SceneHierarchyPanel.h b/src/editor/ui/panels/SceneHierarchyPanel.h
index 3e1da111f..1da1c53cf 100644
--- a/src/editor/ui/panels/SceneHierarchyPanel.h
+++ b/src/editor/ui/panels/SceneHierarchyPanel.h
@@ -27,7 +27,8 @@ namespace Atlas::Editor::UI {
SelectedProperty selectedProperty;
private:
- void TraverseHierarchy(Ref& scene, Scene::Entity entity, bool inFocus);
+ void TraverseHierarchy(Ref& scene, Scene::Entity entity,
+ std::unordered_map& matchMap, bool inFocus);
void RenderExtendedHierarchy(const Ref& scene);
@@ -37,7 +38,11 @@ namespace Atlas::Editor::UI {
void DuplicateSelectedEntity(Ref& scene);
+ bool SearchHierarchy(Ref& scene, Scene::Entity entity,
+ std::unordered_map& matchMap, bool parentMatches);
+
std::string entitySearch;
+ std::string transformedEntitySearch;
};
diff --git a/src/editor/ui/panels/ScenePropertiesPanel.h b/src/editor/ui/panels/ScenePropertiesPanel.h
index 159583495..f001e4d9f 100644
--- a/src/editor/ui/panels/ScenePropertiesPanel.h
+++ b/src/editor/ui/panels/ScenePropertiesPanel.h
@@ -20,6 +20,9 @@ namespace Atlas::Editor::UI {
ImGui::Begin(GetNameID());
+ if (ImGui::IsDragDropActive() && ImGui::IsWindowHovered() && !ImGui::IsWindowFocused())
+ ImGui::SetWindowFocus();
+
isFocused = ImGui::IsWindowFocused();
if constexpr (std::is_same_v) {
diff --git a/src/editor/ui/panels/components/AudioComponentPanel.cpp b/src/editor/ui/panels/components/AudioComponentPanel.cpp
index c198f4001..ce332a7a2 100644
--- a/src/editor/ui/panels/components/AudioComponentPanel.cpp
+++ b/src/editor/ui/panels/components/AudioComponentPanel.cpp
@@ -14,9 +14,20 @@ namespace Atlas::Editor::UI {
resource = audioComponent.stream->data.GetResource();
auto buttonName = resource != nullptr ? resource->GetFileName() : "Drop resource here";
- ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0});
+ if (ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0}))
+ audioSelectionPopup.Open();
+
+ // Such that drag and drop will work from the content browser
+ if (ImGui::IsDragDropActive() && ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ ImGui::SetItemDefaultFocus();
+ }
auto handle = ResourcePayloadHelper::AcceptDropResource();
+
+ auto audioResources = ResourceManager::GetResources();
+ handle = audioSelectionPopup.Render(audioResources);
+
if (handle.IsValid()) {
audioComponent.ChangeResource(handle);
resourceChanged = true;
diff --git a/src/editor/ui/panels/components/AudioComponentPanel.h b/src/editor/ui/panels/components/AudioComponentPanel.h
index f9405e340..c1efeca79 100644
--- a/src/editor/ui/panels/components/AudioComponentPanel.h
+++ b/src/editor/ui/panels/components/AudioComponentPanel.h
@@ -5,6 +5,8 @@
#include "scene/Scene.h"
#include "scene/components/AudioComponent.h"
+#include "../../popups/ResourceSelectionPopup.h"
+
namespace Atlas::Editor::UI {
class AudioComponentPanel : public Panel {
@@ -14,6 +16,9 @@ namespace Atlas::Editor::UI {
bool Render(Ref& scene, Scene::Entity entity, AudioComponent& audioVolumeComponent);
+ private:
+ ResourceSelectionPopup audioSelectionPopup;
+
};
}
diff --git a/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp b/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp
index a4e9161eb..62493c21e 100644
--- a/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp
+++ b/src/editor/ui/panels/components/AudioVolumeComponentPanel.cpp
@@ -14,9 +14,20 @@ namespace Atlas::Editor::UI {
resource = audioVolumeComponent.stream->data.GetResource();
auto buttonName = resource != nullptr ? resource->GetFileName() : "Drop resource here";
- ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0});
+ if (ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0}))
+ audioSelectionPopup.Open();
+
+ // Such that drag and drop will work from the content browser
+ if (ImGui::IsDragDropActive() && ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ ImGui::SetItemDefaultFocus();
+ }
auto handle = ResourcePayloadHelper::AcceptDropResource();
+
+ auto audioResources = ResourceManager::GetResources();
+ handle = audioSelectionPopup.Render(audioResources);
+
if (handle.IsValid()) {
audioVolumeComponent.ChangeResource(handle);
resourceChanged = true;
diff --git a/src/editor/ui/panels/components/AudioVolumeComponentPanel.h b/src/editor/ui/panels/components/AudioVolumeComponentPanel.h
index ba20cb3b3..073c6dbc0 100644
--- a/src/editor/ui/panels/components/AudioVolumeComponentPanel.h
+++ b/src/editor/ui/panels/components/AudioVolumeComponentPanel.h
@@ -5,6 +5,8 @@
#include "scene/Scene.h"
#include "scene/components/AudioVolumeComponent.h"
+#include "../../popups/ResourceSelectionPopup.h"
+
namespace Atlas::Editor::UI {
class AudioVolumeComponentPanel : public Panel {
@@ -14,6 +16,9 @@ namespace Atlas::Editor::UI {
bool Render(Ref& scene, Scene::Entity entity, AudioVolumeComponent& audioVolumeComponent);
+ private:
+ ResourceSelectionPopup audioSelectionPopup;
+
};
}
diff --git a/src/editor/ui/panels/components/CameraComponentPanel.cpp b/src/editor/ui/panels/components/CameraComponentPanel.cpp
index d0e8463dd..dda85c129 100644
--- a/src/editor/ui/panels/components/CameraComponentPanel.cpp
+++ b/src/editor/ui/panels/components/CameraComponentPanel.cpp
@@ -9,7 +9,7 @@ namespace Atlas::Editor::UI {
ImGui::Text("Transform");
ImGui::DragFloat3("Position", glm::value_ptr(cameraComponent.location), 0.1f, -10000.0f, 10000.0f);
- ImGui::DragFloat2("Rotation", glm::value_ptr(cameraComponent.rotation), 0.01f, -glm::pi() / 2.0f, glm::pi() / 2.0f);
+ ImGui::DragFloat2("Rotation", glm::value_ptr(cameraComponent.rotation), 0.01f, -glm::pi(), glm::pi());
ImGui::Checkbox("Use entity translation", &cameraComponent.useEntityTranslation);
ImGui::Checkbox("Use entity rotation", &cameraComponent.useEntityRotation);
diff --git a/src/editor/ui/panels/components/LightComponentPanel.cpp b/src/editor/ui/panels/components/LightComponentPanel.cpp
index 39aec7814..b7514e717 100644
--- a/src/editor/ui/panels/components/LightComponentPanel.cpp
+++ b/src/editor/ui/panels/components/LightComponentPanel.cpp
@@ -79,6 +79,7 @@ namespace Atlas::Editor::UI {
ImGui::DragFloat("Bias", &shadow->bias, 0.05f, 0.0f, 10.0f);
ImGui::DragFloat("Distance", &shadow->distance, 1.0f, 0.0f, 10000.0f);
+ ImGui::DragFloat("Edge softness", &shadow->edgeSoftness, 0.005f, 0.0f, 1.0f);
ImGui::Separator();
@@ -106,7 +107,7 @@ namespace Atlas::Editor::UI {
auto matrix = glm::ortho(-200.0f, 200.0f, -200.0f, 200.0f, -120.0f, 120.0f);
lightComponent.AddDirectionalShadow(shadow->distance, shadow->bias, shadow->resolution,
- shadow->center, orthoSize);
+ shadow->edgeSoftness, shadow->center, orthoSize);
}
else {
ImGui::SliderInt("Cascade count", &shadow->viewCount, 1, 5);
@@ -114,7 +115,7 @@ namespace Atlas::Editor::UI {
ImGui::Checkbox("Long range", &shadow->longRange);
ImGui::DragFloat("Long range distance", &shadow->longRangeDistance, 10.0f, 10.0f, 10000.0f);
- lightComponent.AddDirectionalShadow(shadow->distance, shadow->bias, shadow->resolution,
+ lightComponent.AddDirectionalShadow(shadow->distance, shadow->bias, shadow->resolution, shadow->edgeSoftness,
shadow->viewCount, shadow->splitCorrection, shadow->longRange, shadow->longRangeDistance);
}
}
diff --git a/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp
new file mode 100644
index 000000000..0d78df670
--- /dev/null
+++ b/src/editor/ui/panels/components/LuaScriptComponentPanel.cpp
@@ -0,0 +1,60 @@
+#include "LuaScriptComponentPanel.h"
+
+#include "../../../tools/ResourcePayloadHelper.h"
+
+#include "imgui_stdlib.h"
+
+namespace Atlas::Editor::UI
+{
+ bool LuaScriptComponentPanel::Render(Ref& scene, Scene::Entity entity, LuaScriptComponent &luaScriptComponent)
+ {
+ auto buttonName = luaScriptComponent.script.IsValid() ? luaScriptComponent.script.GetResource()->GetFileName() : "Drop script resource here";
+ if (ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0}))
+ scriptSelectionPopup.Open();
+
+ // Such that drag and drop will work from the content browser
+ if (ImGui::IsDragDropActive() && ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ ImGui::SetItemDefaultFocus();
+ }
+
+ auto handle = ResourcePayloadHelper::AcceptDropResource();
+
+ auto scriptResources = ResourceManager::GetResources();
+ handle = scriptSelectionPopup.Render(scriptResources);
+
+ if (handle.IsValid()) {
+ // Needs to be implemented
+ // luaScriptComponent.ChangeResource(handle);
+ luaScriptComponent.script = handle;
+ }
+
+ if (!luaScriptComponent.script.IsLoaded())
+ return false;
+
+ ImGui::InputTextMultiline("Code", &luaScriptComponent.script->code, ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
+
+ ImGui::Separator();
+ ImGui::Text("Script defined properties:");
+ for (auto &property : luaScriptComponent.properties)
+ {
+ switch (property.type)
+ {
+ case LuaScriptComponent::PropertyType::Boolean:
+ ImGui::Checkbox(property.name.c_str(), &property.booleanValue);
+ break;
+ case LuaScriptComponent::PropertyType::Integer:
+ ImGui::InputInt(property.name.c_str(), &property.integerValue);
+ break;
+ case LuaScriptComponent::PropertyType::Double:
+ ImGui::InputDouble(property.name.c_str(), &property.doubleValue);
+ break;
+ case LuaScriptComponent::PropertyType::String:
+ ImGui::InputText(property.name.c_str(), &property.stringValue);
+ break;
+ }
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/editor/ui/panels/components/LuaScriptComponentPanel.h b/src/editor/ui/panels/components/LuaScriptComponentPanel.h
new file mode 100644
index 000000000..3ffb9478f
--- /dev/null
+++ b/src/editor/ui/panels/components/LuaScriptComponentPanel.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "../Panel.h"
+
+#include "scene/components/LuaScriptComponent.h"
+#include "../../popups/ResourceSelectionPopup.h"
+
+namespace Atlas::Editor::UI
+{
+
+ class LuaScriptComponentPanel : public Panel {
+
+ public:
+ LuaScriptComponentPanel() : Panel("Lua script component") {}
+
+ bool Render(Ref& scene, Scene::Entity entity, LuaScriptComponent &luaScriptComponent);
+
+ private:
+ ResourceSelectionPopup scriptSelectionPopup;
+
+ };
+
+}
\ No newline at end of file
diff --git a/src/editor/ui/panels/components/MeshComponentPanel.cpp b/src/editor/ui/panels/components/MeshComponentPanel.cpp
index c8e5b6410..fd853b726 100644
--- a/src/editor/ui/panels/components/MeshComponentPanel.cpp
+++ b/src/editor/ui/panels/components/MeshComponentPanel.cpp
@@ -14,9 +14,20 @@ namespace Atlas::Editor::UI {
auto buttonName = meshComponent.mesh.IsValid() ? meshComponent.mesh.GetResource()->GetFileName() :
"Drop mesh resource here";
- ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0});
+ if (ImGui::Button(buttonName.c_str(), {-FLT_MIN, 0}))
+ meshSelectionPopup.Open();
+
+ // Such that drag and drop will work from the content browser
+ if (ImGui::IsDragDropActive() && ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ ImGui::SetItemDefaultFocus();
+ }
auto handle = ResourcePayloadHelper::AcceptDropResource();
+
+ auto meshResources = ResourceManager::GetResources();
+ handle = meshSelectionPopup.Render(meshResources);
+
if (handle.IsValid()) {
meshComponent.mesh = handle;
resourceChanged = true;
@@ -29,6 +40,12 @@ namespace Atlas::Editor::UI {
auto& mesh = meshComponent.mesh;
ImGui::Separator();
ImGui::Text("Mesh settings");
+
+ const char* mobilityItems[] = { "Stationary", "Movable" };
+ int mobilityItem = static_cast(mesh->mobility);
+ ImGui::Combo("Mobility", &mobilityItem, mobilityItems, IM_ARRAYSIZE(mobilityItems));
+ mesh->mobility = static_cast(mobilityItem);
+
ImGui::Checkbox("Invert UVs", &mesh->invertUVs);
ImGui::Checkbox("Cull backfaces", &mesh->cullBackFaces);
ImGui::Separator();
diff --git a/src/editor/ui/panels/components/MeshComponentPanel.h b/src/editor/ui/panels/components/MeshComponentPanel.h
index c154de55b..6e5b2b730 100644
--- a/src/editor/ui/panels/components/MeshComponentPanel.h
+++ b/src/editor/ui/panels/components/MeshComponentPanel.h
@@ -6,6 +6,7 @@
#include "scene/Entity.h"
#include "scene/components/MeshComponent.h"
+#include "../../popups/ResourceSelectionPopup.h"
#include "ImguiExtension/panels/MaterialsPanel.h"
namespace Atlas::Editor::UI {
@@ -19,6 +20,7 @@ namespace Atlas::Editor::UI {
private:
ImguiExtension::MaterialsPanel materialsPanel;
+ ResourceSelectionPopup meshSelectionPopup;
};
diff --git a/src/editor/ui/panels/components/TransformComponentPanel.cpp b/src/editor/ui/panels/components/TransformComponentPanel.cpp
index 6cf63f5e3..bdd4c378f 100644
--- a/src/editor/ui/panels/components/TransformComponentPanel.cpp
+++ b/src/editor/ui/panels/components/TransformComponentPanel.cpp
@@ -11,7 +11,8 @@ namespace Atlas::Editor::UI {
// Make sure the local matrix is updated from the global one
// This needs to happen when external system like physics just updated the globalMatrix
- transform.ReconstructLocalMatrix(scene);
+ auto parentEntity = scene->GetParentEntity(entity);
+ transform.ReconstructLocalMatrix(parentEntity);
// The matrix decomposition/composition code is a bit unstable and
// we work with fixed information that is recomposed when changed,
diff --git a/src/editor/ui/popups/Popup.h b/src/editor/ui/popups/Popup.h
new file mode 100644
index 000000000..018ee3f5f
--- /dev/null
+++ b/src/editor/ui/popups/Popup.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+#include
+
+namespace Atlas::Editor::UI {
+
+ class Popup {
+
+ public:
+ Popup(const std::string& name) : name(name), nameID(name + "##" + std::to_string(ID)) {}
+
+ const char* GetNameID() const { return nameID.c_str(); }
+
+ void Open() { ImGui::OpenPopup(GetNameID()); }
+
+ std::string name;
+
+ protected:
+ int32_t ID = GetID();
+
+ std::string nameID;
+
+ private:
+ static int32_t GetID() {
+
+ static int32_t counter = 0;
+ return counter++;
+
+ }
+
+ };
+
+}
\ No newline at end of file
diff --git a/src/editor/ui/popups/ResourceSelectionPopup.cpp b/src/editor/ui/popups/ResourceSelectionPopup.cpp
new file mode 100644
index 000000000..feb066b23
--- /dev/null
+++ b/src/editor/ui/popups/ResourceSelectionPopup.cpp
@@ -0,0 +1,7 @@
+#include "ResourceSelectionPopup.h"
+
+namespace Atlas::Editor::UI {
+
+
+
+}
\ No newline at end of file
diff --git a/src/editor/ui/popups/ResourceSelectionPopup.h b/src/editor/ui/popups/ResourceSelectionPopup.h
new file mode 100644
index 000000000..8c88f75ec
--- /dev/null
+++ b/src/editor/ui/popups/ResourceSelectionPopup.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "Popup.h"
+
+#include "resource/Resource.h"
+
+#include
+#include
+
+namespace Atlas::Editor::UI {
+
+ class ResourceSelectionPopup : public Popup {
+
+ public:
+ ResourceSelectionPopup() : Popup("ResourceSelection") {}
+
+ template
+ ResourceHandle Render(std::vector> resources) {
+
+ ResourceHandle handle;
+
+ ImGui::SetNextWindowSize(ImVec2(-FLT_MAX, 200.0f));
+
+ if (ImGui::BeginPopup(GetNameID())) {
+
+ ImGui::InputTextWithHint("Search", "Type to search for loaded resource", &resourceSearch);
+
+ ImGui::BeginChild("Resource list");
+
+ resources = ApplySearchAndSortFiltering(resources);
+
+ for (size_t i = 0; i < resources.size(); i++) {
+ bool isSelected = false;
+ const auto& resource = resources[i].GetResource();
+
+ auto itemName = resource->GetFileName();
+
+ ImGui::Selectable(itemName.c_str(), &isSelected, ImGuiSelectableFlags_SpanAvailWidth);
+
+ if (isSelected)
+ handle = resources[i];
+ }
+
+ ImGui::EndChild();
+
+ if (handle.IsValid())
+ ImGui::CloseCurrentPopup();
+
+ ImGui::EndPopup();
+
+ }
+
+ return handle;
+
+ }
+
+ private:
+ template
+ std::vector> ApplySearchAndSortFiltering(const std::vector>& resources) {
+
+ std::vector> filteredResources;
+
+ if (!resourceSearch.empty()) {
+ std::string searchQuery = resourceSearch;
+ std::transform(searchQuery.begin(), searchQuery.end(), searchQuery.begin(), ::tolower);
+
+ for (const auto& handle : resources) {
+ auto filename = handle.GetResource()->GetFileName();
+ std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower);
+
+ // Filter out by search query, if it is a valid (non-empty) query
+ if (searchQuery.empty() || filename.find(searchQuery) != std::string::npos)
+ filteredResources.push_back(handle);
+ }
+ }
+ else {
+ filteredResources = resources;
+ }
+
+ std::sort(filteredResources.begin(), filteredResources.end(),
+ [](const ResourceHandle& res0, const ResourceHandle& res1) {
+ auto res0Filename = res0.GetResource()->GetFileName();
+ auto res1Filename = res1.GetResource()->GetFileName();
+
+ return res0Filename < res1Filename;
+ });
+
+ return filteredResources;
+
+ }
+
+ std::string resourceSearch;
+
+ };
+
+}
\ No newline at end of file
diff --git a/src/editor/ui/windows/ContentBrowserWindow.cpp b/src/editor/ui/windows/ContentBrowserWindow.cpp
index cb48c06e6..2245e277f 100644
--- a/src/editor/ui/windows/ContentBrowserWindow.cpp
+++ b/src/editor/ui/windows/ContentBrowserWindow.cpp
@@ -1,5 +1,7 @@
#include "ContentBrowserWindow.h"
#include "FileImporter.h"
+#include "DataCreator.h"
+#include "ui/panels/PopupPanels.h"
#include "mesh/Mesh.h"
#include "scene/Scene.h"
@@ -16,7 +18,7 @@
namespace Atlas::Editor::UI {
- ContentBrowserWindow::ContentBrowserWindow(bool show) : Window("Object browser", show) {
+ ContentBrowserWindow::ContentBrowserWindow(bool show) : Window("Content browser", show) {
@@ -57,8 +59,14 @@ namespace Atlas::Editor::UI {
End();
ImGui::Begin("ResourceTypeSelection", nullptr);
- ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen |
- ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed;
+
+ ImGui::SetWindowFontScale(1.5f);
+
+ ImGui::Text("Filters");
+
+ ImGui::SetWindowFontScale(1.0f);
+
+ ImGui::Separator();
const char *items[] = {"Audio", "Mesh", "Terrain", "Scene", "Script", "Font", "Prefab"};
for (int i = 0; i < IM_ARRAYSIZE(items); i++) {
@@ -87,6 +95,10 @@ namespace Atlas::Editor::UI {
ImGui::EndChild();
+ if (ImGui::IsDragDropActive() && ImGui::IsWindowHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ }
+
if (ImGui::BeginDragDropTarget()) {
auto dropPayload = ImGui::GetDragDropPayload();
if (ImGui::AcceptDragDropPayload(typeid(Scene::Entity).name())) {
@@ -101,16 +113,23 @@ namespace Atlas::Editor::UI {
// There must be a scene, otherwise we want to get a fatal error
auto iter = std::find_if(scenes.begin(), scenes.end(),
- [&](const ResourceHandle& item) -> bool { return item->name == scene->name; });
+ [&](const ResourceHandle& item) -> bool {
+ if (!item.IsLoaded())
+ return false;
+ return item->name == scene->name;
+ });
auto sceneHandle = *iter;
auto nameComponent = entity.TryGetComponent();
auto entityName = nameComponent ? nameComponent->name : "Entity " + std::to_string(entity);
auto assetDirectory = Loader::AssetLoader::GetAssetDirectory();
- auto assetPath = Common::Path::GetRelative(assetDirectory, currentDirectory);
+ auto assetPath = Common::Path::GetRelative(assetDirectory, currentDirectory) + "/";
+ if (assetPath.starts_with('/'))
+ assetPath.erase(assetPath.begin());
+
auto entityPath = assetPath + entityName + ".aeprefab";
- Scene::SceneSerializer::SerializePrefab(sceneHandle.Get(), entity, entityPath);
+ Serializer::SerializePrefab(sceneHandle.Get(), entity, entityPath);
}
}
@@ -230,17 +249,33 @@ namespace Atlas::Editor::UI {
}
if (!isDirectory && ImGui::BeginDragDropSource()) {
- ImGui::SetDragDropPayload("ContentBrowserResource", assetRelativePath.c_str(), assetRelativePath.size());
+ ImGui::SetDragDropPayload("ContentBrowserResource", assetRelativePath.c_str(), assetRelativePath.length());
ImGui::Text("Drag to entity component");
ImGui::EndDragDropSource();
}
if (ImGui::BeginPopupContextItem()) {
+ // Do a direct import here without relying on the file importer
+ if (type == FileType::Mesh && ImGui::MenuItem("Import as scene")) {
+ PopupPanels::filename = assetRelativePath;
+ PopupPanels::isImportScenePopupVisible = true;
+ }
+
// We shouldn't allow the user to delete the root entity
if (ImGui::MenuItem("Open externally"))
OpenExternally(std::filesystem::absolute(dirEntry.path()).string(), isDirectory);
+ if (ImGui::MenuItem("Rename")) {
+ renamePopupVisible = true;
+ auto dirEntryFilename = dirEntry.path().filename();
+ renameString = dirEntryFilename.replace_extension("").string();
+ renameDirEntry = dirEntry;
+ }
+
+ if (ImGui::MenuItem("Delete"))
+ std::filesystem::remove(dirEntry.path());
+
ImGui::EndPopup();
}
@@ -264,6 +299,28 @@ namespace Atlas::Editor::UI {
}
+ if (ImGui::BeginPopupContextWindow(nullptr, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight)) {
+ if (ImGui::BeginMenu("Create")) {
+ if (ImGui::MenuItem("Folder")) {
+
+ }
+ if (ImGui::MenuItem("Script")) {
+
+ }
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndPopup();
+ }
+
+ if (TextInputPopup("Rename item", renamePopupVisible, renameString)) {
+ auto newPath = renameDirEntry.path();
+ newPath = newPath.filename().replace_filename(renameString);
+ if (renameDirEntry.path().has_extension())
+ newPath = newPath.replace_extension(renameDirEntry.path().extension());
+ std::filesystem::rename(renameDirEntry.path(), newPath);
+ }
+
if (!nextDirectory.empty()) {
currentDirectory = nextDirectory;
}
@@ -379,4 +436,48 @@ namespace Atlas::Editor::UI {
}
+ bool ContentBrowserWindow::TextInputPopup(const char* name, bool& isVisible, std::string& input) {
+
+ if (!isVisible)
+ return false;
+
+ PopupPanels::SetupPopupSize(0.4f, 0.1f);
+
+ bool popupNew = false;
+
+ if (!ImGui::IsPopupOpen(name)) {
+ popupNew = true;
+ ImGui::OpenPopup(name);
+ }
+
+ bool success = false;
+
+ if (ImGui::BeginPopupModal(name, nullptr, ImGuiWindowFlags_NoResize)) {
+
+ if (popupNew)
+ ImGui::SetKeyboardFocusHere();
+
+ ImGui::InputText("New name", &input);
+
+ if (ImGui::Button("Cancel")) {
+ isVisible = false;
+ ImGui::CloseCurrentPopup();
+ }
+
+ ImGui::SameLine();
+
+ if (ImGui::Button("Ok") || ImGui::IsKeyReleased(ImGuiKey_Enter)) {
+ success = true;
+ isVisible = false;
+ ImGui::CloseCurrentPopup();
+ }
+
+ ImGui::EndPopup();
+
+ }
+
+ return success;
+
+ }
+
}
\ No newline at end of file
diff --git a/src/editor/ui/windows/ContentBrowserWindow.h b/src/editor/ui/windows/ContentBrowserWindow.h
index 3cd61ccfe..423d7eee3 100644
--- a/src/editor/ui/windows/ContentBrowserWindow.h
+++ b/src/editor/ui/windows/ContentBrowserWindow.h
@@ -33,11 +33,17 @@ namespace Atlas::Editor::UI {
void OpenExternally(const std::string& path, bool isDirectory);
+ bool TextInputPopup(const char* name, bool& isVisible, std::string& input);
+
int selectedFilter = -1;
std::string currentDirectory = Loader::AssetLoader::GetAssetDirectory();
std::string assetSearch;
+ std::string renameString;
+ std::filesystem::directory_entry renameDirEntry;
+ bool renamePopupVisible = false;
+
};
}
\ No newline at end of file
diff --git a/src/editor/ui/windows/GeometryBrushWindow.cpp b/src/editor/ui/windows/GeometryBrushWindow.cpp
index 86e5a0c67..f4425fcf0 100644
--- a/src/editor/ui/windows/GeometryBrushWindow.cpp
+++ b/src/editor/ui/windows/GeometryBrushWindow.cpp
@@ -10,7 +10,7 @@ namespace Atlas::Editor::UI {
if (!Begin())
return;
- std::string buttonName = "Drop entity here";
+ std::string buttonName = "Drop entity with transform component here";
if (brushEntity.IsValid() && brushEntity.HasComponent())
buttonName = brushEntity.GetComponent().name;
@@ -22,8 +22,6 @@ namespace Atlas::Editor::UI {
if (dropPayload->IsDataType(typeid(Scene::Entity).name())) {
std::memcpy(&dropEntity, dropPayload->Data, dropPayload->DataSize);
bool validEntity = dropEntity.HasComponent();
- if (!validEntity)
- Notifications::Push({.message = "Entity needs to have a transform component"});
if (validEntity && ImGui::AcceptDragDropPayload(typeid(Scene::Entity).name())) {
brushEntity = dropEntity;
@@ -52,7 +50,9 @@ namespace Atlas::Editor::UI {
ImGui::EndDragDropTarget();
}
- if (brushEntity.IsValid() && parentEntity.IsValid()) {
+ if (brushEntity.IsValid() && parentEntity.IsValid() && activeSceneWindow != nullptr
+ && activeSceneWindow->scene.Get().get() == brushEntity.GetScene()
+ && activeSceneWindow->scene.Get().get() == parentEntity.GetScene()) {
RenderBrushSettings();
if (brushEnabled) {
@@ -88,7 +88,7 @@ namespace Atlas::Editor::UI {
ImGui::Separator();
ImGui::Text("Drop randomization");
-
+
}
@@ -160,6 +160,8 @@ namespace Atlas::Editor::UI {
if (!parentEntity.HasComponent())
parentEntity.AddComponent();
+ auto decomposition = brushEntity.GetComponent().Decompose();
+
for (int32_t i = 0; i < dropsPerFrame; i++) {
auto deg = Common::Random::SampleFastUniformFloat() * 2.0f * 3.14159f;
auto dist = Common::Random::SampleFastUniformFloat() + Common::Random::SampleFastUniformFloat();
@@ -172,19 +174,23 @@ namespace Atlas::Editor::UI {
Atlas::Volume::Ray ray(pos + dropTarget.normal * brushRayLength, -dropTarget.normal);
auto rayCastResult = scene->CastRay(ray);
- if (!rayCastResult.valid || !rayCastResult.IsNormalValid() || rayCastResult.hitDistance > 2.0f * brushRayLength)
+ if (!rayCastResult.valid || !rayCastResult.IsNormalValid() || rayCastResult.hitDistance > 2.0f * brushRayLength) {
return;
+ }
mat4 rot { 1.0f };
if (brushAlignToSurface) {
- vec3 normal = rayCastResult.normal;
- vec3 tangent = vec3(1.0f, 0.0f, 0.0f);
- vec3 bitangent = normalize(cross(tangent, normal));
- rot = mat4(mat3(tangent, normal, bitangent));
+ vec3 N = rayCastResult.normal;
+ vec3 up = abs(N.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
+ vec3 tangent = normalize(cross(up, N));
+ vec3 bitangent = cross(N, tangent);
+
+ rot = mat4(mat3(tangent, N, bitangent));
}
- auto transform = glm::translate(ray.Get(rayCastResult.hitDistance)) * rot;
+ decomposition.translation = ray.Get(rayCastResult.hitDistance);
+ auto transform = decomposition.Compose() * rot;
auto entity = scene->DuplicateEntity(brushEntity);
auto& transformComponent = entity.GetComponent();
@@ -194,7 +200,7 @@ namespace Atlas::Editor::UI {
// Ray cast result is in global space, so need to bring transform to valid local one
transformComponent.globalMatrix = transform;
- transformComponent.ReconstructLocalMatrix(activeSceneWindow->scene.Get());
+ transformComponent.ReconstructLocalMatrix(parentEntity);
}
}
diff --git a/src/editor/ui/windows/ProfilerWindow.cpp b/src/editor/ui/windows/ProfilerWindow.cpp
index 5d301a445..b0f5cadae 100644
--- a/src/editor/ui/windows/ProfilerWindow.cpp
+++ b/src/editor/ui/windows/ProfilerWindow.cpp
@@ -1,5 +1,7 @@
#include "ProfilerWindow.h"
+#include "Clock.h"
+
namespace Atlas::Editor::UI {
void ProfilerWindow::Render() {
@@ -7,6 +9,12 @@ namespace Atlas::Editor::UI {
if (!Begin())
return;
+ ImGui::Text("Total frame time: %f ms", Clock::GetAverage() * 1000.0f);
+
+ ImGui::Separator();
+
+ ImGui::Text("GPU time table");
+
gpuProfilerPanel.Render();
End();
diff --git a/src/editor/ui/windows/SceneWindow.cpp b/src/editor/ui/windows/SceneWindow.cpp
index b14c8c83c..9ee020ddf 100644
--- a/src/editor/ui/windows/SceneWindow.cpp
+++ b/src/editor/ui/windows/SceneWindow.cpp
@@ -1,8 +1,10 @@
#include "SceneWindow.h"
#include "../../Singletons.h"
+#include "../../Notifications.h"
#include "../../tools/ResourcePayloadHelper.h"
-#include "scene/SceneSerializer.h"
+#include "Serializer.h"
+#include "common/Hash.h"
#include "Clock.h"
#include
@@ -22,12 +24,7 @@ namespace Atlas::Editor::UI {
SceneWindow::~SceneWindow() {
- if (!scene.IsLoaded())
- return;
-
- scene->DestroyEntity(cameraEntity);
-
- Scene::SceneSerializer::SerializeScene(scene.Get(), "scenes/" + std::string(scene->name) + ".aescene");
+
}
@@ -42,14 +39,27 @@ namespace Atlas::Editor::UI {
camera.isMain = true;
}
- auto& camera = cameraEntity.GetComponent();
- camera.aspectRatio = float(viewportPanel.viewport->width) / std::max(float(viewportPanel.viewport->height), 1.0f);
-
// If we're playing we can update here since we don't expect values to change from the UI side
if (isPlaying) {
scene->Timestep(deltaTime);
scene->Update();
}
+ else {
+ auto& camera = cameraEntity.GetComponent();
+ camera.aspectRatio = float(viewportPanel.viewport->width) / std::max(float(viewportPanel.viewport->height), 1.0f);
+ }
+
+ bool controlDown;
+
+#ifdef AE_OS_MACOS
+ controlDown = ImGui::IsKeyDown(ImGuiKey_LeftSuper);
+#else
+ controlDown = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
+#endif
+ if (inFocus && controlDown && ImGui::IsKeyPressed(ImGuiKey_S, false) && !isPlaying) {
+ SaveScene();
+ Notifications::Push({ .message = "Saved scene " + scene->name });
+ }
}
@@ -58,6 +68,10 @@ namespace Atlas::Editor::UI {
if (!Begin())
return;
+ if (ImGui::IsDragDropActive() && ImGui::IsWindowHovered(ImGuiHoveredFlags_RectOnly)) {
+ ImGui::SetWindowFocus();
+ }
+
ImGuiID dsID = ImGui::GetID(dockSpaceNameID.c_str());
if (!ImGui::DockBuilderGetNode(dsID) || resetDockingLayout) {
@@ -130,6 +144,9 @@ namespace Atlas::Editor::UI {
comp.isMain = false;
}
+ // Path tracing needs history while ray tracing
+ scene->rayTracingWorld->includeObjectHistory = Singletons::config->pathTrace;
+
scene->Timestep(Clock::GetDelta());
scene->Update();
@@ -149,7 +166,7 @@ namespace Atlas::Editor::UI {
auto path = ResourcePayloadHelper::AcceptDropResourceAndGetPath();
if (!path.empty()) {
- auto entity = Scene::SceneSerializer::DeserializePrefab(scene.Get(), path);
+ auto entity = Serializer::DeserializePrefab(scene.Get(), path);
PushEntityIntoSceneHierarchy(entity);
}
@@ -213,19 +230,8 @@ namespace Atlas::Editor::UI {
auto offset = region.x / 2.0f - buttonSize.x - padding;
ImGui::SetCursorPos(ImVec2(offset, 0.0f));
- if (ImGui::ImageButton(set, buttonSize, uvMin, uvMax) && scene.IsLoaded()) {
- if (hasMainCamera) {
- auto& camera = cameraEntity.GetComponent();
- camera.isMain = false;
- }
-
- scene->physicsWorld->SaveState();
- scene->physicsWorld->pauseSimulation = false;
- // Unselect when starting the simulation/scene (otherwise some physics settings might not
- // be reverted after stopping
- sceneHierarchyPanel.selectedEntity = Scene::Entity();
-
- isPlaying = true;
+ if (ImGui::ImageButton(set, buttonSize, uvMin, uvMax) && scene.IsLoaded() && !isPlaying) {
+ StartPlaying();
}
auto& stopIcon = Singletons::icons->Get(IconType::Stop);
@@ -234,14 +240,7 @@ namespace Atlas::Editor::UI {
offset = region.x / 2.0f + padding;
ImGui::SetCursorPos(ImVec2(offset, 0.0f));
if (ImGui::ImageButton(set, buttonSize, uvMin, uvMax) && scene.IsLoaded() && isPlaying) {
- // Set camera to main in any case
- auto& camera = cameraEntity.GetComponent();
- camera.isMain = true;
-
- scene->physicsWorld->RestoreState();
- scene->physicsWorld->pauseSimulation = true;
-
- isPlaying = false;
+ StopPlaying();
}
auto& settingsIcon = Singletons::icons->Get(IconType::Settings);
@@ -265,6 +264,7 @@ namespace Atlas::Editor::UI {
ImGui::Text("Editor camera");
+ ImGui::DragFloat("Exposure", &camera.exposure, 0.1f, 1.0f, 180.0f);
ImGui::DragFloat("Field of view", &camera.fieldOfView, 0.1f, 1.0f, 180.0f);
ImGui::DragFloat("Near plane", &camera.nearPlane, 0.01f, 0.01f, 10.0f);
@@ -311,18 +311,31 @@ namespace Atlas::Editor::UI {
if (selectedEntity.IsValid() && selectedEntity.HasComponent()) {
auto& transform = selectedEntity.GetComponent();
+ auto mesh = selectedEntity.TryGetComponent();
+
+ auto globalDecomp = Common::MatrixDecomposition(transform.globalMatrix);
- auto globalMatrix = transform.globalMatrix;
+ glm::vec3 offset = vec3(0.0f);
+ if (mesh)
+ offset = (0.5f * (mesh->aabb.min + mesh->aabb.max)) - globalDecomp.translation;
+
+ globalDecomp.translation += offset;
+ auto globalMatrix = globalDecomp.Compose();
ImGuizmo::Manipulate(glm::value_ptr(vMatrix), glm::value_ptr(pMatrix),
static_cast(guizmoMode), ImGuizmo::MODE::WORLD,
glm::value_ptr(globalMatrix));
+ globalDecomp = Common::MatrixDecomposition(globalMatrix);
+ globalDecomp.translation -= offset;
+
// Update both the local and global matrix, since e.g. the transform component
// panel recovers the local matrix from the global one (needs to do this after
// e.g. physics only updated the global matrix
- transform.globalMatrix = globalMatrix;
- transform.ReconstructLocalMatrix(scene.Get());
+ transform.globalMatrix = globalDecomp.Compose();
+
+ auto parentEntity = scene->GetParentEntity(selectedEntity);
+ transform.ReconstructLocalMatrix(parentEntity);
}
const auto& io = ImGui::GetIO();
@@ -409,8 +422,14 @@ namespace Atlas::Editor::UI {
if (!parentEntity.HasComponent())
parentEntity.AddComponent();
- auto& hierarchy = parentEntity.GetComponent();
- hierarchy.AddChild(entity);
+ auto& parentHierarchy = parentEntity.GetComponent();
+ parentHierarchy.AddChild(entity);
+
+ // We don't know where this entity came from, so disable root hierarchy in any case to
+ // avoid setting the matrices twice and getting unwanted movements
+ auto hierarchy = entity.TryGetComponent();
+ if (hierarchy)
+ hierarchy->root = false;
if (changeSelection) {
sceneHierarchyPanel.selectedEntity = entity;
@@ -418,4 +437,67 @@ namespace Atlas::Editor::UI {
}
}
+ void SceneWindow::StartPlaying() {
+
+ SaveSceneState();
+
+ scene->physicsWorld->pauseSimulation = false;
+ // Unselect when starting the simulation/scene (otherwise some physics settings might not
+ // be reverted after stopping
+ sceneHierarchyPanel.selectedEntity = Scene::Entity();
+
+ isPlaying = true;
+
+ }
+
+ void SceneWindow::StopPlaying() {
+
+ RestoreSceneState();
+
+ isPlaying = false;
+
+ }
+
+ void SceneWindow::SaveSceneState() {
+
+ cameraState = Scene::Entity::Backup(scene.Get(), cameraEntity);
+
+ scene->DestroyEntity(cameraEntity);
+
+ sceneState = Scene::Scene::Backup(scene.Get());
+
+ }
+
+ void SceneWindow::RestoreSceneState() {
+
+ if (sceneState.empty())
+ return;
+
+ auto backupScene = Scene::Scene::Restore(sceneState);
+ scene.GetResource()->Swap(backupScene);
+
+ cameraEntity = Scene::Entity::Restore(scene.Get(), cameraState);
+
+ sceneState.clear();
+ cameraState.clear();
+
+ }
+
+ void SceneWindow::SaveScene() {
+
+ if (!scene.IsLoaded())
+ return;
+
+ cameraState = Scene::Entity::Backup(scene.Get(), cameraEntity);
+
+ scene->DestroyEntity(cameraEntity);
+
+ Serializer::SerializeScene(scene.Get(), "scenes/" + std::string(scene->name) + ".aescene");
+
+ cameraEntity = Scene::Entity::Restore(scene.Get(), cameraState);
+
+ cameraState.clear();
+
+ }
+
}
diff --git a/src/editor/ui/windows/SceneWindow.h b/src/editor/ui/windows/SceneWindow.h
index c04dc8fe7..5cac55363 100644
--- a/src/editor/ui/windows/SceneWindow.h
+++ b/src/editor/ui/windows/SceneWindow.h
@@ -28,6 +28,16 @@ namespace Atlas::Editor::UI {
void PushEntityIntoSceneHierarchy(Scene::Entity entity, bool changeSelection = true);
+ void StartPlaying();
+
+ void StopPlaying();
+
+ void SaveSceneState();
+
+ void RestoreSceneState();
+
+ void SaveScene();
+
SceneHierarchyPanel sceneHierarchyPanel;
ViewportPanel viewportPanel;
ScenePropertiesPanel scenePropertiesPanel;
@@ -52,6 +62,9 @@ namespace Atlas::Editor::UI {
private:
void RenderEntityBoundingVolumes(Scene::Entity entity);
+ std::vector sceneState;
+ std::vector cameraState;
+
};
}
\ No newline at end of file
diff --git a/src/editor/ui/windows/Window.cpp b/src/editor/ui/windows/Window.cpp
index 528f3167a..01a6718bc 100644
--- a/src/editor/ui/windows/Window.cpp
+++ b/src/editor/ui/windows/Window.cpp
@@ -1,5 +1,9 @@
#include "Window.h"
+#include
+
+#include
+
namespace Atlas::Editor::UI {
bool Window::Begin(ImGuiWindowFlags flags) {
diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt
index bafa7e31c..f85926788 100644
--- a/src/engine/CMakeLists.txt
+++ b/src/engine/CMakeLists.txt
@@ -24,12 +24,13 @@ endif()
# Set built type macros ###########################################################################
if (DEFINED CMAKE_BUILD_TYPE)
+ # We want the better/safer usertypes, such that we don't crash everything
if(CMAKE_BUILD_TYPE STREQUAL "Release")
- set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_RELEASE)
+ set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_RELEASE SOL_ALL_SAFETIES_ON)
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
- set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_RELWITHDEBINFO)
+ set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_RELWITHDEBINFO SOL_ALL_SAFETIES_ON)
else()
- set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_DEBUG)
+ set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_DEBUG SOL_ALL_SAFETIES_ON)
endif()
else()
set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_BUILDTYPE_RELEASE)
@@ -40,8 +41,9 @@ if(WIN32)
set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_OS_WINDOWS)
set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SPIRV-Tools-opt
- volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator fsr2
- unofficial::spirv-reflect::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt)
+ volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator
+ unofficial::spirv-reflect::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt
+ ${LUA_LIBRARIES} sol2 fsr2)
endif()
if (MINGW)
@@ -54,15 +56,16 @@ if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED")
set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static
- volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt
+ volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt fsr2
GPUOpen::VulkanMemoryAllocator Vulkan::Vulkan Vulkan::Headers
- unofficial::spirv-reflect::spirv-reflect glslang::SPIRV fsr2)
+ unofficial::spirv-reflect::spirv-reflect glslang::SPIRV ${LUA_LIBRARIES} sol2)
endif()
if(ANDROID)
set(ATLAS_ENGINE_COMPILE_DEFINITIONS ${ATLAS_ENGINE_COMPILE_DEFINITIONS} AE_OS_ANDROID)
- set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static hidapi)
+ set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static hidapi
+ ${LUA_LIBRARIES} sol2 fsr2)
set(ATLAS_ENGINE_SYSTEM_LIBS android m)
endif()
@@ -77,9 +80,14 @@ if(UNIX AND NOT APPLE AND NOT ANDROID)
set(CMAKE_INSTALL_RPATH "./")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
- set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static
+ set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static fsr2
volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt
- unofficial::spirv-reflect::spirv-reflect SPIRV-Tools-opt glslang::SPIRV fsr2)
+ unofficial::spirv-reflect::spirv-reflect SPIRV-Tools-opt glslang::SPIRV ${LUA_LIBRARIES} sol2)
+endif()
+
+# Due to lua bindings we need more addressable functions (but not for clang)
+if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ add_compile_options(/bigobj)
endif()
# Add source files ################################################################################
@@ -145,6 +153,7 @@ target_include_directories(${PROJECT_NAME}
${VULKAN_HEADERS_INCLUDE_DIRS}
${STB_INCLUDE_DIRS}
${GLM_INCLUDE_DIRS}
+ ${LUA_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../libs)
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index d6e02a5fd..d3eb2dba9 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -7,6 +7,7 @@
#include "pipeline/PipelineManager.h"
#include "physics/PhysicsManager.h"
#include "texture/Texture.h"
+#include "input/KeyboardMap.h"
#include "graphics/ShaderCompiler.h"
@@ -71,6 +72,7 @@ namespace Atlas {
Common::Random::Init();
PipelineManager::Init();
Physics::PhysicsManager::Init();
+ Input::KeyboardMap::Init();
// We need lower sample size for smaller buffer on SDL side (e.g. 256 instead of 1024)
Audio::AudioManager::Configure(48000, 2, 128);
@@ -87,6 +89,7 @@ namespace Atlas {
Physics::PhysicsManager::Shutdown();
Texture::Texture::Shutdown();
Audio::AudioManager::Shutdown();
+ Input::KeyboardMap::Shutdown();
#ifdef AE_NO_APP
SDL_Quit();
@@ -100,6 +103,7 @@ namespace Atlas {
Events::EventManager::Update();
PipelineManager::Update();
Audio::AudioManager::Update();
+ Physics::ShapesManager::Update();
}
@@ -112,4 +116,4 @@ namespace Atlas {
}
-}
\ No newline at end of file
+}
diff --git a/src/engine/Main.cpp b/src/engine/Main.cpp
index 1a59f0a6b..fa273f94b 100644
--- a/src/engine/Main.cpp
+++ b/src/engine/Main.cpp
@@ -32,8 +32,6 @@ int main(int argc, char* argv[]) {
setenv("MVK_DEBUG", "0", 1);
#endif
- // SetEnvironmentVariable("VK_ICD_FILENAMES", "C:\\Users\\tippe\\Documents\\Repos\\swiftshader\\build\\Windows\\vk_swiftshader_icd.json");
-
Atlas::Engine::Init(Atlas::EngineInstance::engineConfig);
auto graphicsInstance = Atlas::Graphics::Instance::DefaultInstance;
diff --git a/src/engine/RenderList.cpp b/src/engine/RenderList.cpp
index 63067376d..b60103f74 100644
--- a/src/engine/RenderList.cpp
+++ b/src/engine/RenderList.cpp
@@ -30,9 +30,20 @@ namespace Atlas {
impostorMatrices.clear();
if (lastSize) impostorMatrices.reserve(lastSize);
+ // Fill in missing meshes since they are cleared at the end of each frame
+ auto meshes = scene->GetMeshes();
+ for (auto& pass : passes) {
+ for (const auto& mesh : meshes) {
+ auto id = mesh.GetID();
+ pass->meshIdToMeshMap[id] = mesh;
+ }
+
+ std::erase_if(pass->meshToEntityMap, [pass](const auto& item) { return !pass->meshIdToMeshMap.contains(item.first); });
+ std::erase_if(pass->meshToInstancesMap, [pass](const auto& item) { return !pass->meshIdToMeshMap.contains(item.first); });
+ }
}
- void RenderList::NewMainPass() {
+ Ref RenderList::NewMainPass() {
Pass pass {
.type = RenderPassType::Main,
@@ -40,90 +51,94 @@ namespace Atlas {
.layer = 0
};
- passes.push_back(pass);
+ passes.push_back(CreateRef(pass));
+ return passes.back();
}
- void RenderList::NewShadowPass(ECS::Entity lightEntity, uint32_t layer) {
+ Ref RenderList::NewShadowPass(ECS::Entity lightEntity, uint32_t layer) {
- Pass pass {
+ Pass pass{
.type = RenderPassType::Shadow,
.lightEntity = lightEntity,
- .layer = layer
+ .layer = layer,
+ .wasUsed = true
};
- passes.push_back(pass);
+ passes.push_back(CreateRef(pass));
+ return passes.back();
}
-
- RenderList::Pass* RenderList::GetMainPass() {
+ Ref RenderList::GetMainPass() {
for (auto& pass : passes) {
- if (pass.type == RenderPassType::Main) return &pass;
+ if (pass->type == RenderPassType::Main) return pass;
}
return nullptr;
}
- RenderList::Pass* RenderList::GetShadowPass(ECS::Entity lightEntity, const uint32_t layer) {
+ Ref RenderList::GetShadowPass(ECS::Entity lightEntity, const uint32_t layer) {
for (auto& pass : passes) {
- if (pass.type == RenderPassType::Shadow &&
- pass.lightEntity == lightEntity && pass.layer == layer) return &pass;
+ if (pass->type == RenderPassType::Shadow &&
+ pass->lightEntity == lightEntity && pass->layer == layer) return pass;
}
return nullptr;
}
- void RenderList::Add(const ECS::Entity& entity, const MeshComponent& meshComponent) {
+ void RenderList::Add(const Ref& pass, const ECS::Entity& entity, const MeshComponent& meshComponent) {
- auto& pass = passes.back();
- auto& meshToActorMap = pass.meshToEntityMap;
+ auto& meshToActorMap = pass->meshToEntityMap;
if (!meshComponent.mesh.IsLoaded())
return;
auto id = meshComponent.mesh.GetID();
- if (!meshToActorMap.contains(id)) {
- auto& meshIdToMeshMap = pass.meshIdToMeshMap;
-
- meshToActorMap[id] = { entity };
- meshIdToMeshMap[id] = meshComponent.mesh;
+ auto item = meshToActorMap.find(id);
+ if (item != meshToActorMap.end()) {
+ item->second.Add(entity);
}
else {
- meshToActorMap[id].push_back(entity);
+ auto& meshIdToMeshMap = pass->meshIdToMeshMap;
+
+ EntityBatch batch;
+ batch.Add(entity);
+
+ meshToActorMap[id] = batch;
+ meshIdToMeshMap[id] = meshComponent.mesh;
}
}
- void RenderList::Update(vec3 cameraLocation) {
+ void RenderList::Update(const Ref& pass, vec3 cameraLocation) {
- auto& pass = passes.back();
- auto type = pass.type;
- auto& meshToActorMap = pass.meshToEntityMap;
- auto& meshToInstancesMap = pass.meshToInstancesMap;
- auto& meshIdToMeshMap = pass.meshIdToMeshMap;
+ auto type = pass->type;
+ auto& meshToEntityMap = pass->meshToEntityMap;
+ auto& meshToInstancesMap = pass->meshToInstancesMap;
+ auto& meshIdToMeshMap = pass->meshIdToMeshMap;
size_t maxActorCount = 0;
size_t maxImpostorCount = 0;
- for (auto& [meshId, actors] : meshToActorMap) {
+ for (auto& [meshId, batch] : meshToEntityMap) {
auto mesh = meshIdToMeshMap[meshId];
if (!mesh->castShadow && type == RenderPassType::Shadow)
continue;
auto hasImpostor = mesh->impostor != nullptr;
- maxActorCount += actors.size();
- maxImpostorCount += hasImpostor ? actors.size() : 0;
+ maxActorCount += batch.count;
+ maxImpostorCount += hasImpostor ? batch.count : 0;
}
- for (auto& [meshId, entities] : meshToActorMap) {
+ for (auto& [meshId, batch] : meshToEntityMap) {
auto mesh = meshIdToMeshMap[meshId];
- if (!entities.size()) continue;
+ if (!batch.count) continue;
if (!mesh->castShadow && type == RenderPassType::Shadow) continue;
auto hasImpostor = mesh->impostor != nullptr;
@@ -140,7 +155,8 @@ namespace Atlas {
instances.impostorOffset = impostorMatrices.size();
if (hasImpostor) {
- for (auto ecsEntity : entities) {
+ for (size_t i = 0; i < batch.count; i++) {
+ auto& ecsEntity = batch.entities[i];
auto entity = Scene::Entity(ecsEntity, &scene->entityManager);
auto& transformComponent = entity.GetComponent();
auto distance = glm::distance2(
@@ -154,7 +170,7 @@ namespace Atlas {
}
else {
// For now push back anyways (since indices of matrices per entity need to match)
- lastEntityMatrices.push_back(glm::transpose(transformComponent.globalMatrix));
+ lastEntityMatrices.push_back(currentEntityMatrices.back());
}
}
else {
@@ -163,7 +179,8 @@ namespace Atlas {
}
}
else {
- for (auto ecsEntity : entities) {
+ for (size_t i = 0; i < batch.count; i++) {
+ auto& ecsEntity = batch.entities[i];
auto entity = Scene::Entity(ecsEntity, &scene->entityManager);
auto& transformComponent = entity.GetComponent();
currentEntityMatrices.push_back(glm::transpose(transformComponent.globalMatrix));
@@ -172,7 +189,7 @@ namespace Atlas {
}
else {
// For now push back anyways
- lastEntityMatrices.push_back(glm::transpose(transformComponent.globalMatrix));
+ lastEntityMatrices.push_back(currentEntityMatrices.back());
}
}
}
@@ -229,7 +246,9 @@ namespace Atlas {
// We can reset the scene now and delete the reference
scene = nullptr;
- passes.clear();
+ std::erase_if(passes, [](const auto& item) { return item->wasUsed != true; });
+ for (auto& pass : passes)
+ pass->Reset();
}
diff --git a/src/engine/RenderList.h b/src/engine/RenderList.h
index 815488d2e..d82d077ce 100644
--- a/src/engine/RenderList.h
+++ b/src/engine/RenderList.h
@@ -7,7 +7,7 @@
#include "graphics/Buffer.h"
-#include