├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── export_presets.cfg ├── icon.png ├── icon.png.import ├── post_process ├── blur-post-process_mat.tres ├── dither-banding_mat.tres ├── lcd-overlay_mat.tres └── pp_stack.tscn ├── project.godot ├── readme-assets ├── .gdignore └── screenshot.png ├── shaders ├── lcd_post_process.gdshader ├── post_process_blur.gdshader ├── pp_band-dither.gdshader ├── psx_base.gdshaderinc ├── psx_light-volume.gdshader ├── psx_lit.gdshader ├── psx_lit_alpha-scissor.gdshader ├── psx_lit_metal.gdshader ├── psx_lit_transparent.gdshader ├── psx_unlit.gdshader ├── psx_unlit_alpha-scissor.gdshader ├── psx_unlit_metal.gdshader ├── psx_unlit_transparent.gdshader ├── psxdither.png └── psxdither.png.import └── world ├── box_lit ├── box-lit_mat.tres ├── box.obj └── box.obj.import ├── box_metal ├── bevel-box.obj ├── bevel-box.obj.import ├── box-metal_mat.tres ├── metal-tex.png └── metal-tex.png.import ├── crystal ├── crystal.gltf ├── crystal.gltf.import ├── crystal_ground_mat.tres ├── crystal_mesh.tscn └── crystal_spire_mat.tres ├── floor ├── floor.png ├── floor.png.import └── floor.tres ├── light-shaft ├── light-shaft.glb ├── light-shaft.glb.import ├── light-shaft_mat.tres └── light-shaft_mesh.res ├── orbit_camera.gd ├── scene_controls.gd ├── shadow ├── shadow.gd ├── shadow.png ├── shadow.png.import ├── shadow.tscn └── shadow_mat.tres ├── sparkle ├── sparkle.png ├── sparkle.png.import ├── sparkle_mat.tres └── sparkle_particle-process_mat.tres ├── spatial_sin_pan.gd ├── world.tscn └── world_env.tres /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | export-builds: 10 | runs-on: ubuntu-latest 11 | name: Export Builds 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v2.3.1 15 | with: 16 | fetch-depth: 0 17 | - name: export game 18 | uses: firebelley/godot-export@v4.7.0 19 | with: 20 | godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0/Godot_v4.0-stable_linux.x86_64.zip 21 | godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0/Godot_v4.0-stable_export_templates.tpz 22 | relative_project_path: ./ 23 | create_release: false 24 | use_preset_export_path: true 25 | use_godot_4: true 26 | - name: upload linux artifact 27 | uses: actions/upload-artifact@v3 28 | with: 29 | name: linux 30 | path: build/x11/* 31 | - name: upload windows artifact 32 | uses: actions/upload-artifact@v3 33 | with: 34 | name: windows 35 | path: build/win/* 36 | - name: upload html5 artifact 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: html5 40 | path: build/html5/* 41 | 42 | deploy-itch: 43 | if: github.repository == 'MenacingMecha/godot-psx-style-demo' 44 | needs: [export-builds] 45 | runs-on: ubuntu-latest 46 | strategy: 47 | fail-fast: true 48 | matrix: 49 | channel: 50 | - linux 51 | - windows 52 | - html5 53 | name: Deploy -> itch.io:${{matrix.channel}} 54 | env: 55 | ITCH_USERNAME: MenacingMecha 56 | ITCH_GAME_ID: godot-psx-style-demo 57 | steps: 58 | - uses: actions/download-artifact@v3.0.0 59 | with: 60 | name: ${{matrix.channel}} 61 | - uses: KikimoraGames/itch-publish@v0.0.3 62 | with: 63 | butlerApiKey: ${{secrets.BUTLER_CREDENTIALS}} 64 | gameData: ./ 65 | itchUsername: ${{env.ITCH_USERNAME}} 66 | itchGameId: ${{env.ITCH_GAME_ID}} 67 | buildChannel: v2.x_${{matrix.channel}} 68 | buildNumber: ${{github.ref_name}} 69 | 70 | create-release-page: 71 | runs-on: ubuntu-latest 72 | name: Create Release Page 73 | permissions: 74 | contents: write 75 | steps: 76 | - name: Create release page 77 | uses: softprops/action-gh-release@v0.1.14 78 | with: 79 | token: ${{secrets.GITHUB_TOKEN}} 80 | draft: true 81 | generate_release_notes: true 82 | 83 | add-release-artifacts: 84 | needs: [export-builds, create-release-page] 85 | runs-on: ubuntu-latest 86 | name: Add Release Artifact -> ${{matrix.channel}} 87 | strategy: 88 | fail-fast: true 89 | matrix: 90 | channel: 91 | - linux 92 | - windows 93 | - html5 94 | permissions: 95 | contents: write 96 | env: 97 | ARTIFACT_FILENAME: ${{github.event.repository.name}}_${{matrix.channel}}_${{github.ref_name}}.zip 98 | steps: 99 | - name: Download artifact 100 | uses: actions/download-artifact@v3.0.0 101 | with: 102 | name: ${{matrix.channel}} 103 | - name: Archive release artifact 104 | uses: thedoctor0/zip-release@main 105 | with: 106 | filename: ${{env.ARTIFACT_FILENAME}} 107 | - name: Upload release artifact to release page 108 | uses: softprops/action-gh-release@v0.1.14 109 | with: 110 | token: ${{secrets.GITHUB_TOKEN}} 111 | fail_on_unmatched_files: true 112 | files: ${{env.ARTIFACT_FILENAME}} 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,godot 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,godot 5 | 6 | ### Godot ### 7 | 8 | # Godot-specific ignores 9 | .import/ 10 | .godot/ 11 | export.cfg 12 | export_presets.cfg 13 | 14 | # Imported translations (automatically generated from CSV files) 15 | *.translation 16 | 17 | # Mono-specific ignores 18 | .mono/ 19 | data_*/ 20 | 21 | ### Linux ### 22 | *~ 23 | 24 | # temporary files which can be created if a process still has a handle open of a deleted file 25 | .fuse_hidden* 26 | 27 | # KDE directory preferences 28 | .directory 29 | 30 | # Linux trash folder which might appear on any partition or disk 31 | .Trash-* 32 | 33 | # .nfs files are created when an open file is removed but is still being accessed 34 | .nfs* 35 | 36 | ### VisualStudioCode ### 37 | .vscode/* 38 | *.code-workspace 39 | 40 | ### VisualStudioCode Patch ### 41 | # Ignore all local history of files 42 | .history 43 | 44 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,godot 45 | 46 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 47 | 48 | !export_presets.cfg 49 | build/* 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MenacingMecha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Godot PSX Style Demo 2 | 3 | [Play demo in browser!](https://menacingmecha.itch.io/godot-psx-style-demo) 4 | 5 | ![Example Screenshot](./readme-assets/screenshot.png) 6 | 7 | A collection of shaders and materials for Godot engine that aim to recreate the following aspects of the PS1 aesthetic: 8 | 9 | - Vertex "snapping" 10 | - "Wobbly" texures through affine texture mapping 11 | - Limited color depth 12 | - Hardware dithering to hide color banding 13 | - Shiny chrome-like metallic surfaces 14 | - Billboard sprites 15 | - Fog to limit draw distance 16 | 17 | Originally based on: https://github.com/marmitoTH/godot-psx-shaders 18 | 19 | Floor texture (available under CC-0): https://stealthix.itch.io/rpg-nature-tileset 20 | 21 | ## Design Goals 22 | These shaders are focused on having as few parameters as possible to achieve the desired effect of recreating (most of) the PS1's rendering quirks. 23 | This is to aid accessibility by way of reducing the amount of things the user has to understand and configure. 24 | 25 | However, this is at the cost of customizability; there are fewer parameters to highly tweak how the shaders look versus other projects. 26 | 27 | ## Demo Controls 28 | 29 | - Space: Toggle camera and object movement 30 | - R: Reset scene 31 | 32 | ## Usage 33 | ### Brand new projects 34 | For brand new projects, I would reccomend duplicating this project and playing around with things from there. 35 | 36 | ### Existing projects 37 | 1. Add the contents of `shaders/` to your project. 38 | 2. Add the `precision_multiplier` as a `float` shader global in Project Settings, ensuring it's value is minimum 0 (non-inclusive), and maximum 1 (inclusive). 39 | 4. Configure a Dither/Banding viewport shader, using the demo project as reference. 40 | 41 | ## Tips for best results 42 | 43 | - Use very low poly models 44 | - Prefer smooth-shading over flat-shading wherever possible 45 | - Don't be afraid to include extra edge loops to smooth out texture distortion in your geometry! PS1 levels often had much higher polycounts than you might expect! 46 | - Keep textures as low resolution as you can 47 | - Make sure filtering and mip-maps are both disabled 48 | - Rely on a mix of vertex colours and texture maps, instead of higher detailed texture maps wherever possible 49 | - Posterizing your textures with a depth of 15 or 16 before import goes a long way to making them feel more "PS1" 50 | - Keep your internal resolution low 51 | - Common PS1 resolutions were 256×240, 320x240 and 512x240 ([Source](https://docs.google.com/spreadsheets/d/1UgysgrgqbiIlyHIiwCxVoWMu1bwgO2OBlDO1ORpsi78/edit?usp=sharing)) 52 | - That being said, you can easily go widescreen by using a 16:9 resolution with similar height 53 | - Use as basic of a lighting set up as you can get away with 54 | - Modern lighting techniques are a very easy way to break the illusion of appearing like early 3D! 55 | - Where possible, prefer to use white ambient light, with vertex colours on geometry to fake lighting 56 | - Prefer additive blending to transparent blending 57 | 58 | ## Changes from v1.x 59 | 60 | ### Major version change 61 | This version is for Godot 4.x only. 62 | Please refer to the v1.x branch for Godot 3.x support. 63 | 64 | ### Fog 65 | 66 | Godot 4.0 changed how environmental fog worked, the key part being the removal of the "start distance" and "end distance" properties. 67 | While a manual workaround could be implemented, there is work being done to restore this functionality in a later version. 68 | 69 | ### Runtime options 70 | 71 | In order to release working Godot 4 shaders as soon as possible, runtime options for the demo will be re-implemented at a later date. 72 | 73 | ## Games using these shaders (in some form) 74 | - [Isle of Dreamers](https://menacingmecha.itch.io/isle-of-dreamers) - [MenacingMecha](https://menacingmecha.github.io/) 75 | - [Inktober 2020 Demo Disc](https://menacingmecha.itch.io/inktober-2020-demo-disc) - [MenacingMecha](https://menacingmecha.github.io/) 76 | - [Please Don't Feed the Creatures of the Deep](https://vaporshark.itch.io/please-dont-feed-the-creatures-of-the-deep) - [VaporShark](https://vaporshark.itch.io/) 77 | - [Headlines from the Deep](https://menacingmecha.itch.io/headlines-from-the-deep) - [MenacingMecha](https://menacingmecha.github.io/) 78 | - [Beetlebum](https://menacingmecha.itch.io/beetlebum) - [MenacingMecha](https://menacingmecha.github.io/) 79 | - [P.O.S.S.U.M.](https://vaporshark.itch.io/possum) - [VaporShark](https://vaporshark.itch.io/) 80 | - [The Deep Ones](https://bronxtaco.itch.io/the-deep-ones) - [bronxtaco](https://bronxtaco.itch.io/) 81 | 82 | Please submit a PR (or send a message) if you have a title to add! 83 | -------------------------------------------------------------------------------- /export_presets.cfg: -------------------------------------------------------------------------------- 1 | [preset.0] 2 | 3 | name="Linux/X11" 4 | platform="Linux/X11" 5 | runnable=true 6 | dedicated_server=false 7 | custom_features="" 8 | export_filter="all_resources" 9 | include_filter="" 10 | exclude_filter="build/*, build.sh, README.md, *.gif, readme-assets/*" 11 | export_path="build/x11/psx-style-demo.x86_64" 12 | encryption_include_filters="" 13 | encryption_exclude_filters="" 14 | encrypt_pck=false 15 | encrypt_directory=false 16 | script_encryption_key="" 17 | 18 | [preset.0.options] 19 | 20 | custom_template/debug="" 21 | custom_template/release="" 22 | debug/export_console_script=1 23 | binary_format/embed_pck=false 24 | texture_format/bptc=false 25 | texture_format/s3tc=true 26 | texture_format/etc=false 27 | texture_format/etc2=false 28 | binary_format/architecture="x86_64" 29 | ssh_remote_deploy/enabled=false 30 | ssh_remote_deploy/host="user@host_ip" 31 | ssh_remote_deploy/port="22" 32 | ssh_remote_deploy/extra_args_ssh="" 33 | ssh_remote_deploy/extra_args_scp="" 34 | ssh_remote_deploy/run_script="#!/usr/bin/env bash 35 | export DISPLAY=:0 36 | unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" 37 | \"{temp_dir}/{exe_name}\" {cmd_args}" 38 | ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash 39 | kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") 40 | rm -rf \"{temp_dir}\"" 41 | 42 | [preset.1] 43 | 44 | name="Windows Desktop" 45 | platform="Windows Desktop" 46 | runnable=true 47 | dedicated_server=false 48 | custom_features="" 49 | export_filter="all_resources" 50 | include_filter="" 51 | exclude_filter="build/*, build.sh, README.md, *.gif, readme-assets/*" 52 | export_path="build/win/psx-style-demo.exe" 53 | encryption_include_filters="" 54 | encryption_exclude_filters="" 55 | encrypt_pck=false 56 | encrypt_directory=false 57 | script_encryption_key="" 58 | 59 | [preset.1.options] 60 | 61 | custom_template/debug="" 62 | custom_template/release="" 63 | debug/export_console_script=1 64 | binary_format/embed_pck=false 65 | texture_format/bptc=false 66 | texture_format/s3tc=true 67 | texture_format/etc=false 68 | texture_format/etc2=false 69 | binary_format/architecture="x86_64" 70 | codesign/enable=false 71 | codesign/identity_type=0 72 | codesign/identity="" 73 | codesign/password="" 74 | codesign/timestamp=true 75 | codesign/timestamp_server_url="" 76 | codesign/digest_algorithm=1 77 | codesign/description="" 78 | codesign/custom_options=PackedStringArray() 79 | application/modify_resources=true 80 | application/icon="" 81 | application/console_wrapper_icon="" 82 | application/icon_interpolation=4 83 | application/file_version="" 84 | application/product_version="" 85 | application/company_name="" 86 | application/product_name="" 87 | application/file_description="" 88 | application/copyright="" 89 | application/trademarks="" 90 | ssh_remote_deploy/enabled=false 91 | ssh_remote_deploy/host="user@host_ip" 92 | ssh_remote_deploy/port="22" 93 | ssh_remote_deploy/extra_args_ssh="" 94 | ssh_remote_deploy/extra_args_scp="" 95 | ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' 96 | $action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' 97 | $trigger = New-ScheduledTaskTrigger -Once -At 00:00 98 | $settings = New-ScheduledTaskSettingsSet 99 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings 100 | Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true 101 | Start-ScheduledTask -TaskName godot_remote_debug 102 | while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } 103 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" 104 | ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue 105 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue 106 | Remove-Item -Recurse -Force '{temp_dir}'" 107 | 108 | [preset.2] 109 | 110 | name="Web" 111 | platform="Web" 112 | runnable=true 113 | dedicated_server=false 114 | custom_features="" 115 | export_filter="all_resources" 116 | include_filter="" 117 | exclude_filter="build/*, build.sh, README.md, *.gif, readme-assets/*" 118 | export_path="build/html5/index.html" 119 | encryption_include_filters="" 120 | encryption_exclude_filters="" 121 | encrypt_pck=false 122 | encrypt_directory=false 123 | script_encryption_key="" 124 | 125 | [preset.2.options] 126 | 127 | custom_template/debug="" 128 | custom_template/release="" 129 | variant/extensions_support=false 130 | vram_texture_compression/for_desktop=true 131 | vram_texture_compression/for_mobile=false 132 | html/export_icon=true 133 | html/custom_html_shell="" 134 | html/head_include="" 135 | html/canvas_resize_policy=2 136 | html/focus_canvas_on_start=true 137 | html/experimental_virtual_keyboard=false 138 | progressive_web_app/enabled=false 139 | progressive_web_app/offline_page="" 140 | progressive_web_app/display=1 141 | progressive_web_app/orientation=0 142 | progressive_web_app/icon_144x144="" 143 | progressive_web_app/icon_180x180="" 144 | progressive_web_app/icon_512x512="" 145 | progressive_web_app/background_color=Color(0, 0, 0, 1) 146 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/icon.png -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b2o6eugnb81a6" 6 | path.s3tc="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://icon.png" 15 | dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /post_process/blur-post-process_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://b6irksunrvdek"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/post_process_blur.gdshader" id="1_00lvw"] 4 | 5 | [resource] 6 | shader = ExtResource("1_00lvw") 7 | shader_parameter/blur_scale = Vector2(0.35, 0.35) 8 | shader_parameter/blur_samples = 20.0 9 | shader_parameter/blur_brightness = 1.5 10 | shader_parameter/enabled = false 11 | -------------------------------------------------------------------------------- /post_process/dither-banding_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://dr52yj2jvqaa7"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/pp_band-dither.gdshader" id="1_lqq5h"] 4 | [ext_resource type="Texture2D" uid="uid://b0ub3tqjyw46f" path="res://shaders/psxdither.png" id="2_6of7q"] 5 | 6 | [resource] 7 | shader = ExtResource("1_lqq5h") 8 | shader_parameter/col_depth = 15.0 9 | shader_parameter/dither_banding = true 10 | shader_parameter/dither_tex = ExtResource("2_6of7q") 11 | -------------------------------------------------------------------------------- /post_process/lcd-overlay_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://bni0eo5gi5ho4"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/lcd_post_process.gdshader" id="1_b6j3k"] 4 | 5 | [resource] 6 | shader = ExtResource("1_b6j3k") 7 | shader_parameter/enabled = false 8 | shader_parameter/lcd_opacity = 0.5 9 | shader_parameter/scanline_gap = 4 10 | -------------------------------------------------------------------------------- /post_process/pp_stack.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://cs8d3xn2towo"] 2 | 3 | [ext_resource type="Material" uid="uid://b6irksunrvdek" path="res://post_process/blur-post-process_mat.tres" id="1_3emcg"] 4 | [ext_resource type="Material" uid="uid://bni0eo5gi5ho4" path="res://post_process/lcd-overlay_mat.tres" id="2_0v7s0"] 5 | [ext_resource type="Shader" path="res://shaders/pp_band-dither.gdshader" id="3_rkbcs"] 6 | [ext_resource type="Texture2D" uid="uid://b0ub3tqjyw46f" path="res://shaders/psxdither.png" id="4_05ih0"] 7 | [ext_resource type="PackedScene" uid="uid://c1xno4bm2dlyj" path="res://world/world.tscn" id="5_i4o5h"] 8 | 9 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_m5nvn"] 10 | render_priority = 0 11 | shader = ExtResource("3_rkbcs") 12 | shader_parameter/col_depth = 15.0 13 | shader_parameter/dither_banding = true 14 | shader_parameter/dither_tex = ExtResource("4_05ih0") 15 | 16 | [node name="Node" type="Node"] 17 | 18 | [node name="PSXLayer" type="CanvasLayer" parent="."] 19 | layer = 0 20 | 21 | [node name="BlurPostProcess" type="SubViewportContainer" parent="PSXLayer"] 22 | material = ExtResource("1_3emcg") 23 | anchors_preset = 15 24 | anchor_right = 1.0 25 | anchor_bottom = 1.0 26 | mouse_filter = 2 27 | 28 | [node name="Viewport" type="SubViewport" parent="PSXLayer/BlurPostProcess"] 29 | handle_input_locally = false 30 | canvas_item_default_texture_filter = 0 31 | audio_listener_enable_2d = true 32 | audio_listener_enable_3d = true 33 | size = Vector2i(960, 720) 34 | render_target_update_mode = 4 35 | 36 | [node name="LCDOverlay" type="SubViewportContainer" parent="PSXLayer/BlurPostProcess/Viewport"] 37 | material = ExtResource("2_0v7s0") 38 | anchors_preset = 15 39 | anchor_right = 1.0 40 | anchor_bottom = 1.0 41 | mouse_filter = 2 42 | stretch = true 43 | 44 | [node name="Viewport" type="SubViewport" parent="PSXLayer/BlurPostProcess/Viewport/LCDOverlay"] 45 | handle_input_locally = false 46 | canvas_item_default_texture_filter = 0 47 | audio_listener_enable_2d = true 48 | audio_listener_enable_3d = true 49 | size = Vector2i(960, 720) 50 | render_target_update_mode = 4 51 | 52 | [node name="DitherBanding" type="SubViewportContainer" parent="PSXLayer/BlurPostProcess/Viewport/LCDOverlay/Viewport"] 53 | material = SubResource("ShaderMaterial_m5nvn") 54 | anchors_preset = 15 55 | anchor_right = 1.0 56 | anchor_bottom = 1.0 57 | mouse_filter = 2 58 | stretch = true 59 | stretch_shrink = 3 60 | 61 | [node name="Viewport" type="SubViewport" parent="PSXLayer/BlurPostProcess/Viewport/LCDOverlay/Viewport/DitherBanding"] 62 | handle_input_locally = false 63 | canvas_item_default_texture_filter = 0 64 | audio_listener_enable_2d = true 65 | audio_listener_enable_3d = true 66 | size = Vector2i(320, 240) 67 | render_target_update_mode = 4 68 | 69 | [node name="World" parent="PSXLayer/BlurPostProcess/Viewport/LCDOverlay/Viewport/DitherBanding/Viewport" instance=ExtResource("5_i4o5h")] 70 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="Godot PSX Style Demo" 14 | config/description="Demo project featuring a collection of PS1 style shaders and materials for Godot engine. 15 | (MIT License) 16 | https://github.com/MenacingMecha/godot-psx-style-demo/" 17 | run/main_scene="res://post_process/pp_stack.tscn" 18 | config/features=PackedStringArray("4.0") 19 | run/max_fps=24 20 | config/icon="res://readme-assets/screenshot.png" 21 | 22 | [display] 23 | 24 | window/size/viewport_width=960 25 | window/size/viewport_height=720 26 | window/size/resizable=false 27 | window/vsync/vsync_mode=0 28 | window/stretch/mode="viewport" 29 | window/size/width=960 30 | window/size/height=720 31 | 32 | [input] 33 | 34 | kb_1={ 35 | "deadzone": 0.5, 36 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":49,"physical_keycode":0,"key_label":0,"unicode":49,"echo":false,"script":null) 37 | ] 38 | } 39 | kb_2={ 40 | "deadzone": 0.5, 41 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":50,"physical_keycode":0,"key_label":0,"unicode":50,"echo":false,"script":null) 42 | ] 43 | } 44 | reset_camera_position={ 45 | "deadzone": 0.5, 46 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":114,"echo":false,"script":null) 47 | ] 48 | } 49 | 50 | [rendering] 51 | 52 | vram_compression/import_etc=true 53 | vram_compression/import_etc2=false 54 | quality/reflections/high_quality_ggx=false 55 | quality/shading/force_vertex_shading=true 56 | quality/shading/force_lambert_over_burley=true 57 | quality/shading/force_blinn_over_ggx=true 58 | quality/filters/anisotropic_filter_level=1 59 | quality/subsurface_scattering/quality=0 60 | quality/subsurface_scattering/weight_samples=false 61 | 62 | [shader_globals] 63 | 64 | precision_multiplier={ 65 | "type": "float", 66 | "value": 1.0 67 | } 68 | -------------------------------------------------------------------------------- /readme-assets/.gdignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/readme-assets/.gdignore -------------------------------------------------------------------------------- /readme-assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/readme-assets/screenshot.png -------------------------------------------------------------------------------- /shaders/lcd_post_process.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | #pragma disable_preprocessor 3 | 4 | uniform bool enabled = true; 5 | uniform float lcd_opacity = 0.5; 6 | uniform int scanline_gap = 5; 7 | 8 | // http://theorangeduck.com/page/avoiding-shader-conditionals 9 | float when_eq(int x, int y) 10 | { 11 | return 1.0 - abs(sign(float(x) - float(y))); 12 | } 13 | 14 | vec4 lcdColor(int pos_x, int pos_y) 15 | { 16 | vec4 lcdColor = vec4(1); 17 | // Change every 1st, 2nd, and 3rd vertical strip to RGB respectively 18 | // if (px == 1) lcdColor.r = 1.0; 19 | // else if (px == 2) lcdColor.g = 1.0; 20 | // else lcdColor.b = 1.0; 21 | lcdColor.r = lcdColor.r * when_eq(pos_x, 0); 22 | lcdColor.g = lcdColor.g * when_eq(pos_x, 1); 23 | lcdColor.b = lcdColor.b * when_eq(pos_x, 2); 24 | 25 | // Darken every 3rd horizontal strip for scanline 26 | // if (int(mod(FRAGCOORD.y,3.0)) == 0) lcdColor.rgb = vec3(0); 27 | lcdColor.rgb = lcdColor.rgb * vec3(1.0 - when_eq(pos_y, 0)); 28 | 29 | return lcdColor; 30 | } 31 | 32 | void fragment() 33 | { 34 | vec4 tex = texture(TEXTURE,UV); 35 | int pos_x = int(mod(FRAGCOORD.x, 3.0)); 36 | int pos_y = int(mod(FRAGCOORD.y, float(scanline_gap))); 37 | vec4 lcd_overlay_tex = lcdColor(pos_x, pos_y); 38 | COLOR = enabled ? mix(tex, tex * lcd_overlay_tex, lcd_opacity) : tex; 39 | } 40 | -------------------------------------------------------------------------------- /shaders/post_process_blur.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | #pragma disable_preprocessor 3 | 4 | uniform vec2 blur_scale = vec2(0.5, 0.5); 5 | uniform float blur_samples = 50.0; 6 | uniform float blur_brightness = 1.65; 7 | uniform bool enabled = true; 8 | 9 | const float PI2 = 6.283185307179586476925286766559; 10 | 11 | // 2-pass gaussian blur based on https://github.com/GDQuest/godot-shaders/blob/master/godot/Shaders/gaussian_blur.shader 12 | // TODO: change to this algorithm https://github.com/GDQuest/godot-shaders/blob/master/godot/Shaders/gaussian_blur_optimized.shader 13 | float gaussian(float x) 14 | { 15 | float x_squared = x*x; 16 | float width = 1.0 / sqrt(PI2 * blur_samples); 17 | 18 | return width * exp((x_squared / (2.0 * blur_samples)) * -1.0); 19 | } 20 | 21 | vec4 gaussian_blur_pass(vec2 texture_pixel_size, sampler2D texture, vec2 uv, float _blur_samples) 22 | { 23 | float weight = 0.0; 24 | float total_weight = 0.0; 25 | vec2 scale_horiz = texture_pixel_size * vec2(blur_scale.x, 0.0); 26 | vec4 color_horiz = vec4(0.0); 27 | 28 | for(int i=-int(_blur_samples)/2; i < int(_blur_samples)/2; ++i) { 29 | weight = gaussian(float(i)); 30 | color_horiz += texture(texture, uv + scale_horiz * vec2(float(i))) * weight; 31 | total_weight += weight; 32 | } 33 | 34 | weight = 0.0; 35 | total_weight = 0.0; 36 | vec2 scale_vert = texture_pixel_size * vec2(0.0, blur_scale.y); 37 | vec4 color_vert = vec4(0.0); 38 | 39 | for(int i=-int(_blur_samples)/2; i < int(_blur_samples)/2; ++i) { 40 | weight = gaussian(float(i)); 41 | color_vert += texture(texture, uv + scale_vert * vec2(float(i))) * weight; 42 | total_weight += weight; 43 | } 44 | 45 | vec4 blur_horiz = color_horiz / total_weight; 46 | vec4 blur_vert = color_vert / total_weight; 47 | vec4 blur = mix(color_horiz, color_vert, 0.5); 48 | return blur; 49 | } 50 | 51 | void fragment() 52 | { 53 | COLOR = enabled ? gaussian_blur_pass(TEXTURE_PIXEL_SIZE, TEXTURE, UV, blur_samples) * blur_brightness : texture(TEXTURE, UV); 54 | } 55 | -------------------------------------------------------------------------------- /shaders/pp_band-dither.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | #pragma disable_preprocessor 3 | // originally based on https://github.com/WittyCognomen/godot-psx-shaders-demo/blob/master/shaders/psx_dither_post.shader 4 | 5 | uniform sampler2D dither_tex: hint_default_white, repeat_enable, filter_nearest; 6 | uniform float col_depth = 15.0; 7 | uniform bool dither_banding = true; 8 | 9 | void fragment() { 10 | vec4 base_color = texture(TEXTURE, SCREEN_UV); 11 | vec2 dith_size = vec2(textureSize(dither_tex, 0)); // for GLES2: substitute for the dimensions of the dithering matrix 12 | vec2 buf_size = vec2(textureSize(TEXTURE, 0)); 13 | vec3 dith = texture(dither_tex, SCREEN_UV * (buf_size / dith_size)).rgb - 0.5; 14 | COLOR.rgb = round(base_color.rgb * col_depth + dith * (dither_banding ? 1.0 : 0.0)) / col_depth; 15 | } 16 | -------------------------------------------------------------------------------- /shaders/psx_base.gdshaderinc: -------------------------------------------------------------------------------- 1 | render_mode LIT, CULL, shadows_disabled, DEPTH, BLEND, specular_disabled; 2 | 3 | global uniform float precision_multiplier : hint_range(0.0, 1.0) = 1.0; 4 | uniform vec4 modulate_color : source_color = vec4(1.0); 5 | 6 | #ifndef NO_TEXTURE 7 | uniform sampler2D albedoTex : source_color, filter_nearest, repeat_enable; 8 | #endif 9 | 10 | #if !defined(NO_TEXTURE) && !defined(METAL) // METAL doesn't use UV, so no need for panning properties 11 | uniform vec2 uv_scale = vec2(1.0, 1.0); 12 | uniform vec2 uv_offset = vec2(.0, .0); 13 | uniform vec2 uv_pan_velocity = vec2(0.0); 14 | #endif 15 | 16 | #ifdef ALPHA_SCISSOR 17 | uniform bool billboard = false; 18 | uniform bool y_billboard = false; 19 | uniform float alpha_scissor : hint_range(0, 1) = 0.1; 20 | #endif 21 | 22 | // https://github.com/dsoft20/psx_retroshader/blob/master/Assets/Shaders/psx-vertexlit.shader 23 | const vec2 base_snap_res = vec2(160.0, 120.0); 24 | vec4 get_snapped_pos(vec4 base_pos) 25 | { 26 | vec4 snapped_pos = base_pos; 27 | snapped_pos.xyz = base_pos.xyz / base_pos.w; // convert to normalised device coordinates (NDC) 28 | vec2 snap_res = floor(base_snap_res * precision_multiplier); // increase "snappy-ness" 29 | snapped_pos.x = floor(snap_res.x * snapped_pos.x) / snap_res.x; // snap the base_pos to the lower-vertex_resolution grid 30 | snapped_pos.y = floor(snap_res.y * snapped_pos.y) / snap_res.y; 31 | snapped_pos.xyz *= base_pos.w; // convert back to projection-space 32 | return snapped_pos; 33 | } 34 | 35 | void vertex() 36 | { 37 | #if !defined(NO_TEXTURE) && !defined(METAL) // METAL doesn't use UV, so no need to pan UVs 38 | UV = UV * uv_scale + uv_offset; 39 | UV += uv_pan_velocity * TIME; 40 | #endif 41 | 42 | #ifdef ALPHA_SCISSOR 43 | if (y_billboard) 44 | { 45 | MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], MODEL_MATRIX[1], vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, MODEL_MATRIX[1].xyz)), 0.0), MODEL_MATRIX[3]); 46 | MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0 / length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); 47 | } 48 | else if (billboard) 49 | { 50 | MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]); 51 | } 52 | #endif 53 | 54 | POSITION = get_snapped_pos(PROJECTION_MATRIX * MODELVIEW_MATRIX * vec4(VERTEX, 1.0)); // snap position to grid 55 | POSITION /= abs(POSITION.w); // discard depth for affine mapping 56 | 57 | #ifdef ALPHA_SCISSOR 58 | if (y_billboard) 59 | { 60 | MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]); 61 | MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0)); 62 | } 63 | #endif 64 | 65 | VERTEX = VERTEX; // it breaks without this - not sure why 66 | } 67 | 68 | void fragment() 69 | { 70 | #ifdef METAL 71 | vec2 texture_uv = vec2(NORMAL.x / 2.0 + 0.5, (-NORMAL.y) / 2.0 + 0.5); // Special thanks to Adam McLaughlan 72 | #elif !defined(NO_TEXTURE) 73 | vec2 texture_uv = UV; 74 | #endif 75 | 76 | vec4 color_base = COLOR * modulate_color; 77 | 78 | #ifdef NO_TEXTURE 79 | ALBEDO = color_base.rgb; 80 | #else 81 | vec4 texture_color = texture(albedoTex, texture_uv); 82 | ALBEDO = (color_base * texture_color).rgb; 83 | #endif 84 | 85 | #ifdef LIGHT_VOLUME 86 | ALPHA = 1.0 - UV.y; 87 | #elif defined(ALPHA_BLEND) || defined(ALPHA_SCISSOR) 88 | ALPHA = texture_color.a * color_base.a; 89 | #endif 90 | 91 | #ifdef ALPHA_SCISSOR 92 | ALPHA_SCISSOR_THRESHOLD = alpha_scissor; 93 | #endif 94 | } 95 | -------------------------------------------------------------------------------- /shaders/psx_light-volume.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define CULL cull_disabled 5 | #define DEPTH depth_draw_opaque 6 | #define BLEND blend_add 7 | #define NO_TEXTURE 8 | #define LIGHT_VOLUME 9 | 10 | #include "psx_base.gdshaderinc" 11 | -------------------------------------------------------------------------------- /shaders/psx_lit.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_opaque 6 | #define BLEND blend_mix 7 | 8 | #include "psx_base.gdshaderinc" 9 | -------------------------------------------------------------------------------- /shaders/psx_lit_alpha-scissor.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define CULL cull_disabled 5 | #define DEPTH depth_prepass_alpha 6 | #define BLEND blend_mix 7 | #define ALPHA_SCISSOR 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psx_lit_metal.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_opaque 6 | #define BLEND blend_mix 7 | #define METAL 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psx_lit_transparent.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_always 6 | #define BLEND blend_mix 7 | #define ALPHA_BLEND 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psx_unlit.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT unshaded 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_opaque 6 | #define BLEND blend_mix 7 | 8 | #include "psx_base.gdshaderinc" 9 | -------------------------------------------------------------------------------- /shaders/psx_unlit_alpha-scissor.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT unshaded 4 | #define CULL cull_disabled 5 | #define DEPTH depth_prepass_alpha 6 | #define BLEND blend_mix 7 | #define ALPHA_SCISSOR 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psx_unlit_metal.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT unshaded 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_opaque 6 | #define BLEND blend_mix 7 | #define METAL 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psx_unlit_transparent.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT unshaded 4 | #define CULL cull_back 5 | #define DEPTH depth_draw_always 6 | #define BLEND blend_mix 7 | #define ALPHA_BLEND 8 | 9 | #include "psx_base.gdshaderinc" 10 | -------------------------------------------------------------------------------- /shaders/psxdither.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/shaders/psxdither.png -------------------------------------------------------------------------------- /shaders/psxdither.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b0ub3tqjyw46f" 6 | path.s3tc="res://.godot/imported/psxdither.png-6c00fd8f19411080f93d281ca7da7716.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://shaders/psxdither.png" 15 | dest_files=["res://.godot/imported/psxdither.png-6c00fd8f19411080f93d281ca7da7716.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /world/box_lit/box-lit_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://duageqxj0x4k1"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit.gdshader" id="1_jfxfi"] 4 | [ext_resource type="Texture2D" uid="uid://b2o6eugnb81a6" path="res://icon.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1_jfxfi") 9 | shader_parameter/precision_multiplier = 1.0 10 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 11 | shader_parameter/uv_scale = Vector2(1, 1) 12 | shader_parameter/uv_offset = Vector2(0, 0) 13 | shader_parameter/uv_pan_velocity = Vector2(0, 0) 14 | shader_parameter/albedoTex = ExtResource("2") 15 | -------------------------------------------------------------------------------- /world/box_lit/box.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.83.2 OBJ File: 'box.blend' 2 | # www.blender.org 3 | o Cube_Cube.004 4 | v 1.000000 -1.000000 -1.000000 5 | v 1.000000 1.000000 -1.000000 6 | v 1.000000 -1.000000 1.000000 7 | v 1.000000 1.000000 1.000000 8 | v -1.000000 -1.000000 -1.000000 9 | v -1.000000 1.000000 -1.000000 10 | v -1.000000 -1.000000 1.000000 11 | v -1.000000 1.000000 1.000000 12 | v 0.000000 -1.000000 1.000000 13 | v 0.000000 1.000000 1.000000 14 | v 0.000000 -1.000000 -1.000000 15 | v 0.000000 1.000000 -1.000000 16 | v 1.000000 -1.000000 0.000000 17 | v 1.000000 1.000000 0.000000 18 | v -1.000000 -1.000000 0.000000 19 | v -1.000000 1.000000 0.000000 20 | v 0.000000 1.000000 0.000000 21 | v 0.000000 -1.000000 0.000000 22 | v 1.000000 0.000000 -1.000000 23 | v 1.000000 0.000000 1.000000 24 | v -1.000000 0.000000 1.000000 25 | v -1.000000 0.000000 -1.000000 26 | v 0.000000 0.000000 -1.000000 27 | v 0.000000 0.000000 1.000000 28 | v -1.000000 0.000000 0.000000 29 | v 1.000000 0.000000 0.000000 30 | vt 0.500000 0.500000 31 | vt 0.500000 1.000000 32 | vt -0.000000 1.000000 33 | vt -0.000000 0.500000 34 | vt 0.500000 0.500000 35 | vt 0.500000 1.000000 36 | vt -0.000000 1.000000 37 | vt -0.000000 0.500000 38 | vt 0.500000 0.500000 39 | vt 0.500000 1.000000 40 | vt -0.000000 1.000000 41 | vt -0.000000 0.500000 42 | vt 0.500000 0.500000 43 | vt 0.500000 1.000000 44 | vt 0.000000 1.000000 45 | vt 0.000000 0.500000 46 | vt 0.500000 0.500000 47 | vt 1.000000 0.500000 48 | vt 1.000000 1.000000 49 | vt 0.500000 1.000000 50 | vt 0.500000 0.500000 51 | vt 1.000000 0.500000 52 | vt 1.000000 1.000000 53 | vt 0.000000 0.500000 54 | vt -0.000000 0.500000 55 | vt -0.000000 1.000000 56 | vt 1.000000 0.500000 57 | vt 1.000000 1.000000 58 | vt 1.000000 0.500000 59 | vt 1.000000 1.000000 60 | vt -0.000000 -0.000000 61 | vt 0.500000 -0.000000 62 | vt 0.000000 -0.000000 63 | vt 0.500000 -0.000000 64 | vt 1.000000 -0.000000 65 | vt 1.000000 -0.000000 66 | vt 1.000000 0.500000 67 | vt 1.000000 1.000000 68 | vt 1.000000 0.500000 69 | vt 1.000000 -0.000000 70 | vt 0.500000 -0.000000 71 | vt 0.500000 -0.000000 72 | vt 1.000000 -0.000000 73 | vt 1.000000 0.000000 74 | vt 0.500000 0.000000 75 | vt 0.000000 0.000000 76 | vt -0.000000 -0.000000 77 | vt -0.000000 -0.000000 78 | vn 1.0000 0.0000 0.0000 79 | vn 0.0000 0.0000 1.0000 80 | vn -1.0000 0.0000 0.0000 81 | vn 0.0000 0.0000 -1.0000 82 | vn 0.0000 -1.0000 0.0000 83 | vn 0.0000 1.0000 0.0000 84 | usemtl None 85 | s off 86 | f 26/1/1 14/2/1 4/3/1 20/4/1 87 | f 24/5/2 10/6/2 8/7/2 21/8/2 88 | f 25/9/3 16/10/3 6/11/3 22/12/3 89 | f 23/13/4 12/14/4 2/15/4 19/16/4 90 | f 18/17/5 15/18/5 5/19/5 11/20/5 91 | f 17/21/6 14/22/6 2/23/6 12/14/6 92 | f 16/24/6 17/21/6 12/14/6 6/11/6 93 | f 13/25/5 18/17/5 11/20/5 1/26/5 94 | f 22/27/4 6/28/4 12/14/4 23/13/4 95 | f 20/29/2 4/30/2 10/6/2 24/5/2 96 | f 3/31/5 9/32/5 18/17/5 13/25/5 97 | f 8/33/6 10/34/6 17/21/6 16/24/6 98 | f 10/34/6 4/35/6 14/22/6 17/21/6 99 | f 9/32/5 7/36/5 15/18/5 18/17/5 100 | f 21/37/3 8/38/3 16/10/3 25/9/3 101 | f 19/39/1 2/23/1 14/2/1 26/1/1 102 | f 1/40/1 19/39/1 26/1/1 13/41/1 103 | f 7/36/3 21/37/3 25/9/3 15/42/3 104 | f 3/43/2 20/29/2 24/5/2 9/32/2 105 | f 5/44/4 22/27/4 23/13/4 11/45/4 106 | f 11/45/4 23/13/4 19/16/4 1/46/4 107 | f 15/42/3 25/9/3 22/12/3 5/47/3 108 | f 9/32/2 24/5/2 21/8/2 7/48/2 109 | f 13/41/1 26/1/1 20/4/1 3/31/1 110 | -------------------------------------------------------------------------------- /world/box_lit/box.obj.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wavefront_obj" 4 | importer_version=1 5 | type="Mesh" 6 | uid="uid://cd1odanjyg1jw" 7 | path="res://.godot/imported/box.obj-d02975eb462582baf5827d4dd18ba1a7.mesh" 8 | 9 | [deps] 10 | 11 | files=["res://.godot/imported/box.obj-d02975eb462582baf5827d4dd18ba1a7.mesh"] 12 | 13 | source_file="res://world/box_lit/box.obj" 14 | dest_files=["res://.godot/imported/box.obj-d02975eb462582baf5827d4dd18ba1a7.mesh", "res://.godot/imported/box.obj-d02975eb462582baf5827d4dd18ba1a7.mesh"] 15 | 16 | [params] 17 | 18 | generate_tangents=true 19 | scale_mesh=Vector3(1, 1, 1) 20 | offset_mesh=Vector3(0, 0, 0) 21 | optimize_mesh=true 22 | -------------------------------------------------------------------------------- /world/box_metal/bevel-box.obj: -------------------------------------------------------------------------------- 1 | # Blender 3.4.1 2 | # www.blender.org 3 | o Cube 4 | v 0.900000 0.900000 -1.000000 5 | v 0.900000 1.000000 -0.900000 6 | v 0.900000 1.000000 -0.900000 7 | v 1.000000 0.900000 -0.900000 8 | v 1.000000 0.900000 -0.900000 9 | v 0.900000 -1.000000 -0.900000 10 | v 0.900000 -0.900000 -1.000000 11 | v 0.900000 -0.900000 -1.000000 12 | v 1.000000 -0.900000 -0.900000 13 | v 1.000000 -0.900000 -0.900000 14 | v 1.000000 0.900000 0.900000 15 | v 0.900000 1.000000 0.900000 16 | v 0.900000 1.000000 0.900000 17 | v 0.900000 1.000000 0.900000 18 | v 0.900000 0.900000 1.000000 19 | v 0.900000 0.900000 1.000000 20 | v 1.000000 -0.900000 0.900000 21 | v 1.000000 -0.900000 0.900000 22 | v 0.900000 -0.900000 1.000000 23 | v 0.900000 -0.900000 1.000000 24 | v 0.900000 -0.900000 1.000000 25 | v 0.900000 -1.000000 0.900000 26 | v 0.900000 -1.000000 0.900000 27 | v -0.900000 0.900000 -1.000000 28 | v -0.900000 0.900000 -1.000000 29 | v -1.000000 0.900000 -0.900000 30 | v -1.000000 0.900000 -0.900000 31 | v -0.900000 1.000000 -0.900000 32 | v -0.900000 1.000000 -0.900000 33 | v -0.900000 1.000000 -0.900000 34 | v -1.000000 -0.900000 -0.900000 35 | v -1.000000 -0.900000 -0.900000 36 | v -0.900000 -0.900000 -1.000000 37 | v -0.900000 -0.900000 -1.000000 38 | v -0.900000 -0.900000 -1.000000 39 | v -0.900000 -1.000000 -0.900000 40 | v -0.900000 -1.000000 -0.900000 41 | v -1.000000 0.900000 0.900000 42 | v -0.900000 0.900000 1.000000 43 | v -0.900000 0.900000 1.000000 44 | v -0.900000 1.000000 0.900000 45 | v -0.900000 1.000000 0.900000 46 | v -0.900000 1.000000 0.900000 47 | v -0.900000 -1.000000 0.900000 48 | v -0.900000 -0.900000 1.000000 49 | v -0.900000 -0.900000 1.000000 50 | v -0.900000 -0.900000 1.000000 51 | v -1.000000 -0.900000 0.900000 52 | v -1.000000 -0.900000 0.900000 53 | vn -0.3417 -0.8755 -0.3417 54 | vn 0.3416 -0.8756 -0.3416 55 | vn 0.3417 -0.8755 0.3417 56 | vn -0.3416 -0.8756 0.3416 57 | vn -0.8756 -0.3416 0.3416 58 | vn -0.8756 0.3416 0.3416 59 | vn -0.8755 0.3417 -0.3417 60 | vn -0.8756 -0.3416 -0.3416 61 | vn 0.3416 -0.3416 0.8756 62 | vn 0.3417 0.3417 0.8755 63 | vn -0.3416 0.3416 0.8756 64 | vn -0.3416 -0.3416 0.8756 65 | vn 0.3416 0.8756 -0.3416 66 | vn -0.3416 0.8756 -0.3416 67 | vn -0.3416 0.8756 0.3416 68 | vn 0.3416 0.8756 0.3416 69 | vn 0.8755 -0.3417 -0.3417 70 | vn 0.8755 0.3417 -0.3417 71 | vn 0.8755 0.3417 0.3417 72 | vn 0.8755 -0.3417 0.3417 73 | vn 0.3416 0.3416 -0.8756 74 | vn 0.8756 0.3415 -0.3416 75 | vn 0.3416 -0.3416 -0.8756 76 | vn 0.8756 -0.3416 -0.3415 77 | vn 0.8756 0.3416 0.3415 78 | vn 0.3415 0.8756 0.3416 79 | vn 0.3416 0.3415 0.8756 80 | vn 0.8756 -0.3415 0.3416 81 | vn 0.3415 -0.3416 0.8756 82 | vn 0.3416 -0.8756 0.3415 83 | vn -0.3416 0.3415 -0.8756 84 | vn -0.8756 0.3416 -0.3415 85 | vn -0.3415 0.8756 -0.3416 86 | vn -0.8756 -0.3415 -0.3416 87 | vn -0.3415 -0.3416 -0.8756 88 | vn -0.3416 -0.8756 -0.3415 89 | vn -0.3415 0.8756 0.3416 90 | vn -0.8756 -0.3415 0.3416 91 | vn -0.3416 -0.3415 -0.8756 92 | vn -0.3415 -0.3416 0.8756 93 | vn -0.3417 0.3417 -0.8755 94 | vn -0.3416 -0.3416 -0.8756 95 | vn 0.3416 0.8756 0.3415 96 | vn -0.3416 0.8756 0.3415 97 | vn 0.3416 -0.3415 0.8756 98 | vn -0.3416 0.8756 -0.3415 99 | vt 0.612500 0.487500 100 | vt 0.625000 0.487500 101 | vt 0.637500 0.512500 102 | vt 0.612500 0.512500 103 | vt 0.612500 0.500000 104 | vt 0.362500 0.512500 105 | vt 0.362500 0.500000 106 | vt 0.387500 0.487500 107 | vt 0.375000 0.512500 108 | vt 0.387500 0.512500 109 | vt 0.612500 0.737500 110 | vt 0.625000 0.762500 111 | vt 0.625000 0.737500 112 | vt 0.637500 0.737500 113 | vt 0.612500 0.762500 114 | vt 0.612500 0.750000 115 | vt 0.387500 0.750000 116 | vt 0.387500 0.737500 117 | vt 0.362500 0.750000 118 | vt 0.375000 0.762500 119 | vt 0.387500 0.762500 120 | vt 0.362500 0.737500 121 | vt 0.375000 0.762500 122 | vt 0.612500 0.262500 123 | vt 0.612500 0.250000 124 | vt 0.612500 0.237500 125 | vt 0.612500 0.250000 126 | vt 0.625000 0.262500 127 | vt 0.625000 0.237500 128 | vt 0.862500 0.512500 129 | vt 0.125000 0.512500 130 | vt 0.387500 0.237500 131 | vt 0.137500 0.500000 132 | vt 0.387500 0.262500 133 | vt 0.387500 0.250000 134 | vt 0.137500 0.512500 135 | vt 0.375000 0.237500 136 | vt 0.612500 0.012500 137 | vt 0.612500 0.987500 138 | vt 0.612500 0.000000 139 | vt 0.625000 0.987500 140 | vt 0.625000 0.012500 141 | vt 0.862500 0.737500 142 | vt 0.137500 0.737500 143 | vt 0.137500 0.750000 144 | vt 0.387500 0.987500 145 | vt 0.387500 0.000000 146 | vt 0.125000 0.737500 147 | vt 0.387500 0.012500 148 | s 1 149 | f 36/36/1 6/6/2 22/22/3 150 | f 36/36/1 22/22/3 44/44/4 151 | f 49/49/5 38/38/6 26/26/7 152 | f 49/49/5 26/26/7 32/32/8 153 | f 21/21/9 15/15/10 39/39/11 154 | f 21/21/9 39/39/11 46/46/12 155 | f 3/3/13 30/30/14 43/43/15 156 | f 3/3/13 43/43/15 14/14/16 157 | f 10/10/17 4/4/18 11/11/19 158 | f 10/10/17 11/11/19 18/18/20 159 | f 1/1/21 2/2/13 5/5/22 160 | f 6/6/2 7/7/23 9/9/24 161 | f 11/11/25 13/13/26 16/16/27 162 | f 17/17/28 20/20/29 23/23/30 163 | f 25/25/31 27/27/32 29/29/33 164 | f 32/32/34 35/35/35 37/37/36 165 | f 38/38/6 40/40/11 42/42/37 166 | f 44/44/4 45/45/12 48/48/38 167 | f 36/36/1 44/44/4 48/48/38 168 | f 36/36/1 48/48/38 31/31/34 169 | f 6/6/2 36/36/1 33/33/39 170 | f 6/6/2 33/33/39 7/7/23 171 | f 4/4/18 10/10/17 8/8/23 172 | f 4/4/18 8/8/23 1/1/21 173 | f 47/47/40 40/40/11 38/38/6 174 | f 47/47/40 38/38/6 49/49/5 175 | f 15/15/10 21/21/9 18/18/20 176 | f 15/15/10 18/18/20 11/11/19 177 | f 24/24/41 34/34/42 32/32/8 178 | f 24/24/41 32/32/8 26/26/7 179 | f 12/12/43 41/41/44 39/39/11 180 | f 12/12/43 39/39/11 15/15/10 181 | f 3/3/13 14/14/16 11/11/19 182 | f 3/3/13 11/11/19 4/4/18 183 | f 44/44/4 22/22/3 19/19/45 184 | f 44/44/4 19/19/45 45/45/12 185 | f 42/42/37 29/29/33 26/26/7 186 | f 42/42/37 26/26/7 38/38/6 187 | f 28/28/46 2/2/13 1/1/21 188 | f 28/28/46 1/1/21 24/24/41 189 | f 22/22/3 6/6/2 10/10/17 190 | f 22/22/3 10/10/17 18/18/20 191 | f 34/34/42 24/24/41 1/1/21 192 | f 34/34/42 1/1/21 8/8/23 193 | -------------------------------------------------------------------------------- /world/box_metal/bevel-box.obj.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wavefront_obj" 4 | importer_version=1 5 | type="Mesh" 6 | uid="uid://cbvn8fwufde7c" 7 | path="res://.godot/imported/bevel-box.obj-28a5573e1a1eca6adbca83c44a86e0b5.mesh" 8 | 9 | [deps] 10 | 11 | files=["res://.godot/imported/bevel-box.obj-28a5573e1a1eca6adbca83c44a86e0b5.mesh"] 12 | 13 | source_file="res://world/box_metal/bevel-box.obj" 14 | dest_files=["res://.godot/imported/bevel-box.obj-28a5573e1a1eca6adbca83c44a86e0b5.mesh", "res://.godot/imported/bevel-box.obj-28a5573e1a1eca6adbca83c44a86e0b5.mesh"] 15 | 16 | [params] 17 | 18 | generate_tangents=true 19 | scale_mesh=Vector3(1, 1, 1) 20 | offset_mesh=Vector3(0, 0, 0) 21 | optimize_mesh=true 22 | -------------------------------------------------------------------------------- /world/box_metal/box-metal_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://5nocpdx2io83"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit_metal.gdshader" id="1_mibpy"] 4 | [ext_resource type="Texture2D" uid="uid://f714cvvwb8wk" path="res://world/box_metal/metal-tex.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1_mibpy") 9 | shader_parameter/precision_multiplier = 1.0 10 | shader_parameter/modulate_color = Color(0.95, 0.6, 0, 1) 11 | shader_parameter/albedoTex = ExtResource("2") 12 | -------------------------------------------------------------------------------- /world/box_metal/metal-tex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/box_metal/metal-tex.png -------------------------------------------------------------------------------- /world/box_metal/metal-tex.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://f714cvvwb8wk" 6 | path.s3tc="res://.godot/imported/metal-tex.png-1a61700c40562a6eacbdb052324a4600.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/box_metal/metal-tex.png" 15 | dest_files=["res://.godot/imported/metal-tex.png-1a61700c40562a6eacbdb052324a4600.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /world/crystal/crystal.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset" : { 3 | "generator" : "Khronos glTF Blender I/O v1.5.17", 4 | "version" : "2.0" 5 | }, 6 | "scene" : 0, 7 | "scenes" : [ 8 | { 9 | "name" : "Scene", 10 | "nodes" : [ 11 | 4 12 | ] 13 | } 14 | ], 15 | "nodes" : [ 16 | { 17 | "mesh" : 0, 18 | "name" : "Spire_1", 19 | "rotation" : [ 20 | 0, 21 | 0, 22 | -0.13394181430339813, 23 | 0.9909892082214355 24 | ], 25 | "scale" : [ 26 | 0.9665998816490173, 27 | 1.9730743169784546, 28 | 0.9665998220443726 29 | ] 30 | }, 31 | { 32 | "mesh" : 1, 33 | "name" : "Spire_2", 34 | "rotation" : [ 35 | -0.1060328334569931, 36 | 0.7845003008842468, 37 | -0.08183794468641281, 38 | 0.6054906249046326 39 | ], 40 | "scale" : [ 41 | 0.9143921136856079, 42 | 1.9730740785598755, 43 | 0.9143921732902527 44 | ] 45 | }, 46 | { 47 | "mesh" : 2, 48 | "name" : "Spire_3", 49 | "rotation" : [ 50 | 0.13004890084266663, 51 | -0.9621871113777161, 52 | -0.032057520002126694, 53 | 0.23718255758285522 54 | ], 55 | "scale" : [ 56 | 0.8077337741851807, 57 | 1.9730740785598755, 58 | 0.8077337741851807 59 | ] 60 | }, 61 | { 62 | "mesh" : 3, 63 | "name" : "Spire_4", 64 | "rotation" : [ 65 | 0.08229666948318481, 66 | -0.6088846325874329, 67 | -0.10567717254161835, 68 | 0.7818689346313477 69 | ], 70 | "scale" : [ 71 | 0.6145420670509338, 72 | 1.9730740785598755, 73 | 0.6145421862602234 74 | ] 75 | }, 76 | { 77 | "children" : [ 78 | 0, 79 | 1, 80 | 2, 81 | 3 82 | ], 83 | "mesh" : 4, 84 | "name" : "Ground", 85 | "scale" : [ 86 | 0.3105831444263458, 87 | 0.3105831444263458, 88 | 0.3105831444263458 89 | ], 90 | "translation" : [ 91 | -0.022743847221136093, 92 | 0, 93 | 0.012320916168391705 94 | ] 95 | } 96 | ], 97 | "meshes" : [ 98 | { 99 | "name" : "Sphere", 100 | "primitives" : [ 101 | { 102 | "attributes" : { 103 | "POSITION" : 0, 104 | "NORMAL" : 1, 105 | "TEXCOORD_0" : 2, 106 | "COLOR_0" : 3 107 | }, 108 | "indices" : 4 109 | } 110 | ] 111 | }, 112 | { 113 | "name" : "Sphere.001", 114 | "primitives" : [ 115 | { 116 | "attributes" : { 117 | "POSITION" : 5, 118 | "NORMAL" : 6, 119 | "TEXCOORD_0" : 7, 120 | "COLOR_0" : 8 121 | }, 122 | "indices" : 9 123 | } 124 | ] 125 | }, 126 | { 127 | "name" : "Sphere.002", 128 | "primitives" : [ 129 | { 130 | "attributes" : { 131 | "POSITION" : 10, 132 | "NORMAL" : 11, 133 | "TEXCOORD_0" : 12, 134 | "COLOR_0" : 13 135 | }, 136 | "indices" : 9 137 | } 138 | ] 139 | }, 140 | { 141 | "name" : "Sphere.003", 142 | "primitives" : [ 143 | { 144 | "attributes" : { 145 | "POSITION" : 14, 146 | "NORMAL" : 15, 147 | "TEXCOORD_0" : 16, 148 | "COLOR_0" : 17 149 | }, 150 | "indices" : 18 151 | } 152 | ] 153 | }, 154 | { 155 | "name" : "Torus", 156 | "primitives" : [ 157 | { 158 | "attributes" : { 159 | "POSITION" : 19, 160 | "NORMAL" : 20, 161 | "TEXCOORD_0" : 21, 162 | "COLOR_0" : 22 163 | }, 164 | "indices" : 23 165 | } 166 | ] 167 | } 168 | ], 169 | "accessors" : [ 170 | { 171 | "bufferView" : 0, 172 | "componentType" : 5126, 173 | "count" : 40, 174 | "max" : [ 175 | 0.74625164270401, 176 | 3.0796260833740234, 177 | 0.8314425945281982 178 | ], 179 | "min" : [ 180 | -0.9857993721961975, 181 | 0.23422129452228546, 182 | -0.9006084203720093 183 | ], 184 | "type" : "VEC3" 185 | }, 186 | { 187 | "bufferView" : 1, 188 | "componentType" : 5126, 189 | "count" : 40, 190 | "type" : "VEC3" 191 | }, 192 | { 193 | "bufferView" : 2, 194 | "componentType" : 5126, 195 | "count" : 40, 196 | "type" : "VEC2" 197 | }, 198 | { 199 | "bufferView" : 3, 200 | "componentType" : 5123, 201 | "count" : 40, 202 | "normalized" : true, 203 | "type" : "VEC4" 204 | }, 205 | { 206 | "bufferView" : 4, 207 | "componentType" : 5123, 208 | "count" : 48, 209 | "type" : "SCALAR" 210 | }, 211 | { 212 | "bufferView" : 5, 213 | "componentType" : 5126, 214 | "count" : 40, 215 | "max" : [ 216 | 1.0716272592544556, 217 | 2.383936882019043, 218 | 0.8469353914260864 219 | ], 220 | "min" : [ 221 | -0.660423755645752, 222 | 0.2847820520401001, 223 | -0.8851156234741211 224 | ], 225 | "type" : "VEC3" 226 | }, 227 | { 228 | "bufferView" : 6, 229 | "componentType" : 5126, 230 | "count" : 40, 231 | "type" : "VEC3" 232 | }, 233 | { 234 | "bufferView" : 7, 235 | "componentType" : 5126, 236 | "count" : 40, 237 | "type" : "VEC2" 238 | }, 239 | { 240 | "bufferView" : 8, 241 | "componentType" : 5123, 242 | "count" : 40, 243 | "normalized" : true, 244 | "type" : "VEC4" 245 | }, 246 | { 247 | "bufferView" : 9, 248 | "componentType" : 5123, 249 | "count" : 48, 250 | "type" : "SCALAR" 251 | }, 252 | { 253 | "bufferView" : 10, 254 | "componentType" : 5126, 255 | "count" : 40, 256 | "max" : [ 257 | 1.0190777778625488, 258 | 2.782522439956665, 259 | 0.9576164484024048 260 | ], 261 | "min" : [ 262 | -0.7129731774330139, 263 | 0.295535147190094, 264 | -0.7744345664978027 265 | ], 266 | "type" : "VEC3" 267 | }, 268 | { 269 | "bufferView" : 11, 270 | "componentType" : 5126, 271 | "count" : 40, 272 | "type" : "VEC3" 273 | }, 274 | { 275 | "bufferView" : 12, 276 | "componentType" : 5126, 277 | "count" : 40, 278 | "type" : "VEC2" 279 | }, 280 | { 281 | "bufferView" : 13, 282 | "componentType" : 5123, 283 | "count" : 40, 284 | "normalized" : true, 285 | "type" : "VEC4" 286 | }, 287 | { 288 | "bufferView" : 14, 289 | "componentType" : 5126, 290 | "count" : 40, 291 | "max" : [ 292 | 1.3640248775482178, 293 | 2.0944957733154297, 294 | 0.8980217576026917 295 | ], 296 | "min" : [ 297 | -0.36802613735198975, 298 | 0.2590293884277344, 299 | -0.8340292572975159 300 | ], 301 | "type" : "VEC3" 302 | }, 303 | { 304 | "bufferView" : 15, 305 | "componentType" : 5126, 306 | "count" : 40, 307 | "type" : "VEC3" 308 | }, 309 | { 310 | "bufferView" : 16, 311 | "componentType" : 5126, 312 | "count" : 40, 313 | "type" : "VEC2" 314 | }, 315 | { 316 | "bufferView" : 17, 317 | "componentType" : 5123, 318 | "count" : 40, 319 | "normalized" : true, 320 | "type" : "VEC4" 321 | }, 322 | { 323 | "bufferView" : 18, 324 | "componentType" : 5123, 325 | "count" : 48, 326 | "type" : "SCALAR" 327 | }, 328 | { 329 | "bufferView" : 19, 330 | "componentType" : 5126, 331 | "count" : 29, 332 | "max" : [ 333 | 1.5700442790985107, 334 | 0.9535278081893921, 335 | 1.5286825895309448 336 | ], 337 | "min" : [ 338 | -1.4354413747787476, 339 | -2.9802322387695312e-08, 340 | -1.4516061544418335 341 | ], 342 | "type" : "VEC3" 343 | }, 344 | { 345 | "bufferView" : 20, 346 | "componentType" : 5126, 347 | "count" : 29, 348 | "type" : "VEC3" 349 | }, 350 | { 351 | "bufferView" : 21, 352 | "componentType" : 5126, 353 | "count" : 29, 354 | "type" : "VEC2" 355 | }, 356 | { 357 | "bufferView" : 22, 358 | "componentType" : 5123, 359 | "count" : 29, 360 | "normalized" : true, 361 | "type" : "VEC4" 362 | }, 363 | { 364 | "bufferView" : 23, 365 | "componentType" : 5123, 366 | "count" : 81, 367 | "type" : "SCALAR" 368 | } 369 | ], 370 | "bufferViews" : [ 371 | { 372 | "buffer" : 0, 373 | "byteLength" : 480, 374 | "byteOffset" : 0 375 | }, 376 | { 377 | "buffer" : 0, 378 | "byteLength" : 480, 379 | "byteOffset" : 480 380 | }, 381 | { 382 | "buffer" : 0, 383 | "byteLength" : 320, 384 | "byteOffset" : 960 385 | }, 386 | { 387 | "buffer" : 0, 388 | "byteLength" : 320, 389 | "byteOffset" : 1280 390 | }, 391 | { 392 | "buffer" : 0, 393 | "byteLength" : 96, 394 | "byteOffset" : 1600 395 | }, 396 | { 397 | "buffer" : 0, 398 | "byteLength" : 480, 399 | "byteOffset" : 1696 400 | }, 401 | { 402 | "buffer" : 0, 403 | "byteLength" : 480, 404 | "byteOffset" : 2176 405 | }, 406 | { 407 | "buffer" : 0, 408 | "byteLength" : 320, 409 | "byteOffset" : 2656 410 | }, 411 | { 412 | "buffer" : 0, 413 | "byteLength" : 320, 414 | "byteOffset" : 2976 415 | }, 416 | { 417 | "buffer" : 0, 418 | "byteLength" : 96, 419 | "byteOffset" : 3296 420 | }, 421 | { 422 | "buffer" : 0, 423 | "byteLength" : 480, 424 | "byteOffset" : 3392 425 | }, 426 | { 427 | "buffer" : 0, 428 | "byteLength" : 480, 429 | "byteOffset" : 3872 430 | }, 431 | { 432 | "buffer" : 0, 433 | "byteLength" : 320, 434 | "byteOffset" : 4352 435 | }, 436 | { 437 | "buffer" : 0, 438 | "byteLength" : 320, 439 | "byteOffset" : 4672 440 | }, 441 | { 442 | "buffer" : 0, 443 | "byteLength" : 480, 444 | "byteOffset" : 4992 445 | }, 446 | { 447 | "buffer" : 0, 448 | "byteLength" : 480, 449 | "byteOffset" : 5472 450 | }, 451 | { 452 | "buffer" : 0, 453 | "byteLength" : 320, 454 | "byteOffset" : 5952 455 | }, 456 | { 457 | "buffer" : 0, 458 | "byteLength" : 320, 459 | "byteOffset" : 6272 460 | }, 461 | { 462 | "buffer" : 0, 463 | "byteLength" : 96, 464 | "byteOffset" : 6592 465 | }, 466 | { 467 | "buffer" : 0, 468 | "byteLength" : 348, 469 | "byteOffset" : 6688 470 | }, 471 | { 472 | "buffer" : 0, 473 | "byteLength" : 348, 474 | "byteOffset" : 7036 475 | }, 476 | { 477 | "buffer" : 0, 478 | "byteLength" : 232, 479 | "byteOffset" : 7384 480 | }, 481 | { 482 | "buffer" : 0, 483 | "byteLength" : 232, 484 | "byteOffset" : 7616 485 | }, 486 | { 487 | "buffer" : 0, 488 | "byteLength" : 162, 489 | "byteOffset" : 7848 490 | } 491 | ], 492 | "buffers" : [ 493 | { 494 | "byteLength" : 8012, 495 | "uri" : "data:application/octet-stream;base64,BEz1vZkYJUBGjma/BEz1vZkYJUBGjma/BEz1vZkYJUBGjma/BEz1vZkYJUBGjma/CEz1vbnXbz5Fjma/CEz1vbnXbz5Fjma/CEz1vbnXbz5Fjma/CEz1vbnXbz5Fjma/WQo/P5kYJUDIpg29WQo/P5kYJUDIpg29WQo/P5kYJUDIpg29WQo/P5kYJUDIpg29Vwo/P7nXbz7Ipg29Vwo/P7nXbz7Ipg29Vwo/P7nXbz7Ipg29Vwo/P7nXbz7Ipg29BEz1vZgYRUC7pg29BEz1vZgYRUC7pg29BEz1vZgYRUC7pg29BEz1vZgYRUC7pg29Dkz1vZgYJUBs2VQ/Dkz1vZgYJUBs2VQ/Dkz1vZgYJUBs2VQ/Dkz1vZgYJUBs2VQ/Ekz1vbnXbz5r2VQ/Ekz1vbnXbz5r2VQ/Ekz1vbnXbz5r2VQ/Ekz1vbnXbz5r2VQ/WV18v5gYJUDwpg29WV18v5gYJUDwpg29WV18v5gYJUDwpg29WV18v5gYJUDwpg29WV18v7nXbz7wpg29WV18v7nXbz7wpg29WV18v7nXbz7wpg29WV18v7nXbz7wpg29CEz1vbXXbz7Spg29CEz1vbXXbz7Spg29CEz1vbXXbz7Spg29CEz1vbXXbz7Spg298wQ1v2OGIDL1BDW/NPnkvvhLRj8m+eS+HfnkPv1LRj8p+eS+9AQ1P1wI/7LzBDW/8wQ1v2OGIDL1BDW/qaqqswAAgL85zZOzqaoqMwAAgL85zZOz9AQ1P1wI/7LzBDW/HfnkPv1LRj8p+eS+MvnkPvZLRj8s+eQ+8wQ1Py5KV7P1BDU/9AQ1P1wI/7LzBDW/qaoqMwAAgL85zZOzAAAANAAAgL88zZMz8wQ1Py5KV7P1BDU/9AQ1P1wI/7LzBDW/NPnkvvhLRj8m+eS+LPnkvvlLRj8v+eQ+HfnkPv1LRj8p+eS+MvnkPvZLRj8s+eQ+9QQ1vwAAAADyBDU/LPnkvvlLRj8v+eQ+MvnkPvZLRj8s+eQ+8wQ1Py5KV7P1BDU/9QQ1vwAAAADyBDU/qqqqswAAgL85zZMzAAAANAAAgL88zZMz8wQ1Py5KV7P1BDU/9QQ1vwAAAADyBDU/8wQ1v2OGIDL1BDW/NPnkvvhLRj8m+eS+LPnkvvlLRj8v+eQ+9QQ1vwAAAADyBDU/8wQ1v2OGIDL1BDW/qqqqswAAgL85zZMzqaqqswAAgL85zZOzqqqqswAAgL85zZMzqaqqswAAgL85zZOzqaoqMwAAgL85zZOzAAAANAAAgL88zZMzAABAP6yqqj4AAEA/rKqqPgAAQD+sqqo+AABAP6yqqj4AAEA/q6oqPwAAQD+rqio/AABAP6uqKj8AAEA/q6oqP////z6sqqo+////Pqyqqj7///8+rKqqPv///z6sqqo+////PquqKj////8+q6oqP////z6rqio/////PquqKj8AAGA/AAAAAAAAAD4AAAAA//8fPwAAAAD//78+AAAAAAAAgD6sqqo+AACAPqyqqj4AAIA+rKqqPgAAgD6sqqo+AACAPquqKj8AAIA+q6oqPwAAgD6rqio/AACAPquqKj8AAAAArKqqPgAAgD+sqqo+AACAP6yqqj4AAAAArKqqPgAAAACrqio/AACAP6uqKj8AAAAAq6oqPwAAgD+rqio/AAAAPgAAgD8AAGA/AACAPwAAID8AAIA///+/PgAAgD/Ad0EXnmH//8B3QReeYf//wHdBF55h///Ad0EXnmH//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//wGe8EwZuf//AZ7wTBm5//8BnvBMGbn//wGe8EwZuf//wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//8B3QReeYf//wHdBF55h///Ad0EXnmH//8B3QReeYf//ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//yYABgAMAAcAAwALAAcACwAPAAIAEgAIACcADQAaAA4ACgAXAA4AFwAbAAkAEwAWACQAGQAiABgAFAAcABgAHAAgABUAEQAfACUAIwAFACEAHQAAACEAAAAEAB4AEAABAEaJUj7cJPE/8JZiv0aJUj7cJPE/8JZiv0aJUj7cJPE/8JZiv0aJUj7cJPE/8JZiv0aJUj72zpE+75Ziv0aJUj72zpE+75Ziv0aJUj72zpE+75Ziv0aJUj72zpE+75ZivxUriT/bJPE/xGKcvBUriT/bJPE/xGKcvBUriT/bJPE/xGKcvBUriT/bJPE/xGKcvBUriT/2zpE+xGKcvBUriT/2zpE+xGKcvBUriT/2zpE+xGKcvBUriT/2zpE+xGKcvEaJUj5skhhAqWKcvEaJUj5skhhAqWKcvEaJUj5skhhAqWKcvEaJUj5skhhAqWKcvEGJUj7aJPE/wtBYP0GJUj7aJPE/wtBYP0GJUj7aJPE/wtBYP0GJUj7aJPE/wtBYP0GJUj72zpE+wdBYP0GJUj72zpE+wdBYP0GJUj72zpE+wdBYP0GJUj72zpE+wdBYP4gRKb/ZJPE/FWOcvIgRKb/ZJPE/FWOcvIgRKb/ZJPE/FWOcvIgRKb/ZJPE/FWOcvIYRKb/2zpE+FWOcvIYRKb/2zpE+FWOcvIYRKb/2zpE+FWOcvIYRKb/2zpE+FWOcvEaJUj70zpE+2GKcvEaJUj70zpE+2GKcvEaJUj70zpE+2GKcvEaJUj70zpE+2GKcvPEENb9ftQKz9QQ1vzT55L76S0Y/H/nkvij55D78S0Y/IPnkvvQENT9dtYKy8wQ1v/EENb9ftQKz9QQ1v6mqqrMAAIC/Oc2Ts6qqqjMAAIC/O82Ts/QENT9dtYKy8wQ1vyj55D76S0Y/LPnkPij55D78S0Y/IPnkvvIENT9ftYKy9gQ1P/QENT9dtYKy8wQ1v6mqqjMAAIC/O82TM6qqqjMAAIC/O82Ts/IENT9ftYKy9gQ1P/QENT9dtYKy8wQ1vzT55L76S0Y/H/nkviX55L77S0Y/KfnkPij55D76S0Y/LPnkPij55D78S0Y/IPnkvvYENb+hDUmz8gQ1PyX55L77S0Y/KfnkPij55D76S0Y/LPnkPvIENT9ftYKy9gQ1P/YENb+hDUmz8gQ1P6uqqrMAAIC/Os2TM6mqqjMAAIC/O82TM/IENT9ftYKy9gQ1P/YENb+hDUmz8gQ1P/EENb9ftQKz9QQ1vzT55L76S0Y/H/nkviX55L77S0Y/KfnkPvYENb+hDUmz8gQ1P/EENb9ftQKz9QQ1v6uqqrMAAIC/Os2TM6mqqrMAAIC/Oc2Ts6uqqrMAAIC/Os2TM6mqqrMAAIC/Oc2Ts6mqqjMAAIC/O82TM6qqqjMAAIC/O82TswAAQD+sqqo+AABAP6yqqj4AAEA/rKqqPgAAQD+sqqo+AABAP6uqKj8AAEA/q6oqPwAAQD+rqio/AABAP6uqKj////8+rKqqPv///z6sqqo+////Pqyqqj7///8+rKqqPv///z6rqio/////PquqKj////8+q6oqP////z6rqio/AABgPwAAAAAAAAA+AAAAAP//vz4AAAAA//8fPwAAAAAAAIA+rKqqPgAAgD6sqqo+AACAPqyqqj4AAIA+rKqqPgAAgD6rqio/AACAPquqKj8AAIA+q6oqPwAAgD6rqio/AAAAAKyqqj4AAIA/rKqqPgAAgD+sqqo+AAAAAKyqqj4AAAAAq6oqPwAAgD+rqio/AAAAAKuqKj8AAIA/q6oqPwAAAD4AAIA/AABgPwAAgD///78+AACAPwAAID8AAIA/wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//8B3QReeYf//wHdBF55h///Ad0EXnmH//8B3QReeYf//fEgqCAs8//98SCoICzz//3xIKggLPP//fEgqCAs8//8BnhNO/7r//wGeE07/uv//AZ4TTv+6//8BnhNO/7r//8B3QReeYf//wHdBF55h///Ad0EXnmH//8B3QReeYf//ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7///Ad0EXnmH//8B3QReeYf//wHdBF55h///Ad0EXnmH//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7//8nAAYADQAHAAMACwAHAAsADwACABMACQAmAAwAGgAOAAoAFwAOABcAGwAIABIAFgAkABkAIgAYABQAHAAYABwAIAAVABEAHwAlACMABQAhAB0AAAAhAAAABAAeABAAAQC+uRw+2hQSQFhBRr++uRw+2hQSQFhBRr++uRw+2hQSQFhBRr++uRw+2hQSQFhBRr+8uRw+ZFCXPldBRr+8uRw+ZFCXPldBRr+8uRw+ZFCXPldBRr+8uRw+ZFCXPldBRr8kcYI/2hQSQA6Uuz0kcYI/2hQSQA6Uuz0kcYI/2hQSQA6Uuz0kcYI/2hQSQA6Uuz0kcYI/ZFCXPhCUuz0kcYI/ZFCXPhCUuz0kcYI/ZFCXPhCUuz0kcYI/ZFCXPhCUuz2+uRw+2RQyQBWUuz2+uRw+2RQyQBWUuz2+uRw+2RQyQBWUuz2+uRw+2RQyQBWUuz25uRw+2RQSQFomdT+5uRw+2RQSQFomdT+5uRw+2RQSQFomdT+5uRw+2RQSQFomdT+3uRw+ZFCXPlkmdT+3uRw+ZFCXPlkmdT+3uRw+ZFCXPlkmdT+3uRw+ZFCXPlkmdT9phTa/2RQSQPqTuz1phTa/2RQSQPqTuz1phTa/2RQSQPqTuz1phTa/2RQSQPqTuz1phTa/ZFCXPvyTuz1phTa/ZFCXPvyTuz1phTa/ZFCXPvyTuz1phTa/ZFCXPvyTuz28uRw+YlCXPguUuz28uRw+YlCXPguUuz28uRw+YlCXPguUuz28uRw+YlCXPguUuz3yBDW/Ue8iMvQENb8t+eS++ktGPyf55L4s+eQ++ktGPyf55L7zBDU/WGRSsvMENb/yBDW/Ue8iMvQENb+pqqqzAACAvznNk7Ooqio0AACAvzrNk7PzBDU/WGRSsvMENb8e+eQ++0tGPzH55D4s+eQ++ktGPyf55L7yBDU/jnlJsvMENT/zBDU/WGRSsvMENb+oqqozAACAvzrNkzOoqio0AACAvzrNk7PyBDU/jnlJsvMENT/zBDU/WGRSsvMENb8t+eS++ktGPyf55L4p+eS++ktGPy/55D4e+eQ++0tGPzH55D4s+eQ++ktGPyf55L70BDW/WWRSsvIENT8p+eS++ktGPy/55D4e+eQ++0tGPzH55D7yBDU/jnlJsvMENT/0BDW/WWRSsvIENT+qqqqzAACAvznNkzOoqqozAACAvzrNkzPyBDU/jnlJsvMENT/0BDW/WWRSsvIENT/yBDW/Ue8iMvQENb8t+eS++ktGPyf55L4p+eS++ktGPy/55D70BDW/WWRSsvIENT/yBDW/Ue8iMvQENb+qqqqzAACAvznNkzOpqqqzAACAvznNk7OqqqqzAACAvznNkzOpqqqzAACAvznNk7OoqqozAACAvzrNkzOoqio0AACAvzrNk7MAAEA/rKqqPgAAQD+sqqo+AABAP6yqqj4AAEA/rKqqPgAAQD+rqio/AABAP6uqKj8AAEA/q6oqPwAAQD+rqio/////Pqyqqj7///8+rKqqPv///z6sqqo+////Pqyqqj7///8+q6oqP////z6rqio/////PquqKj////8+q6oqPwAAYD8AAAAAAAAAPgAAAAD//78+AAAAAP//Hz8AAAAAAACAPqyqqj4AAIA+rKqqPgAAgD6sqqo+AACAPqyqqj4AAIA+q6oqPwAAgD6rqio/AACAPquqKj8AAIA+q6oqPwAAAACsqqo+AACAP6yqqj4AAIA/rKqqPgAAAACsqqo+AAAAAKuqKj8AAIA/q6oqPwAAAACrqio/AACAP6uqKj8AAAA+AACAPwAAYD8AAIA///+/PgAAgD8AACA/AACAP8B3QReeYf//wHdBF55h///Ad0EXnmH//8B3QReeYf//ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7///Ad0EXnmH//8B3QReeYf//wHdBF55h///Ad0EXnmH//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///AZ4TTv+6//8BnhNO/7r//wGeE07/uv//AZ4TTv+6///Ad0EXnmH//8B3QReeYf//wHdBF55h///Ad0EXnmH//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///xvn+PnQYzD/xglW/xvn+PnQYzD/xglW/xvn+PnQYzD/xglW/xvn+PnQYzD/xglW/xvn+PoKfhD7wglW/xvn+PoKfhD7wglW/xvn+PoKfhD7wglW/xvn+PoKfhD7wglW/XpiuP3IYzD+LDgM9XpiuP3IYzD+LDgM9XpiuP3IYzD+LDgM9XpiuP3IYzD+LDgM9XpiuP4KfhD6ODgM9XpiuP4KfhD6ODgM9XpiuP4KfhD6ODgM9XpiuP4KfhD6ODgM9xfn+PjgMBkCYDgM9xfn+PjgMBkCYDgM9xfn+PjgMBkCYDgM9xfn+PjgMBkCYDgM9w/n+PnIYzD/B5GU/w/n+PnIYzD/B5GU/w/n+PnIYzD/B5GU/w/n+PnIYzD/B5GU/w/n+PoKfhD7A5GU/w/n+PoKfhD7A5GU/w/n+PoKfhD7A5GU/w/n+PoKfhD7A5GU/7G28vnAYzD9jDgM97G28vnAYzD9jDgM97G28vnAYzD9jDgM97G28vnAYzD9jDgM96m28voKfhD5mDgM96m28voKfhD5mDgM96m28voKfhD5mDgM96m28voKfhD5mDgM9xvn+PoCfhD6EDgM9xvn+PoCfhD6EDgM9xvn+PoCfhD6EDgM9xvn+PoCfhD6EDgM98wQ1v1WEHLP0BDW/LfnkvvtLRj8h+eS+KfnkPvxLRj8h+eS+8wQ1P1OEnLLzBDW/8wQ1v1WEHLP0BDW/qaoqswAAgL85zZOzqaoqMwAAgL87zZOz8wQ1P1OEnLLzBDW/KfnkPvxLRj8h+eS+LfnkPvhLRj8p+eQ+8gQ1P1SEnLL1BDU/8wQ1P1OEnLLzBDW/qaoqMwAAgL87zZOzqaoqMwAAgL88zZMz8gQ1P1SEnLL1BDU/8wQ1P1OEnLLzBDW/NfnkvvdLRj8l+eQ+LfnkvvtLRj8h+eS+KfnkPvxLRj8h+eS+LfnkPvhLRj8p+eQ+9AQ1v3fEZbPyBDU/NfnkvvdLRj8l+eQ+LfnkPvhLRj8p+eQ+8gQ1P1SEnLL1BDU/9AQ1v3fEZbPyBDU/q6oqswAAgL86zZMzqaoqMwAAgL88zZMz8gQ1P1SEnLL1BDU/9AQ1v3fEZbPyBDU/8wQ1v1WEHLP0BDW/NfnkvvdLRj8l+eQ+LfnkvvtLRj8h+eS+9AQ1v3fEZbPyBDU/8wQ1v1WEHLP0BDW/q6oqswAAgL86zZMzqaoqswAAgL85zZOzq6oqswAAgL86zZMzqaoqswAAgL85zZOzqaoqMwAAgL87zZOzqaoqMwAAgL88zZMzAABAP6yqqj4AAEA/rKqqPgAAQD+sqqo+AABAP6yqqj4AAEA/q6oqPwAAQD+rqio/AABAP6uqKj8AAEA/q6oqP////z6sqqo+////Pqyqqj7///8+rKqqPv///z6sqqo+////PquqKj////8+q6oqP////z6rqio/////PquqKj8AAAA+AAAAAAAAYD8AAAAA//8fPwAAAAD//78+AAAAAAAAgD6sqqo+AACAPqyqqj4AAIA+rKqqPgAAgD6sqqo+AACAPquqKj8AAIA+q6oqPwAAgD6rqio/AACAPquqKj8AAAAArKqqPgAAgD+sqqo+AAAAAKyqqj4AAIA/rKqqPgAAAACrqio/AACAP6uqKj8AAAAAq6oqPwAAgD+rqio/AAAAPgAAgD8AAGA/AACAPwAAID8AAIA///+/PgAAgD/Ad0EXnmH//8B3QReeYf//wHdBF55h///Ad0EXnmH//2VH3QcSO///ZUfdBxI7//9lR90HEjv//2VH3QcSO///wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//wGeE07/uv//AZ4TTv+6//8BnhNO/7r//wGeE07/uv//wHdBF55h///Ad0EXnmH//8B3QReeYf//wHdBF55h//9lR90HEjv//2VH3QcSO///ZUfdBxI7//9lR90HEjv//8B3QReeYf//wHdBF55h///Ad0EXnmH//8B3QReeYf//ZUfdBxI7//9lR90HEjv//2VH3QcSO///ZUfdBxI7///PSx0JBj7//89LHQkGPv//z0sdCQY+///PSx0JBj7//yYABgAMAAcAAwALAAcACwAPAAIAEgAIACcADQAaAA4ACgAXAA4AFwAbAAkAEwAWACQAGQAiABgAFAAcABgAHAAgABUAEAAeACUAIwAFACEAHQAAACEAAAAEAB8AEQABADb3yD8AAACzJwErPHkBOj/45io/Gl3gPEddgz8AAACzEMNZvxtfBj9+vCM/HqTvvuaImz4AAACzzba0vzwA0j10ijA/IpJKv3CPO78AAACzO865v1Zsxb42ezU/dx4ivwTyrb8AAACz8p4OvwTyrb8AAACz8p4Ov6l8Nb+KljE/2gRkvql8Nb+KljE/2gRkvou8t78AAACzTIMWPzpZOr+coDI/Ue50PhSPQ78AAACz6H2kP2YG0L6v/Sw/cYAgP5NfrD4AAACz36vDP1u+2z3MX0o/Zwk6Pzvvhj8AAACzOelbPys5CD9FNUM/vIXhPmggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O2ggirxmGnQ/zqH0O1FPKD+Cz0A/W4GtvBpBDT+qJ1U/hCFCvRWfCj9q2TQ/01Xpvtbx6j6eyU4/e229vrg5XD5zSTk/UNcnv2Q5Mj6o91M/EXMIvzr5nL6DmUE/KPcTvxjNi762HVs/ws3gvkr1JL90+zk/6WF0vkr1JL90+zk/6WF0vg1xBr+qM1U/ZhEzvg1xBr+qM1U/ZhEzvkDNH799fT4/56FzPgV/Ar+vr1c/ZCkyPmjps751STo/LssWP0Ylo76mz1I/4U3wPkDRHz53aTs/U78pPy2Rlj26LV0//gX/PiTvET9k3TE/wX3gPtTB6T6vXVc/KDGUPqgB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESvagB1DoA1n8/JAESveQ4Dj+qqqo+5DgOPwAAAACrqio/qqqqPquqKj8AAAAAchxHP6qqqj5yHEc/AAAAADmOYz+qqqo+OY5jPwAAAAAAAIAlqqqqPgAAgD+qqqo+AACAJQAAAAAAAIA/AAAAADmO4z2qqqo+OY7jPQAAAAA5jmM+qqqqPjmOYz4AAAAAq6qqPqqqqj6rqqo+AAAAADmO4z6qqqo+OY7jPgAAAAAAAIAlAAAAADmO4z0AAAAAOY5jPgAAAACrqqo+AAAAADmO4z4AAAAA5DgOPwAAAACrqio/AAAAAHIcRz8AAAAAOY5jPwAAAAAGHF4OUmD//0QfyBpQjf//yBpyCRNO//9EHywahIj//8gacgkTTv//ZhtVDMFY///IGnIJE07//6AgoCB5of//yBpyCRNO///IGnIJE07//6AgoCB5of//oCCgIHmh//9mG8gJOU///6cciBH6av//yBpyCRNO//+gIKAgeaH//wYckQtQVv//pxyXEEBo///IGnIJE07//6AgoCB5of//oCCgIHmh//+gIKAgeaH//6AgoCB5of//oCCgIHmh//+gIKAgeaH//6AgoCB5of//oCCgIHmh//+gIKAgeaH//6AgoCB5of//AAACAAMAAAADAAEAAgAEAAUAAgAFAAMABAAGAAcABAAHAAUABgAJAAsABgALAAcACAAMAA0ACAANAAoADAAOAA8ADAAPAA0ADgAQABEADgARAA8AEAASABMAEAATABEAEgAAAAEAEgABABMADQAPABUACgANABQABwALABwAEwABABgABQAHABsAAwAFABoAAQADABkAEQATABcADwARABYAAAA=" 496 | } 497 | ] 498 | } 499 | -------------------------------------------------------------------------------- /world/crystal/crystal.gltf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | importer_version=1 5 | type="PackedScene" 6 | uid="uid://dj10wq2snt5nf" 7 | path="res://.godot/imported/crystal.gltf-8dfb3168d7d13a85ec2739306bb99624.scn" 8 | 9 | [deps] 10 | 11 | source_file="res://world/crystal/crystal.gltf" 12 | dest_files=["res://.godot/imported/crystal.gltf-8dfb3168d7d13a85ec2739306bb99624.scn"] 13 | 14 | [params] 15 | 16 | nodes/root_type="Spatial" 17 | nodes/root_name="Scene Root" 18 | nodes/apply_root_scale=true 19 | nodes/root_scale=1.0 20 | meshes/ensure_tangents=true 21 | meshes/generate_lods=true 22 | meshes/create_shadow_meshes=true 23 | meshes/light_baking=0 24 | meshes/lightmap_texel_size=0.1 25 | skins/use_named_skins=true 26 | animation/import=true 27 | animation/fps=15 28 | animation/trimming=false 29 | animation/remove_immutable_tracks=true 30 | import_script/path="" 31 | _subresources={} 32 | gltf/embedded_image_handling=1 33 | -------------------------------------------------------------------------------- /world/crystal/crystal_ground_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://t5h4im7t6mey"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit.gdshader" id="1_g7naa"] 4 | 5 | [resource] 6 | render_priority = 0 7 | shader = ExtResource("1_g7naa") 8 | shader_parameter/precision_multiplier = 1.0 9 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 10 | shader_parameter/uv_scale = Vector2(1, 1) 11 | shader_parameter/uv_offset = Vector2(0, 0) 12 | shader_parameter/uv_pan_velocity = Vector2(0, 0) 13 | -------------------------------------------------------------------------------- /world/crystal/crystal_mesh.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://k0jtpj0fkkrv"] 2 | 3 | [ext_resource type="Material" uid="uid://hy0eu287pcxj" path="res://world/crystal/crystal_spire_mat.tres" id="1"] 4 | [ext_resource type="Material" uid="uid://t5h4im7t6mey" path="res://world/crystal/crystal_ground_mat.tres" id="2"] 5 | [ext_resource type="PackedScene" uid="uid://dj10wq2snt5nf" path="res://world/crystal/crystal.gltf" id="3"] 6 | 7 | [node name="crystal" instance=ExtResource("3")] 8 | 9 | [node name="Ground" parent="." index="0"] 10 | surface_material_override/0 = ExtResource("2") 11 | 12 | [node name="Spire_1" parent="Ground" index="0"] 13 | surface_material_override/0 = ExtResource("1") 14 | 15 | [node name="Spire_2" parent="Ground" index="1"] 16 | transform = Transform3D(-0.223364, -0.132712, 0.884556, -0.242743, 1.90228, -1.36255e-08, -0.852817, -0.5067, -0.231677, 0, 0, 0) 17 | surface_material_override/0 = ExtResource("1") 18 | 19 | [node name="Spire_3" parent="Ground" index="2"] 20 | transform = Transform3D(-0.689533, -0.463782, -0.375407, -0.214429, 1.90228, 3.00904e-09, 0.361937, 0.24344, -0.715194, 0, 0, 0) 21 | surface_material_override/0 = ExtResource("1") 22 | 23 | [node name="Spire_4" parent="Ground" index="3"] 24 | surface_material_override/0 = ExtResource("1") 25 | -------------------------------------------------------------------------------- /world/crystal/crystal_spire_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://hy0eu287pcxj"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit.gdshader" id="1_l8lje"] 4 | 5 | [resource] 6 | render_priority = 0 7 | shader = ExtResource("1_l8lje") 8 | shader_parameter/precision_multiplier = 1.0 9 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 10 | shader_parameter/uv_scale = Vector2(1, 1) 11 | shader_parameter/uv_offset = Vector2(0, 0) 12 | shader_parameter/uv_pan_velocity = Vector2(0, 0) 13 | -------------------------------------------------------------------------------- /world/floor/floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/floor/floor.png -------------------------------------------------------------------------------- /world/floor/floor.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cfkqnvjfxouop" 6 | path.s3tc="res://.godot/imported/floor.png-07bd8a5d1a5a27111249edcc10f8f960.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/floor/floor.png" 15 | dest_files=["res://.godot/imported/floor.png-07bd8a5d1a5a27111249edcc10f8f960.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /world/floor/floor.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit.gdshader" id="1_p7lw4"] 4 | [ext_resource type="Texture2D" uid="uid://cfkqnvjfxouop" path="res://world/floor/floor.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1_p7lw4") 9 | shader_parameter/precision_multiplier = 1.0 10 | shader_parameter/modulate_color = Color(0.66, 0.7, 0.8, 1) 11 | shader_parameter/uv_scale = Vector2(24, 24) 12 | shader_parameter/uv_offset = Vector2(0, 0) 13 | shader_parameter/uv_pan_velocity = Vector2(0, 0) 14 | shader_parameter/albedoTex = ExtResource("2") 15 | -------------------------------------------------------------------------------- /world/light-shaft/light-shaft.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/light-shaft/light-shaft.glb -------------------------------------------------------------------------------- /world/light-shaft/light-shaft.glb.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | importer_version=1 5 | type="PackedScene" 6 | uid="uid://kaf86vv454ad" 7 | path="res://.godot/imported/light-shaft.glb-3eefedf28240fddebd854e35e64981c2.scn" 8 | 9 | [deps] 10 | 11 | source_file="res://world/light-shaft/light-shaft.glb" 12 | dest_files=["res://.godot/imported/light-shaft.glb-3eefedf28240fddebd854e35e64981c2.scn"] 13 | 14 | [params] 15 | 16 | nodes/root_type="Node3D" 17 | nodes/root_name="Scene Root" 18 | nodes/apply_root_scale=true 19 | nodes/root_scale=1.0 20 | meshes/ensure_tangents=true 21 | meshes/generate_lods=true 22 | meshes/create_shadow_meshes=true 23 | meshes/light_baking=1 24 | meshes/lightmap_texel_size=0.2 25 | skins/use_named_skins=true 26 | animation/import=true 27 | animation/fps=30 28 | animation/trimming=false 29 | animation/remove_immutable_tracks=true 30 | import_script/path="" 31 | _subresources={ 32 | "meshes": { 33 | "light-shaft_Cube": { 34 | "generate/lightmap_uv": 0, 35 | "generate/lods": 0, 36 | "generate/shadow_meshes": 0, 37 | "lods/normal_merge_angle": 60.0, 38 | "lods/normal_split_angle": 25.0, 39 | "save_to_file/enabled": true, 40 | "save_to_file/make_streamable": "", 41 | "save_to_file/path": "res://world/light-shaft_mesh.res" 42 | } 43 | } 44 | } 45 | gltf/embedded_image_handling=1 46 | -------------------------------------------------------------------------------- /world/light-shaft/light-shaft_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://cg1031m8scq7b"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_light-volume.gdshader" id="1_5xlul"] 4 | 5 | [resource] 6 | render_priority = 0 7 | shader = ExtResource("1_5xlul") 8 | shader_parameter/precision_multiplier = 1.0 9 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 10 | -------------------------------------------------------------------------------- /world/light-shaft/light-shaft_mesh.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/light-shaft/light-shaft_mesh.res -------------------------------------------------------------------------------- /world/orbit_camera.gd: -------------------------------------------------------------------------------- 1 | extends Node3D 2 | 3 | const ROTATION_SPEED := 1.0 4 | 5 | var _time = 0.0 6 | 7 | @onready var _default_y_rotation: float = rotation.y 8 | 9 | 10 | func _process(p_delta: float): 11 | self._time += p_delta 12 | self.rotation.y = self._default_y_rotation + self._time * ROTATION_SPEED 13 | 14 | 15 | func restart(): 16 | self.rotation.y = self._default_y_rotation 17 | self._time = 0.0 18 | -------------------------------------------------------------------------------- /world/scene_controls.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | signal pause 4 | signal reset 5 | 6 | const PAUSE_ACTION := "ui_accept" 7 | const RESET_ACTION := "reset_camera_position" 8 | 9 | var _is_paused := false : 10 | set (value): 11 | _is_paused = value 12 | emit_signal("pause", !value) 13 | 14 | @onready var _viewport := get_viewport() 15 | 16 | 17 | func _ready(): 18 | for node in get_tree().get_nodes_in_group("can_pause"): 19 | pause.connect(node.set_process.bind()) 20 | 21 | for node in get_tree().get_nodes_in_group("can_restart"): 22 | assert(node.has_method("restart")) 23 | reset.connect(node.restart.bind()) 24 | 25 | 26 | func _unhandled_input(event: InputEvent): 27 | if event.is_action_pressed(PAUSE_ACTION): 28 | self._is_paused = !self._is_paused 29 | 30 | elif event.is_action_pressed(RESET_ACTION): 31 | emit_signal("reset") 32 | 33 | self._viewport.set_input_as_handled() 34 | 35 | -------------------------------------------------------------------------------- /world/shadow/shadow.gd: -------------------------------------------------------------------------------- 1 | extends Node3D 2 | 3 | const SpatialSinPan := preload("res://world/spatial_sin_pan.gd") 4 | 5 | const SCALE_DISTANCE := 0.125 6 | const DEFAULT_SCALE := Vector3.ONE * 0.775 7 | 8 | @export var _reverse_direction := false 9 | 10 | var _time := 0.0 11 | 12 | 13 | func _ready(): 14 | self.scale = DEFAULT_SCALE 15 | 16 | 17 | func _process(p_delta: float): 18 | self._time += p_delta 19 | self.scale = get_animated_scale(self._time, self._reverse_direction) 20 | 21 | 22 | func restart(): 23 | self.scale = DEFAULT_SCALE 24 | self._time = 0.0 25 | 26 | 27 | static func get_animated_scale(p_time: float, p_reverse_direction: bool) -> Vector3: 28 | var direction := 1 if p_reverse_direction else -1 29 | var offset_scale := ( 30 | sin(p_time * SpatialSinPan.TRANSLATION_SPEED) 31 | * Vector3.ONE 32 | * SCALE_DISTANCE 33 | * direction 34 | ) 35 | return DEFAULT_SCALE + offset_scale 36 | -------------------------------------------------------------------------------- /world/shadow/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/shadow/shadow.png -------------------------------------------------------------------------------- /world/shadow/shadow.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bowydeerhw2np" 6 | path.s3tc="res://.godot/imported/shadow.png-aaa4c8bbbed404566471584113127456.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/shadow/shadow.png" 15 | dest_files=["res://.godot/imported/shadow.png-aaa4c8bbbed404566471584113127456.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /world/shadow/shadow.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://world/shadow/shadow_mat.tres" type="Material" id=1] 4 | [ext_resource path="res://world/shadow/shadow.gd" type="Script" id=2] 5 | 6 | [sub_resource type="PlaneMesh" id=1] 7 | material = ExtResource( 1 ) 8 | subdivide_width = 1 9 | subdivide_depth = 1 10 | 11 | [node name="BoxShadow" type="Spatial" groups=["can_pause", "can_restart"]] 12 | transform = Transform( 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0 ) 13 | script = ExtResource( 2 ) 14 | 15 | [node name="MeshInstance" type="MeshInstance" parent="."] 16 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0 ) 17 | mesh = SubResource( 1 ) 18 | -------------------------------------------------------------------------------- /world/shadow/shadow_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://07vktneusbih"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_lit_transparent.gdshader" id="1_ehms2"] 4 | [ext_resource type="Texture2D" uid="uid://bowydeerhw2np" path="res://world/shadow/shadow.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1_ehms2") 9 | shader_parameter/precision_multiplier = 1.0 10 | shader_parameter/modulate_color = Color(1, 1, 1, 0.78) 11 | shader_parameter/uv_scale = Vector2(1, 1) 12 | shader_parameter/uv_offset = Vector2(0, 0) 13 | shader_parameter/uv_pan_velocity = Vector2(0, 0) 14 | shader_parameter/albedoTex = ExtResource("2") 15 | -------------------------------------------------------------------------------- /world/sparkle/sparkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-psx-style-demo/91bd24988f70636efca505e2c8022b143b61780e/world/sparkle/sparkle.png -------------------------------------------------------------------------------- /world/sparkle/sparkle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://ced14kbpfucnc" 6 | path.s3tc="res://.godot/imported/sparkle.png-a44d792a2cf02faf7c0ab6a16970750c.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/sparkle/sparkle.png" 15 | dest_files=["res://.godot/imported/sparkle.png-a44d792a2cf02faf7c0ab6a16970750c.s3tc.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=true 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=0 36 | -------------------------------------------------------------------------------- /world/sparkle/sparkle_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://0828pxpypo6k"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/psx_unlit_alpha-scissor.gdshader" id="1_0hjis"] 4 | [ext_resource type="Texture2D" uid="uid://ced14kbpfucnc" path="res://world/sparkle/sparkle.png" id="2_oqpum"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1_0hjis") 9 | shader_parameter/precision_multiplier = 1.0 10 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 11 | shader_parameter/uv_scale = Vector2(1, 1) 12 | shader_parameter/uv_offset = Vector2(0, 0) 13 | shader_parameter/billboard = true 14 | shader_parameter/y_billboard = false 15 | shader_parameter/alpha_scissor = 0.1 16 | shader_parameter/albedoTex = ExtResource("2_oqpum") 17 | -------------------------------------------------------------------------------- /world/sparkle/sparkle_particle-process_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ParticleProcessMaterial" format=3 uid="uid://6l26m1a5na2u"] 2 | 3 | [resource] 4 | direction = Vector3(1, 1, 1) 5 | spread = 180.0 6 | gravity = Vector3(0, 0, 0) 7 | initial_velocity_min = 2.0 8 | initial_velocity_max = 2.0 9 | attractor_interaction_enabled = false 10 | -------------------------------------------------------------------------------- /world/spatial_sin_pan.gd: -------------------------------------------------------------------------------- 1 | extends Node3D 2 | 3 | const TRANSLATION_DISTANCE := 1.0 4 | const TRANSLATION_SPEED := 1.0 5 | const ROTATION_SPEED := 1.0 6 | 7 | @export var _reverse_direction := false 8 | 9 | var _time := 0.0 10 | 11 | @onready var _default_transform: Transform3D = get_transform() 12 | 13 | 14 | func _process(p_delta: float): 15 | self._time += p_delta 16 | self.transform = get_animated_transform( 17 | self._default_transform, self._time, self._reverse_direction 18 | ) 19 | 20 | 21 | func restart(): 22 | set_transform(self._default_transform) 23 | self._time = 0 24 | 25 | 26 | static func get_animated_transform( 27 | p_default_transform: Transform3D, p_time: float, p_reverse_direction: bool 28 | ) -> Transform3D: 29 | var rotation = Vector3.ONE * p_time * ROTATION_SPEED 30 | var translation_direction := -1 if p_reverse_direction else 1 31 | var y_pos := sin(p_time * TRANSLATION_SPEED) * TRANSLATION_DISTANCE * translation_direction 32 | var offset_transform := Transform3D(Basis.from_euler(rotation), Vector3.UP * y_pos) 33 | return p_default_transform * offset_transform 34 | -------------------------------------------------------------------------------- /world/world.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=18 format=3 uid="uid://c1xno4bm2dlyj"] 2 | 3 | [ext_resource type="Script" path="res://world/orbit_camera.gd" id="1"] 4 | [ext_resource type="Material" uid="uid://cg1031m8scq7b" path="res://world/light-shaft/light-shaft_mat.tres" id="2"] 5 | [ext_resource type="Script" path="res://world/spatial_sin_pan.gd" id="3"] 6 | [ext_resource type="Material" path="res://world/floor/floor.tres" id="4"] 7 | [ext_resource type="ArrayMesh" uid="uid://dcm073t81n4p0" path="res://world/light-shaft/light-shaft_mesh.res" id="5_4haum"] 8 | [ext_resource type="PackedScene" path="res://world/shadow/shadow.tscn" id="6"] 9 | [ext_resource type="ArrayMesh" uid="uid://cd1odanjyg1jw" path="res://world/box_lit/box.obj" id="8"] 10 | [ext_resource type="Material" path="res://world/box_metal/box-metal_mat.tres" id="8_yroyl"] 11 | [ext_resource type="Material" uid="uid://6l26m1a5na2u" path="res://world/sparkle/sparkle_particle-process_mat.tres" id="10_rc0nk"] 12 | [ext_resource type="PackedScene" uid="uid://k0jtpj0fkkrv" path="res://world/crystal/crystal_mesh.tscn" id="11"] 13 | [ext_resource type="Material" uid="uid://0828pxpypo6k" path="res://world/sparkle/sparkle_mat.tres" id="11_rf0vm"] 14 | [ext_resource type="ArrayMesh" uid="uid://cbvn8fwufde7c" path="res://world/box_metal/bevel-box.obj" id="12"] 15 | [ext_resource type="Material" uid="uid://duageqxj0x4k1" path="res://world/box_lit/box-lit_mat.tres" id="12_e4oia"] 16 | [ext_resource type="Script" path="res://world/scene_controls.gd" id="14"] 17 | [ext_resource type="Environment" uid="uid://55j275wwndlp" path="res://world/world_env.tres" id="15"] 18 | 19 | [sub_resource type="BoxMesh" id="5"] 20 | material = ExtResource("4") 21 | flip_faces = true 22 | size = Vector3(40, 40, 40) 23 | subdivide_width = 25 24 | subdivide_height = 25 25 | subdivide_depth = 25 26 | 27 | [sub_resource type="QuadMesh" id="2"] 28 | material = ExtResource("11_rf0vm") 29 | size = Vector2(0.3, 0.3) 30 | 31 | [node name="World" type="Node3D"] 32 | 33 | [node name="SceneControls" type="Node" parent="."] 34 | script = ExtResource("14") 35 | 36 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."] 37 | environment = ExtResource("15") 38 | 39 | [node name="OrbitPoint" type="Node3D" parent="." groups=["can_pause", "can_restart"]] 40 | transform = Transform3D(0.831023, 0, -0.556238, 0, 1, 0, 0.556238, 0, 0.831023, 0, -2.38419e-07, -4.76837e-07) 41 | script = ExtResource("1") 42 | 43 | [node name="Camera" type="Camera3D" parent="OrbitPoint"] 44 | transform = Transform3D(1, 0, 0, 0, 0.989078, 0.147395, 0, -0.147395, 0.989078, 0, 2.147, 4.48151) 45 | fov = 68.1243 46 | 47 | [node name="DirectionalLight" type="DirectionalLight3D" parent="OrbitPoint"] 48 | transform = Transform3D(0.999229, -0.0247207, 0.0305003, 0, 0.776871, 0.629659, -0.0392604, -0.629174, 0.776272, 5.08833, 2.79045, -0.311581) 49 | light_energy = 1.5 50 | 51 | [node name="Background" type="MeshInstance3D" parent="."] 52 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 20, 0) 53 | mesh = SubResource("5") 54 | 55 | [node name="LightShaft" type="MeshInstance3D" parent="."] 56 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0109267, 2.05731, 0.0147681) 57 | mesh = ExtResource("5_4haum") 58 | skeleton = NodePath("") 59 | surface_material_override/0 = ExtResource("2") 60 | 61 | [node name="BoxMetal" type="MeshInstance3D" parent="." groups=["can_pause", "can_restart"]] 62 | transform = Transform3D(0.613118, 0, 0, 0, 0.613118, 0, 0, 0, 0.613118, -1, 2.236, 0) 63 | mesh = ExtResource("12") 64 | surface_material_override/0 = ExtResource("8_yroyl") 65 | script = ExtResource("3") 66 | 67 | [node name="Particles" type="GPUParticles3D" parent="BoxMetal" groups=["can_restart"]] 68 | fixed_fps = 15 69 | interpolate = false 70 | process_material = ExtResource("10_rc0nk") 71 | draw_pass_1 = SubResource("2") 72 | 73 | [node name="BoxMetalShadow" parent="." instance=ExtResource("6")] 74 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0) 75 | 76 | [node name="BoxLit" type="MeshInstance3D" parent="." groups=["can_pause", "can_restart"]] 77 | transform = Transform3D(0.613118, 0, 0, 0, 0.613118, 0, 0, 0, 0.613118, 1, 2.236, 0) 78 | mesh = ExtResource("8") 79 | surface_material_override/0 = ExtResource("12_e4oia") 80 | script = ExtResource("3") 81 | _reverse_direction = true 82 | 83 | [node name="BoxLitShadow" parent="." instance=ExtResource("6")] 84 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0) 85 | _reverse_direction = true 86 | 87 | [node name="OmniLight" type="OmniLight3D" parent="."] 88 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4, 0.784, 0) 89 | light_color = Color(0.909804, 0.803922, 0.666667, 1) 90 | light_energy = 4.75 91 | omni_range = 3.0 92 | omni_attenuation = 0.0915055 93 | 94 | [node name="OmniLight2" type="OmniLight3D" parent="."] 95 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0.784, 0) 96 | light_color = Color(0.909804, 0.803922, 0.666667, 1) 97 | light_energy = 4.75 98 | omni_range = 3.0 99 | omni_attenuation = 0.0915055 100 | 101 | [node name="crystal" parent="." instance=ExtResource("11")] 102 | transform = Transform3D(0.719146, 0, 0.694859, 0, 1, 0, -0.694859, 0, 0.719146, 1.93081, 0, 1.34372) 103 | 104 | [node name="crystal2" parent="." instance=ExtResource("11")] 105 | transform = Transform3D(0.826285, 0, -0.563252, 0, 1, 0, 0.563252, 0, 0.826285, -1.32247, 0, 1.77809) 106 | 107 | [node name="crystal3" parent="." instance=ExtResource("11")] 108 | transform = Transform3D(0.864371, 0, 0.502854, 0, 1, 0, -0.502854, 0, 0.864371, -2.32825, 0, -0.999177) 109 | 110 | [node name="crystal4" parent="." instance=ExtResource("11")] 111 | transform = Transform3D(-0.632935, 0, 0.774205, 0, 1, 0, -0.774205, 0, -0.632935, 2.30476, 0, -1.16371) 112 | 113 | [node name="crystal5" parent="." instance=ExtResource("11")] 114 | transform = Transform3D(-0.90227, 0, -0.431172, 0, 1, 0, 0.431172, 0, -0.90227, -0.00271803, 0, -1.98459) 115 | -------------------------------------------------------------------------------- /world/world_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" format=3 uid="uid://55j275wwndlp"] 2 | 3 | [resource] 4 | background_mode = 1 5 | background_color = Color(0.670588, 0.760784, 1, 0.960784) 6 | ambient_light_source = 2 7 | ambient_light_color = Color(1, 0.67451, 0.988235, 1) 8 | ambient_light_energy = 0.15 9 | reflected_light_source = 1 10 | fog_enabled = true 11 | fog_light_color = Color(0.670588, 0.760784, 1, 1) 12 | fog_density = 0.05 13 | --------------------------------------------------------------------------------