├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── export_presets.cfg ├── gui ├── font │ ├── OFL.txt │ ├── Oswald-Bold.ttf │ └── Oswald-Bold.ttf.import └── value_label.gd ├── icon.png ├── icon.png.import ├── main.tscn ├── post-process ├── pp_dither-band.tres └── pp_h-blur.tres ├── project.godot ├── readme-assets ├── .gdignore └── screenshot.png ├── shaders ├── gaussian-blur.gdshader ├── light-volume.gdshader ├── n64_base.gdshaderinc ├── n64_lit.gdshader ├── n64_lit_metal.gdshader ├── n64_lit_transparent.gdshader ├── n64_unlit_particle.gdshader ├── pp_band-dither.gdshader ├── psxdither.png └── psxdither.png.import └── world ├── box ├── bevel-box.obj ├── bevel-box.obj.import ├── metal_tex.png ├── metal_tex.png.import ├── object_metal_mat.tres ├── sparkle.png ├── sparkle.png.import ├── sparkle_mat.tres └── spatial_sin_pan.gd ├── 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 └── floor.tscn ├── light-shaft ├── light-shaft.gltf ├── light-shaft.gltf.import ├── light-shaft_Mesh.mesh └── light-shaft_mat.tres ├── orbit_camera.gd ├── scene_controls.gd ├── shadow ├── shadow.gd ├── shadow.png ├── shadow.png.import ├── shadow.tscn └── shadow_mat.tres ├── stairs ├── stairs.gltf ├── stairs.gltf.import ├── stairs_Mesh.mesh ├── stairs_side.png ├── stairs_side.png.import ├── stairs_side_mat.tres ├── stairs_top.png ├── stairs_top.png.import └── stairs_top_mat.tres ├── 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/linux/linux/* 31 | - name: upload windows artifact 32 | uses: actions/upload-artifact@v3 33 | with: 34 | name: windows 35 | path: build/windows/windows/* 36 | - name: upload html5 artifact 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: html5 40 | path: build/html5/html5/* 41 | 42 | deploy-itch: 43 | if: github.repository == 'MenacingMecha/godot-n64-shader-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-n64-shader-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 | export.cfg 11 | export_presets.cfg 12 | .godot/ 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 N64 Style Demo 2 | 3 | ![Godot Version](https://img.shields.io/badge/godot-v4.0-blue) 4 | [![License](https://img.shields.io/github/license/MenacingMecha/godot-n64-shader-demo)](https://github.com/MenacingMecha/godot-n64-shader-demo/blob/master/LICENSE) 5 | 6 | [Play demo in browser!](https://menacingmecha.itch.io/godot-n64-shader-demo) 7 | 8 | A collection of shaders and materials for Godot engine that aim to recreate the aesthetics and quirks of the N64 9 | 10 | ![Example Screenshot](./readme-assets/screenshot.png) 11 | 12 | ## Features 13 | 14 | - 3-point texture filtering 15 | - Light anti-aliasing 16 | - Linear mip-map filtering 17 | - Horizontal blur across the screen 18 | - Limited color depth 19 | - Hardware dithering to hide color banding 20 | - Shiny chrome-like metallic surfaces 21 | - Billboard sprites 22 | - Fog to limit draw distance 23 | 24 | ## Demo Controls 25 | 26 | - Space: Toggle camera and object movement 27 | - R: Reset scene 28 | 29 | ## Tips for best results 30 | 31 | - Use very low poly models 32 | - Prefer smooth-shading over flat-shading wherever possible 33 | - Keep textures as low resolution as humanly possible 34 | - Huge blurry texels are the cornerstone of the N64 look 35 | - Rely on a mix of vertex colours and texture maps, instead of higher detailed texture maps wherever possible 36 | - Keep your internal resolution low 37 | - Resolution on N64 is a complicated affair. While the system would output to video at certain specific resolutions, games themselves would have their own separate internal resolutions 38 | - These internal resolutions could vary wildly between games, but 320x240 seems to be the most common choice 39 | - That being said, you can easily go widescreen by using a 16:9 resolution with similar height 40 | - Use as basic of a lighting set up as you can get away with 41 | - Modern lighting techniques are a very easy way to break the illusion of appearing like early 3D! 42 | - Where possible, prefer to use white ambient light, with vertex colours on geometry to fake lighting 43 | - Prefer additive blending to transparent blending 44 | 45 | ## Changes from v1.x 46 | 47 | ### Major version change 48 | This version is for Godot 4.x only. 49 | Please refer to the v1.x branch for Godot 3.x support. 50 | 51 | ### Fog 52 | 53 | Godot 4.0 changed how environmental fog worked, the key part being the removal of the "start distance" and "end distance" properties. 54 | While a manual workaround could be implemented, there is work being done to restore this functionality in a later version. 55 | 56 | ### Runtime options 57 | 58 | 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. 59 | 60 | ## Credits 61 | 62 | Floor texture (available under CC-0): https://stealthix.itch.io/rpg-nature-tileset 63 | -------------------------------------------------------------------------------- /export_presets.cfg: -------------------------------------------------------------------------------- 1 | [preset.0] 2 | 3 | name="linux" 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, readme-assets/*" 11 | export_path="build/linux/n64-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" 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, readme-assets/*" 52 | export_path="build/windows/n64-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="html5" 111 | platform="Web" 112 | runnable=true 113 | dedicated_server=false 114 | custom_features="" 115 | export_filter="all_resources" 116 | include_filter="" 117 | exclude_filter="" 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 | -------------------------------------------------------------------------------- /gui/font/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /gui/font/Oswald-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/gui/font/Oswald-Bold.ttf -------------------------------------------------------------------------------- /gui/font/Oswald-Bold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://dc4mm784qpajc" 6 | path="res://.godot/imported/Oswald-Bold.ttf-a3bc353329b0b7c60368ac560b94456a.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://gui/font/Oswald-Bold.ttf" 11 | dest_files=["res://.godot/imported/Oswald-Bold.ttf-a3bc353329b0b7c60368ac560b94456a.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=2 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[{ 31 | "chars": [], 32 | "glyphs": [], 33 | "name": "New Configuration", 34 | "size": Vector2i(16, 0), 35 | "variation_embolden": 0.0 36 | }] 37 | language_support={} 38 | script_support={} 39 | opentype_features={} 40 | -------------------------------------------------------------------------------- /gui/value_label.gd: -------------------------------------------------------------------------------- 1 | extends Label 2 | 3 | func set_text_from_value(value: float, pad_zero_forward := true): 4 | set_text(("%02d" if pad_zero_forward else "%02.2f") % value) 5 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/icon.png -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://xodxuegstnmx" 6 | path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.png" 14 | dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://dp26i51kj0tvp"] 2 | 3 | [ext_resource type="FontFile" uid="uid://dc4mm784qpajc" path="res://gui/font/Oswald-Bold.ttf" id="1"] 4 | [ext_resource type="Material" uid="uid://c8e7ck31g8wbs" path="res://post-process/pp_dither-band.tres" id="2"] 5 | [ext_resource type="PackedScene" uid="uid://dcy86n4si7d7v" path="res://world/world.tscn" id="4"] 6 | [ext_resource type="Material" uid="uid://j8bsdv5386ih" path="res://post-process/pp_h-blur.tres" id="6"] 7 | 8 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_f8ke5"] 9 | bg_color = Color(0.494118, 0.270588, 0.529412, 1) 10 | corner_radius_top_left = 5 11 | corner_radius_top_right = 5 12 | corner_radius_bottom_right = 5 13 | corner_radius_bottom_left = 5 14 | 15 | [sub_resource type="FontVariation" id="FontVariation_j0k5a"] 16 | base_font = ExtResource("1") 17 | spacing_glyph = 2 18 | 19 | [node name="Main" type="Node"] 20 | 21 | [node name="N64Layer" type="CanvasLayer" parent="."] 22 | layer = 0 23 | 24 | [node name="HBlur" type="SubViewportContainer" parent="N64Layer"] 25 | texture_filter = 1 26 | material = ExtResource("6") 27 | anchors_preset = 15 28 | anchor_right = 1.0 29 | anchor_bottom = 1.0 30 | mouse_filter = 2 31 | stretch = true 32 | stretch_shrink = 3 33 | 34 | [node name="SubViewport" type="SubViewport" parent="N64Layer/HBlur"] 35 | handle_input_locally = false 36 | canvas_item_default_texture_filter = 0 37 | size = Vector2i(320, 240) 38 | render_target_update_mode = 4 39 | 40 | [node name="DitherBand" type="SubViewportContainer" parent="N64Layer/HBlur/SubViewport"] 41 | material = ExtResource("2") 42 | anchors_preset = 15 43 | anchor_right = 1.0 44 | anchor_bottom = 1.0 45 | mouse_filter = 2 46 | stretch = true 47 | 48 | [node name="SubViewport" type="SubViewport" parent="N64Layer/HBlur/SubViewport/DitherBand"] 49 | handle_input_locally = false 50 | msaa_3d = 1 51 | canvas_item_default_texture_filter = 0 52 | audio_listener_enable_2d = true 53 | audio_listener_enable_3d = true 54 | size = Vector2i(320, 240) 55 | render_target_update_mode = 4 56 | 57 | [node name="World" parent="N64Layer/HBlur/SubViewport/DitherBand/SubViewport" instance=ExtResource("4")] 58 | 59 | [node name="Panel" type="Panel" parent="N64Layer/HBlur/SubViewport/DitherBand/SubViewport"] 60 | anchors_preset = -1 61 | anchor_left = 0.803 62 | anchor_top = 0.839 63 | anchor_right = 0.86 64 | anchor_bottom = 0.892 65 | offset_right = 40.0 66 | offset_bottom = 20.0 67 | theme_override_styles/panel = SubResource("StyleBoxFlat_f8ke5") 68 | 69 | [node name="Label" type="Label" parent="N64Layer/HBlur/SubViewport/DitherBand/SubViewport/Panel"] 70 | layout_mode = 0 71 | anchor_right = 1.0 72 | anchor_bottom = 1.0 73 | size_flags_horizontal = 4 74 | theme_override_fonts/font = SubResource("FontVariation_j0k5a") 75 | text = "TEXT" 76 | horizontal_alignment = 1 77 | vertical_alignment = 1 78 | -------------------------------------------------------------------------------- /post-process/pp_dither-band.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://c8e7ck31g8wbs"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/pp_band-dither.gdshader" id="1"] 4 | [ext_resource type="Texture2D" uid="uid://b6kcbughmhco" path="res://shaders/psxdither.png" id="2"] 5 | 6 | [resource] 7 | shader = ExtResource("1") 8 | shader_parameter/col_depth = 24.0 9 | shader_parameter/dither_banding = true 10 | shader_parameter/enabled = true 11 | shader_parameter/dither_tex = ExtResource("2") 12 | -------------------------------------------------------------------------------- /post-process/pp_h-blur.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://j8bsdv5386ih"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/gaussian-blur.gdshader" id="1"] 4 | 5 | [resource] 6 | shader = ExtResource("1") 7 | shader_parameter/h = 1.0 8 | shader_parameter/v = 0.0 9 | shader_parameter/enabled = true 10 | -------------------------------------------------------------------------------- /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 N64 Shader Demo" 14 | config/description="Demo project featuring a collection of N64 style shaders and materials for Godot engine. 15 | (MIT License) 16 | https://github.com/MenacingMecha/godot-n64-shader-demo/" 17 | run/main_scene="res://main.tscn" 18 | config/features=PackedStringArray("4.0") 19 | run/max_fps=24 20 | 21 | [display] 22 | 23 | window/size/viewport_width=960 24 | window/size/viewport_height=720 25 | window/stretch/mode="viewport" 26 | window/vsync/vsync_mode=0 27 | 28 | [importer_defaults] 29 | 30 | texture={ 31 | "compress/bptc_ldr": 0, 32 | "compress/hdr_mode": 0, 33 | "compress/lossy_quality": 0.7, 34 | "compress/mode": 0, 35 | "compress/normal_map": 0, 36 | "detect_3d": false, 37 | "flags/anisotropic": false, 38 | "flags/filter": false, 39 | "flags/mipmaps": false, 40 | "flags/repeat": 1, 41 | "flags/srgb": 2, 42 | "process/HDR_as_SRGB": false, 43 | "process/fix_alpha_border": true, 44 | "process/invert_color": false, 45 | "process/premult_alpha": false, 46 | "size_limit": 0, 47 | "stream": false, 48 | "svg/scale": 1.0 49 | } 50 | 51 | [input] 52 | 53 | kb_1={ 54 | "deadzone": 0.5, 55 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"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":0,"echo":false,"script":null) 56 | ] 57 | } 58 | kb_2={ 59 | "deadzone": 0.5, 60 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"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":0,"echo":false,"script":null) 61 | ] 62 | } 63 | reset_camera_position={ 64 | "deadzone": 0.5, 65 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"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":0,"echo":false,"script":null) 66 | ] 67 | } 68 | kb_3={ 69 | "deadzone": 0.5, 70 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":51,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) 71 | ] 72 | } 73 | 74 | [rendering] 75 | 76 | shading/overrides/force_vertex_shading=true 77 | shading/overrides/force_lambert_over_burley=true 78 | vram_compression/import_etc=true 79 | quality/reflections/high_quality_ggx=false 80 | shading/overrides/force_blinn_over_ggx=true 81 | quality/subsurface_scattering/quality=0 82 | quality/subsurface_scattering/weight_samples=false 83 | quality/filters/msaa=1 84 | -------------------------------------------------------------------------------- /readme-assets/.gdignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/readme-assets/.gdignore -------------------------------------------------------------------------------- /readme-assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/readme-assets/screenshot.png -------------------------------------------------------------------------------- /shaders/gaussian-blur.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform float h = 1; 4 | uniform float v = 0; 5 | uniform bool enabled = true; 6 | 7 | void fragment() 8 | { 9 | // float kernel[] = {0.06136, 0.24477, 0.38774, 0.24477, 0.06136}; 10 | float kernel[] = {0.31946576033846985, 0.3610684793230603, 0.31946576033846985}; 11 | vec2 px = TEXTURE_PIXEL_SIZE; 12 | vec4 col = vec4(0); 13 | 14 | if (enabled) 15 | { 16 | for (int i = 0; i < kernel.length(); i++) 17 | { 18 | // int radius = (kernel.length() - 1) / 2; // This is wrong for some reason? 19 | int radius = 1; 20 | int distance = i - radius; 21 | col += texture(TEXTURE, UV + px * vec2(h * float(distance), v * float(distance))) * kernel[i]; 22 | } 23 | COLOR = col; 24 | } 25 | else 26 | { 27 | COLOR = texture(TEXTURE, UV); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shaders/light-volume.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | render_mode unshaded, shadows_disabled, blend_add, depth_draw_opaque, cull_disabled; 3 | 4 | void fragment() 5 | { 6 | ALBEDO = COLOR.rgb; 7 | ALPHA = 1.0 - UV.y; 8 | } 9 | -------------------------------------------------------------------------------- /shaders/n64_base.gdshaderinc: -------------------------------------------------------------------------------- 1 | render_mode LIT, cull_disabled, shadows_disabled, specular_disabled, DEPTH, BLEND; 2 | 3 | uniform vec4 modulate_color : source_color = vec4(1.0); 4 | 5 | #ifndef NO_TEXTURE 6 | uniform sampler2D albedoTex : source_color, filter_nearest, repeat_enable; 7 | #endif 8 | 9 | #if !defined(NO_TEXTURE) && !defined(METAL) // METAL doesn't use UV, so no need for panning properties 10 | uniform vec2 uv_scale = vec2(1.0, 1.0); 11 | uniform vec2 uv_offset = vec2(.0, .0); 12 | uniform vec2 uv_pan_velocity = vec2(0.0); 13 | #endif 14 | 15 | #ifdef ALPHA_SCISSOR 16 | uniform bool billboard = false; 17 | uniform bool y_billboard = false; 18 | uniform float alpha_scissor : hint_range(0, 1) = 0.1; 19 | #endif 20 | 21 | // https://www.emutalk.net/threads/emulating-nintendo-64-3-sample-bilinear-filtering-using-shaders.54215/ 22 | vec4 n64BilinearFilter(vec4 vtx_color, vec2 texcoord) { 23 | ivec2 tex_size = textureSize(albedoTex, 0); 24 | float Texture_X = float(tex_size.x); 25 | float Texture_Y = float(tex_size.y); 26 | 27 | vec2 tex_pix_a = vec2(1.0/Texture_X,0.0); 28 | vec2 tex_pix_b = vec2(0.0,1.0/Texture_Y); 29 | vec2 tex_pix_c = vec2(tex_pix_a.x,tex_pix_b.y); 30 | vec2 half_tex = vec2(tex_pix_a.x*0.5,tex_pix_b.y*0.5); 31 | vec2 UVCentered = texcoord - half_tex; 32 | 33 | vec4 diffuseColor = texture(albedoTex,UVCentered); 34 | vec4 sample_a = texture(albedoTex,UVCentered+tex_pix_a); 35 | vec4 sample_b = texture(albedoTex,UVCentered+tex_pix_b); 36 | vec4 sample_c = texture(albedoTex,UVCentered+tex_pix_c); 37 | 38 | float interp_x = modf(UVCentered.x * Texture_X, Texture_X); 39 | float interp_y = modf(UVCentered.y * Texture_Y, Texture_Y); 40 | 41 | if (UVCentered.x < 0.0) 42 | { 43 | interp_x = 1.0-interp_x*(-1.0); 44 | } 45 | if (UVCentered.y < 0.0) 46 | { 47 | interp_y = 1.0-interp_y*(-1.0); 48 | } 49 | 50 | diffuseColor = (diffuseColor + interp_x * (sample_a - diffuseColor) + interp_y * (sample_b - diffuseColor))*(1.0-step(1.0, interp_x + interp_y)); 51 | diffuseColor += (sample_c + (1.0-interp_x) * (sample_b - sample_c) + (1.0-interp_y) * (sample_a - sample_c))*step(1.0, interp_x + interp_y); 52 | 53 | return diffuseColor * vtx_color; 54 | } 55 | 56 | void vertex() 57 | { 58 | #if !defined(NO_TEXTURE) && !defined(METAL) // METAL doesn't use UV, so no need to pan UVs 59 | UV = UV * uv_scale + uv_offset; 60 | UV += uv_pan_velocity * TIME; 61 | #endif 62 | 63 | #ifdef ALPHA_SCISSOR 64 | if (y_billboard) 65 | { 66 | 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]); 67 | 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)); 68 | MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0],INV_VIEW_MATRIX[1],INV_VIEW_MATRIX[2],MODEL_MATRIX[3]); 69 | 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)); 70 | } 71 | else if (billboard) 72 | { 73 | mat4 mat_world = mat4(normalize(INV_VIEW_MATRIX[0])*length(MODEL_MATRIX[0]),normalize(INV_VIEW_MATRIX[1])*length(MODEL_MATRIX[0]),normalize(INV_VIEW_MATRIX[2])*length(MODEL_MATRIX[2]),MODEL_MATRIX[3]); 74 | // MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0],INV_VIEW_MATRIX[1],INV_VIEW_MATRIX[2],MODEL_MATRIX[3]); 75 | mat_world *= mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0)); 76 | MODELVIEW_MATRIX = VIEW_MATRIX * mat_world; 77 | } 78 | #endif 79 | } 80 | 81 | void fragment() 82 | { 83 | #ifdef METAL 84 | vec2 texture_uv = vec2(NORMAL.x / 2.0 + 0.5, (-NORMAL.y) / 2.0 + 0.5); // Special thanks to Adam McLaughlan 85 | #elif !defined(NO_TEXTURE) 86 | vec2 texture_uv = UV; 87 | #endif 88 | 89 | vec4 color_base = COLOR * modulate_color; 90 | 91 | #ifdef NO_TEXTURE 92 | ALBEDO = color_base.rgb; 93 | #else 94 | vec4 texture_color = n64BilinearFilter(COLOR, texture_uv); 95 | ALBEDO = (color_base * texture_color).rgb; 96 | #endif 97 | 98 | #if defined(ALPHA_BLEND) || defined(ALPHA_SCISSOR) 99 | ALPHA = texture_color.a * color_base.a; 100 | #endif 101 | 102 | #ifdef ALPHA_SCISSOR 103 | ALPHA_SCISSOR_THRESHOLD = alpha_scissor; 104 | #endif 105 | } 106 | -------------------------------------------------------------------------------- /shaders/n64_lit.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define DEPTH depth_draw_opaque 5 | #define BLEND blend_mix 6 | 7 | #include "n64_base.gdshaderinc" 8 | -------------------------------------------------------------------------------- /shaders/n64_lit_metal.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define DEPTH depth_draw_opaque 5 | #define BLEND blend_mix 6 | #define METAL 7 | 8 | #include "n64_base.gdshaderinc" 9 | -------------------------------------------------------------------------------- /shaders/n64_lit_transparent.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT diffuse_lambert, vertex_lighting 4 | #define DEPTH depth_draw_opaque 5 | #define BLEND blend_mix 6 | #define ALPHA_BLEND 7 | 8 | #include "n64_base.gdshaderinc" 9 | -------------------------------------------------------------------------------- /shaders/n64_unlit_particle.gdshader: -------------------------------------------------------------------------------- 1 | shader_type spatial; 2 | 3 | #define LIT unshaded 4 | #define DEPTH depth_draw_always 5 | #define BLEND blend_mix 6 | #define ALPHA_SCISSOR 7 | 8 | #include "n64_base.gdshaderinc" 9 | -------------------------------------------------------------------------------- /shaders/pp_band-dither.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | // originally based on https://github.com/WittyCognomen/godot-psx-shaders-demo/blob/master/shaders/psx_dither_post.shader 3 | 4 | uniform sampler2D dither_tex: hint_default_white, filter_nearest, repeat_enable; 5 | uniform float col_depth = 24.0; 6 | uniform bool dither_banding = true; 7 | uniform bool enabled = true; 8 | 9 | void fragment() { 10 | COLOR = texture(TEXTURE, SCREEN_UV); 11 | 12 | if (enabled) 13 | { 14 | vec2 dith_size = vec2(textureSize(dither_tex,0)); // for GLES2: substitute for the dimensions of the dithering matrix 15 | vec2 buf_size = vec2(textureSize(TEXTURE,0)); 16 | vec3 dith = texture(dither_tex, SCREEN_UV*(buf_size/dith_size)).rgb; 17 | dith -= 0.5; 18 | COLOR.rgb = round(COLOR.rgb*col_depth + dith * (dither_banding ? 1.0 : 0.0)) / col_depth; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /shaders/psxdither.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/shaders/psxdither.png -------------------------------------------------------------------------------- /shaders/psxdither.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b6kcbughmhco" 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/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/bevel-box.obj.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="wavefront_obj" 4 | importer_version=1 5 | type="Mesh" 6 | uid="uid://dpwjccau2wphx" 7 | path="res://.godot/imported/bevel-box.obj-268ccf87cb7260f70e0b32cc7e996ec6.mesh" 8 | 9 | [deps] 10 | 11 | files=["res://.godot/imported/bevel-box.obj-268ccf87cb7260f70e0b32cc7e996ec6.mesh"] 12 | 13 | source_file="res://world/box/bevel-box.obj" 14 | dest_files=["res://.godot/imported/bevel-box.obj-268ccf87cb7260f70e0b32cc7e996ec6.mesh", "res://.godot/imported/bevel-box.obj-268ccf87cb7260f70e0b32cc7e996ec6.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_tex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/box/metal_tex.png -------------------------------------------------------------------------------- /world/box/metal_tex.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://l4bdo700r22l" 6 | path.s3tc="res://.godot/imported/metal_tex.png-0d4e62b82ebdfbdf92d0dd974c1842fd.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_tex.png" 15 | dest_files=["res://.godot/imported/metal_tex.png-0d4e62b82ebdfbdf92d0dd974c1842fd.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/object_metal_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://vtfwemyyumrv"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/n64_lit_metal.gdshader" id="1"] 4 | [ext_resource type="Texture2D" uid="uid://l4bdo700r22l" path="res://world/box/metal_tex.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1") 9 | shader_parameter/modulate_color = Color(1, 1, 1, 1) 10 | shader_parameter/albedoTex = ExtResource("2") 11 | -------------------------------------------------------------------------------- /world/box/sparkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/box/sparkle.png -------------------------------------------------------------------------------- /world/box/sparkle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bfqj24shpv3g5" 6 | path="res://.godot/imported/sparkle.png-ece5f684ef456a59172ae6271ae8f4f1.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://world/box/sparkle.png" 14 | dest_files=["res://.godot/imported/sparkle.png-ece5f684ef456a59172ae6271ae8f4f1.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=true 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=false 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=0 35 | -------------------------------------------------------------------------------- /world/box/sparkle_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://1k4iirdl0qtf"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/n64_unlit_particle.gdshader" id="1"] 4 | [ext_resource type="Texture2D" uid="uid://bfqj24shpv3g5" path="res://world/box/sparkle.png" id="2"] 5 | 6 | [resource] 7 | render_priority = 0 8 | shader = ExtResource("1") 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 | shader_parameter/billboard = true 14 | shader_parameter/y_billboard = false 15 | shader_parameter/alpha_scissor = 0.1 16 | shader_parameter/albedoTex = ExtResource("2") 17 | -------------------------------------------------------------------------------- /world/box/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/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/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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://b6j137wa2eprq" 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="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=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=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit.gdshader" type="Shader" id=1] 4 | 5 | [resource] 6 | shader = ExtResource( 1 ) 7 | shader_param/modulate_color = Color( 1, 1, 1, 1 ) 8 | shader_param/uv_scale = Vector2( 1, 1 ) 9 | shader_param/uv_offset = Vector2( 0, 0 ) 10 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 11 | -------------------------------------------------------------------------------- /world/crystal/crystal_mesh.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://bqksudore6gkp"] 2 | 3 | [ext_resource type="Material" path="res://world/crystal/crystal_spire_mat.tres" id="1"] 4 | [ext_resource type="Material" path="res://world/crystal/crystal_ground_mat.tres" id="2"] 5 | [ext_resource type="PackedScene" uid="uid://b6j137wa2eprq" 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=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit.gdshader" type="Shader" id=1] 4 | 5 | [resource] 6 | shader = ExtResource( 1 ) 7 | shader_param/modulate_color = Color( 1, 0, 0.917647, 0.376471 ) 8 | shader_param/uv_scale = Vector2( 1, 1 ) 9 | shader_param/uv_offset = Vector2( 0, 0 ) 10 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 11 | -------------------------------------------------------------------------------- /world/floor/floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/floor/floor.png -------------------------------------------------------------------------------- /world/floor/floor.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c7yqmbdcqkcw0" 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=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit.gdshader" type="Shader" id=1] 4 | [ext_resource path="res://world/floor/floor.png" type="Texture2D" id=2] 5 | 6 | [resource] 7 | shader = ExtResource( 1 ) 8 | shader_param/modulate_color = Color( 0.662745, 0.701961, 0.796078, 1 ) 9 | shader_param/uv_scale = Vector2( 12, 12 ) 10 | shader_param/uv_offset = Vector2( 0, 0 ) 11 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 12 | shader_param/albedoTex = ExtResource( 2 ) 13 | -------------------------------------------------------------------------------- /world/floor/floor.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://world/floor/floor.tres" type="Material" id=1] 4 | 5 | [sub_resource type="PlaneMesh" id=3] 6 | size = Vector2( 40, 40 ) 7 | subdivide_width = 25 8 | subdivide_depth = 25 9 | 10 | [node name="Floor" type="MeshInstance3D"] 11 | mesh = SubResource( 3 ) 12 | material/0 = ExtResource( 1 ) 13 | -------------------------------------------------------------------------------- /world/light-shaft/light-shaft.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset" : { 3 | "generator" : "Khronos glTF Blender I/O v3.4.50", 4 | "version" : "2.0" 5 | }, 6 | "scene" : 0, 7 | "scenes" : [ 8 | { 9 | "name" : "Scene", 10 | "nodes" : [ 11 | 0 12 | ] 13 | } 14 | ], 15 | "nodes" : [ 16 | { 17 | "mesh" : 0, 18 | "name" : "LightShaft" 19 | } 20 | ], 21 | "meshes" : [ 22 | { 23 | "name" : "Mesh", 24 | "primitives" : [ 25 | { 26 | "attributes" : { 27 | "COLOR_0" : 0, 28 | "POSITION" : 1, 29 | "TEXCOORD_0" : 2, 30 | "NORMAL" : 3 31 | }, 32 | "indices" : 4 33 | } 34 | ] 35 | } 36 | ], 37 | "accessors" : [ 38 | { 39 | "bufferView" : 0, 40 | "componentType" : 5123, 41 | "count" : 20, 42 | "normalized" : true, 43 | "type" : "VEC4" 44 | }, 45 | { 46 | "bufferView" : 1, 47 | "componentType" : 5126, 48 | "count" : 20, 49 | "max" : [ 50 | 2.3582985401153564, 51 | 3.000000238418579, 52 | 2.3582985401153564 53 | ], 54 | "min" : [ 55 | -2.3582985401153564, 56 | 0, 57 | -2.3582985401153564 58 | ], 59 | "type" : "VEC3" 60 | }, 61 | { 62 | "bufferView" : 2, 63 | "componentType" : 5126, 64 | "count" : 20, 65 | "type" : "VEC2" 66 | }, 67 | { 68 | "bufferView" : 3, 69 | "componentType" : 5126, 70 | "count" : 20, 71 | "type" : "VEC3" 72 | }, 73 | { 74 | "bufferView" : 4, 75 | "componentType" : 5123, 76 | "count" : 72, 77 | "type" : "SCALAR" 78 | } 79 | ], 80 | "bufferViews" : [ 81 | { 82 | "buffer" : 0, 83 | "byteLength" : 160, 84 | "byteOffset" : 0, 85 | "target" : 34962 86 | }, 87 | { 88 | "buffer" : 0, 89 | "byteLength" : 240, 90 | "byteOffset" : 160, 91 | "target" : 34962 92 | }, 93 | { 94 | "buffer" : 0, 95 | "byteLength" : 160, 96 | "byteOffset" : 400, 97 | "target" : 34962 98 | }, 99 | { 100 | "buffer" : 0, 101 | "byteLength" : 240, 102 | "byteOffset" : 560, 103 | "target" : 34962 104 | }, 105 | { 106 | "buffer" : 0, 107 | "byteLength" : 144, 108 | "byteOffset" : 800, 109 | "target" : 34963 110 | } 111 | ], 112 | "buffers" : [ 113 | { 114 | "byteLength" : 944, 115 | "uri" : "data:application/octet-stream;base64,/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3CsiD8AAEBAcKyIv3CsiD8AAEBAcKyIvz+J2z8AAAAAP4nbv3CsiD8AAEBAcKyIP3CsiD8AAEBAcKyIPz+J2z8AAAAAP4nbP3CsiL8AAEBAcKyIvz+J278AAAAAP4nbv3CsiL8AAEBAcKyIPz+J278AAAAAP4nbP13uFsAAAAAAgFDJsjIg7jEAAAAAXe4WwIzT4zEBAEBAGu27Pxrtuz8BAEBAkx/Vshrtuz8BAEBAkx/VsjIg7jEAAAAAXe4WQBrtu78BAEBAkx/VsozT4zEBAEBAGu27v13uFkAAAAAAgFDJsgxRmDIBAEBAzYZrslZVVT8AAAA/V1VVP/z//z5WVVU/AACAP6uqKj4AAAA/rKoqPvz//z6sqio+AACAPwEAgD/8//8+AQCAPwAAgD8AAAAA/P//PgAAAAAAAIA/AQAAPwAAgD+sqno/AACAP6yqqjz8//8+AQAAP/z//z4BAAA//P//PqyqqjwAAIA/AQAAP/z//z6sqno//P//PgEAAD8AAIA/AAAAPwAAAD/cbvY+zIc7P4129r5mb/Y+pog7P3Nz9r4DIy0/eHGVPgMjLb+YdvY+xIc7P+pu9j5jb/Y+pYg7P3Zz9j4DIy0/eXGVPgMjLT9scfa+p4g7P2hx9r4DIy2/eXGVPgMjLb9mcfa+qIg7P2Zx9j4DIy2/eXGVPgIjLT+9bHW/oKORPqL3ODMAAAAAoKORPr1sdb/hSyuzMXw9Pz8jLD9XIyw/G3w9PwAQwjc6JCw/T3s9PwDwJbgAAAAAoKORPr1sdT9AIyy/MXw9P2qggTN8pi+zMXw9P0AjLL+9bHU/oKORPqP3ODKZ7hizAACAPwAAAIAAABEAEwAAABMADgARAAYAEAARABAAEwATABAACAATAAgADAAOABMADAAOAAwAAwAPAAwACAAPAAgACQAJAAgAEAAJABAACgAKABAABgAKAAYABwABAA0AEgABABIAAgASAA0ABAASAAQABQAGABEACwAGAAsABwALABEAAQALAAEAAgAEAAwADwAEAA8ABQA=" 116 | } 117 | ] 118 | } 119 | -------------------------------------------------------------------------------- /world/light-shaft/light-shaft.gltf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | importer_version=1 5 | type="PackedScene" 6 | uid="uid://c30rqsh4d0ul6" 7 | path="res://.godot/imported/light-shaft.gltf-48bf216081c2e27ec22cc4604158d806.scn" 8 | 9 | [deps] 10 | 11 | source_file="res://world/light-shaft/light-shaft.gltf" 12 | dest_files=["res://.godot/imported/light-shaft.gltf-48bf216081c2e27ec22cc4604158d806.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=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/light-shaft/light-shaft_Mesh.mesh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/light-shaft/light-shaft_Mesh.mesh -------------------------------------------------------------------------------- /world/light-shaft/light-shaft_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://blpnruy0dhpw5"] 2 | 3 | [ext_resource type="Shader" path="res://shaders/light-volume.gdshader" id="1"] 4 | 5 | [resource] 6 | render_priority = 0 7 | shader = ExtResource("1") 8 | -------------------------------------------------------------------------------- /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 : set = _set_is_paused 10 | 11 | 12 | func _ready(): 13 | for node in get_tree().get_nodes_in_group("can_pause"): 14 | connect("pause",Callable(node,"set_process")) 15 | 16 | for node in get_tree().get_nodes_in_group("can_restart"): 17 | assert(node.has_method("restart")) 18 | connect("reset",Callable(node,"restart")) 19 | 20 | 21 | func _unhandled_input(event: InputEvent): 22 | if event.is_action_pressed(PAUSE_ACTION): 23 | self._is_paused = !self._is_paused 24 | 25 | elif event.is_action_pressed(RESET_ACTION): 26 | emit_signal("reset") 27 | 28 | get_viewport().set_input_as_handled() 29 | 30 | 31 | func _set_is_paused(p_paused: bool): 32 | _is_paused = p_paused 33 | emit_signal("pause", !p_paused) 34 | -------------------------------------------------------------------------------- /world/shadow/shadow.gd: -------------------------------------------------------------------------------- 1 | extends Node3D 2 | 3 | const SpatialSinPan := preload("res://world/box/spatial_sin_pan.gd") 4 | 5 | const SCALE_DISTANCE := 0.225 6 | const DEFAULT_SCALE := Vector3.ONE * 1.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-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/shadow/shadow.png -------------------------------------------------------------------------------- /world/shadow/shadow.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://coa0ie243ped4" 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=3 uid="uid://dy02fdb77e812"] 2 | 3 | [ext_resource type="Material" path="res://world/shadow/shadow_mat.tres" id="1"] 4 | [ext_resource type="Script" path="res://world/shadow/shadow.gd" id="2"] 5 | 6 | [sub_resource type="PlaneMesh" id="1"] 7 | size = Vector2(1, 1) 8 | 9 | [node name="BoxShadow" type="Node3D"] 10 | script = ExtResource("2") 11 | 12 | [node name="MeshInstance3D" type="MeshInstance3D" parent="."] 13 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.02, 0) 14 | mesh = SubResource("1") 15 | surface_material_override/0 = ExtResource("1") 16 | -------------------------------------------------------------------------------- /world/shadow/shadow_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit_transparent.gdshader" type="Shader" id=1] 4 | [ext_resource path="res://world/shadow/shadow.png" type="Texture2D" id=2] 5 | 6 | [resource] 7 | shader = ExtResource( 1 ) 8 | shader_param/modulate_color = Color( 1, 1, 1, 0.78 ) 9 | shader_param/uv_scale = Vector2( 1, 1 ) 10 | shader_param/uv_offset = Vector2( 0, 0 ) 11 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 12 | shader_param/albedoTex = ExtResource( 2 ) 13 | -------------------------------------------------------------------------------- /world/stairs/stairs.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset" : { 3 | "generator" : "Khronos glTF Blender I/O v3.4.50", 4 | "version" : "2.0" 5 | }, 6 | "scene" : 0, 7 | "scenes" : [ 8 | { 9 | "name" : "Scene", 10 | "nodes" : [ 11 | 0 12 | ] 13 | } 14 | ], 15 | "nodes" : [ 16 | { 17 | "mesh" : 0, 18 | "name" : "Stairs" 19 | } 20 | ], 21 | "meshes" : [ 22 | { 23 | "name" : "Mesh", 24 | "primitives" : [ 25 | { 26 | "attributes" : { 27 | "POSITION" : 0, 28 | "TEXCOORD_0" : 1, 29 | "NORMAL" : 2 30 | }, 31 | "indices" : 3 32 | }, 33 | { 34 | "attributes" : { 35 | "POSITION" : 4, 36 | "TEXCOORD_0" : 5, 37 | "NORMAL" : 6 38 | }, 39 | "indices" : 7 40 | } 41 | ] 42 | } 43 | ], 44 | "accessors" : [ 45 | { 46 | "bufferView" : 0, 47 | "componentType" : 5126, 48 | "count" : 12, 49 | "max" : [ 50 | 1.1370224952697754, 51 | 2, 52 | 2.489109516143799 53 | ], 54 | "min" : [ 55 | -1.1370224952697754, 56 | 0, 57 | -2.489109516143799 58 | ], 59 | "type" : "VEC3" 60 | }, 61 | { 62 | "bufferView" : 1, 63 | "componentType" : 5126, 64 | "count" : 12, 65 | "type" : "VEC2" 66 | }, 67 | { 68 | "bufferView" : 2, 69 | "componentType" : 5126, 70 | "count" : 12, 71 | "type" : "VEC3" 72 | }, 73 | { 74 | "bufferView" : 3, 75 | "componentType" : 5123, 76 | "count" : 18, 77 | "type" : "SCALAR" 78 | }, 79 | { 80 | "bufferView" : 4, 81 | "componentType" : 5126, 82 | "count" : 6, 83 | "max" : [ 84 | 1.1370224952697754, 85 | 2, 86 | 2.489109516143799 87 | ], 88 | "min" : [ 89 | -1.1370224952697754, 90 | 0, 91 | -2.489109516143799 92 | ], 93 | "type" : "VEC3" 94 | }, 95 | { 96 | "bufferView" : 5, 97 | "componentType" : 5126, 98 | "count" : 6, 99 | "type" : "VEC2" 100 | }, 101 | { 102 | "bufferView" : 6, 103 | "componentType" : 5126, 104 | "count" : 6, 105 | "type" : "VEC3" 106 | }, 107 | { 108 | "bufferView" : 7, 109 | "componentType" : 5123, 110 | "count" : 12, 111 | "type" : "SCALAR" 112 | } 113 | ], 114 | "bufferViews" : [ 115 | { 116 | "buffer" : 0, 117 | "byteLength" : 144, 118 | "byteOffset" : 0, 119 | "target" : 34962 120 | }, 121 | { 122 | "buffer" : 0, 123 | "byteLength" : 96, 124 | "byteOffset" : 144, 125 | "target" : 34962 126 | }, 127 | { 128 | "buffer" : 0, 129 | "byteLength" : 144, 130 | "byteOffset" : 240, 131 | "target" : 34962 132 | }, 133 | { 134 | "buffer" : 0, 135 | "byteLength" : 36, 136 | "byteOffset" : 384, 137 | "target" : 34963 138 | }, 139 | { 140 | "buffer" : 0, 141 | "byteLength" : 72, 142 | "byteOffset" : 420, 143 | "target" : 34962 144 | }, 145 | { 146 | "buffer" : 0, 147 | "byteLength" : 48, 148 | "byteOffset" : 492, 149 | "target" : 34962 150 | }, 151 | { 152 | "buffer" : 0, 153 | "byteLength" : 72, 154 | "byteOffset" : 540, 155 | "target" : 34962 156 | }, 157 | { 158 | "buffer" : 0, 159 | "byteLength" : 24, 160 | "byteOffset" : 612, 161 | "target" : 34963 162 | } 163 | ], 164 | "buffers" : [ 165 | { 166 | "byteLength" : 636, 167 | "uri" : "data:application/octet-stream;base64,9ImRPwAAAACSTR/A9ImRPwAAAECSTR9A9ImRPwAAAECSTR9A9ImRPwAAAACSTR9A9ImRPwAAAACSTR9A9ImRvwAAAACSTR/A9ImRvwAAAECSTR9A9ImRvwAAAECSTR9A9ImRvwAAAACSTR9A9ImRvwAAAACSTR9AAAAAAAAAAECSTR9AAAAAAAAAAACSTR9AAIB8PwAAQDwAACA/AACAPv3/fzzYOH0/AADAPgAAgD4AgHw/2Dh9PwCAfD8AAEA8/f9/PNg4fT8AACA/AACAPgCAfD/YOH0/AADAPgAAgD4AACA/AAAAPgAAwD4AAAA+//9/PwAAAAAAAACAAAAAAAAAAAAAAIA///9/PwAAAAAAAACAAAAAAAAAAAAAAIA///9/PwAAAAAAAACA//9/vwAAAAAAAACA//9/vwAAAAAAAACAAAAAAAAAAAAAAIA///9/vwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAACAAQAAwABAAoAAwAKAAsABQAIAAYACQALAAoACQAKAAcA9ImRPwAAAACSTR/A9ImRPwAAAECSTR9A9ImRvwAAAACSTR/A9ImRvwAAAECSTR9AAAAAAAAAAECSTR9AAAAAAAAAAACSTR/A9skxPAAAgD/2yTE8AAAAAPbJMTwAAIA/9skxPAAAAACg6X0/AAAAAKDpfT8AAIA/AAAAAOKLbT9c3r6+AAAAAOKLbT9c3r6+AAAAAOKLbT9c3r6+AAAAAOKLbT9c3r6+AAAAAOKLbT9c3r6+AAAAAOKLbT9c3r6+AAAFAAQAAAAEAAEAAgADAAQAAgAEAAUA" 168 | } 169 | ] 170 | } 171 | -------------------------------------------------------------------------------- /world/stairs/stairs.gltf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | importer_version=1 5 | type="PackedScene" 6 | uid="uid://b7vlhuvhfdnh5" 7 | path="res://.godot/imported/stairs.gltf-627eb097c1432ffe8266ecc737d86add.scn" 8 | 9 | [deps] 10 | 11 | source_file="res://world/stairs/stairs.gltf" 12 | dest_files=["res://.godot/imported/stairs.gltf-627eb097c1432ffe8266ecc737d86add.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=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 | "meshes": { 33 | "stairs_Mesh": { 34 | "generate/lightmap_uv": 2, 35 | "generate/lods": 2, 36 | "generate/shadow_meshes": 2, 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/stairs/stairs_Mesh.mesh" 42 | } 43 | } 44 | } 45 | gltf/embedded_image_handling=1 46 | -------------------------------------------------------------------------------- /world/stairs/stairs_Mesh.mesh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/stairs/stairs_Mesh.mesh -------------------------------------------------------------------------------- /world/stairs/stairs_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/stairs/stairs_side.png -------------------------------------------------------------------------------- /world/stairs/stairs_side.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://blwrc8m1nlr1g" 6 | path.s3tc="res://.godot/imported/stairs_side.png-b24fc00822520c9d5e1947b6b02236f3.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/stairs/stairs_side.png" 15 | dest_files=["res://.godot/imported/stairs_side.png-b24fc00822520c9d5e1947b6b02236f3.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/stairs/stairs_side_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit.gdshader" type="Shader" id=1] 4 | [ext_resource path="res://world/stairs/stairs_side.png" type="Texture2D" id=2] 5 | 6 | [resource] 7 | shader = ExtResource( 1 ) 8 | shader_param/modulate_color = Color( 1, 1, 1, 1 ) 9 | shader_param/uv_scale = Vector2( 1, 1 ) 10 | shader_param/uv_offset = Vector2( 0, 0 ) 11 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 12 | shader_param/albedoTex = ExtResource( 2 ) 13 | -------------------------------------------------------------------------------- /world/stairs/stairs_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MenacingMecha/godot-n64-shader-demo/f9ee31d2b98f6519d080e3dcbbaa129cdac8870c/world/stairs/stairs_top.png -------------------------------------------------------------------------------- /world/stairs/stairs_top.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c7vn5bhjp0123" 6 | path.s3tc="res://.godot/imported/stairs_top.png-705bb3608576d1f995ce1cbc2e979586.s3tc.ctex" 7 | metadata={ 8 | "imported_formats": ["s3tc_bptc"], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://world/stairs/stairs_top.png" 15 | dest_files=["res://.godot/imported/stairs_top.png-705bb3608576d1f995ce1cbc2e979586.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/stairs/stairs_top_mat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ShaderMaterial" load_steps=3 format=2] 2 | 3 | [ext_resource path="res://shaders/n64_lit.gdshader" type="Shader" id=1] 4 | [ext_resource path="res://world/stairs/stairs_top.png" type="Texture2D" id=2] 5 | 6 | [resource] 7 | shader = ExtResource( 1 ) 8 | shader_param/modulate_color = Color( 1, 1, 1, 1 ) 9 | shader_param/uv_scale = Vector2( 1, 8 ) 10 | shader_param/uv_offset = Vector2( 0, 0 ) 11 | shader_param/uv_pan_velocity = Vector2( 0, 0 ) 12 | shader_param/albedoTex = ExtResource( 2 ) 13 | -------------------------------------------------------------------------------- /world/world.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=19 format=3 uid="uid://dcy86n4si7d7v"] 2 | 3 | [ext_resource type="Script" path="res://world/orbit_camera.gd" id="1"] 4 | [ext_resource type="ArrayMesh" uid="uid://dpwjccau2wphx" path="res://world/box/bevel-box.obj" id="2"] 5 | [ext_resource type="Script" path="res://world/box/spatial_sin_pan.gd" id="3"] 6 | [ext_resource type="PackedScene" path="res://world/floor/floor.tscn" id="4"] 7 | [ext_resource type="PackedScene" uid="uid://dy02fdb77e812" path="res://world/shadow/shadow.tscn" id="6"] 8 | [ext_resource type="Material" uid="uid://1k4iirdl0qtf" path="res://world/box/sparkle_mat.tres" id="7"] 9 | [ext_resource type="Material" uid="uid://vtfwemyyumrv" path="res://world/box/object_metal_mat.tres" id="9"] 10 | [ext_resource type="Material" uid="uid://blpnruy0dhpw5" path="res://world/light-shaft/light-shaft_mat.tres" id="10"] 11 | [ext_resource type="Material" path="res://world/floor/floor.tres" id="10_oo5rr"] 12 | [ext_resource type="PackedScene" uid="uid://bqksudore6gkp" path="res://world/crystal/crystal_mesh.tscn" id="11"] 13 | [ext_resource type="ArrayMesh" path="res://world/light-shaft/light-shaft_Mesh.mesh" id="12"] 14 | [ext_resource type="ArrayMesh" uid="uid://dh4nw5qd6jcdp" path="res://world/stairs/stairs_Mesh.mesh" id="14"] 15 | [ext_resource type="Environment" uid="uid://v0ricrcvgxa4" path="res://world/world_env.tres" id="15"] 16 | [ext_resource type="Script" path="res://world/scene_controls.gd" id="16"] 17 | [ext_resource type="Material" path="res://world/stairs/stairs_side_mat.tres" id="19"] 18 | [ext_resource type="Material" path="res://world/stairs/stairs_top_mat.tres" id="20"] 19 | 20 | [sub_resource type="ParticleProcessMaterial" id="1"] 21 | direction = Vector3(1, 1, 1) 22 | spread = 180.0 23 | gravity = Vector3(0, 0, 0) 24 | initial_velocity_min = 2.0 25 | initial_velocity_max = 2.0 26 | 27 | [sub_resource type="QuadMesh" id="2"] 28 | material = ExtResource("7") 29 | size = Vector2(0.5, 0.5) 30 | 31 | [node name="World" type="Node3D"] 32 | 33 | [node name="SceneControls" type="Node" parent="."] 34 | script = ExtResource("16") 35 | 36 | [node name="OrbitPoint" type="Node3D" parent="." groups=["can_pause", "can_restart"]] 37 | transform = Transform3D(0.831023, 0, -0.556238, 0, 1, 0, 0.556238, 0, 0.831023, 0, -2.38419e-07, -4.76837e-07) 38 | script = ExtResource("1") 39 | 40 | [node name="Camera3D" type="Camera3D" parent="OrbitPoint"] 41 | transform = Transform3D(1, 0, 0, 0, 0.989078, 0.147395, 0, -0.147395, 0.989078, 0, 2.147, 4.48151) 42 | fov = 68.1243 43 | 44 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] 45 | transform = Transform3D(0.524194, -0.536217, 0.661583, 0, 0.776871, 0.62966, -0.851599, -0.330064, 0.407231, 4.40183, 2.79045, 2.57139) 46 | light_bake_mode = 0 47 | sky_mode = 1 48 | 49 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."] 50 | environment = ExtResource("15") 51 | 52 | [node name="BoxMetal" type="MeshInstance3D" parent="." groups=["can_pause", "can_restart"]] 53 | transform = Transform3D(0.613118, 0, 0, 0, 0.613118, 0, 0, 0, 0.613118, -1, 2.236, 0) 54 | mesh = ExtResource("2") 55 | surface_material_override/0 = ExtResource("9") 56 | script = ExtResource("3") 57 | 58 | [node name="Particles" type="GPUParticles3D" parent="BoxMetal" groups=["can_restart"]] 59 | transform = Transform3D(0.999973, 0.00729208, -0.00112456, -0.00729237, 0.999973, -0.000250523, 0.00112271, 0.000258713, 0.999999, 0, 0, 0) 60 | cast_shadow = 0 61 | fixed_fps = 15 62 | interpolate = false 63 | fract_delta = false 64 | process_material = SubResource("1") 65 | draw_pass_1 = SubResource("2") 66 | 67 | [node name="BoxShadow" parent="." groups=["can_pause", "can_restart"] instance=ExtResource("6")] 68 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.052, 0, 0.04) 69 | 70 | [node name="Floor" parent="." instance=ExtResource("4")] 71 | surface_material_override/0 = ExtResource("10_oo5rr") 72 | 73 | [node name="crystal" parent="." instance=ExtResource("11")] 74 | transform = Transform3D(0.719146, 0, 0.694859, 0, 1, 0, -0.694859, 0, 0.719146, 2.32347, 0, 1.434) 75 | 76 | [node name="crystal2" parent="." instance=ExtResource("11")] 77 | transform = Transform3D(0.826285, 0, -0.563252, 0, 1, 0, 0.563252, 0, 0.826285, -1.32247, 0, 1.77809) 78 | 79 | [node name="crystal3" parent="." instance=ExtResource("11")] 80 | transform = Transform3D(0.864371, 0, 0.502854, 0, 1, 0, -0.502854, 0, 0.864371, -2.32825, 0, -0.999177) 81 | 82 | [node name="crystal4" parent="." instance=ExtResource("11")] 83 | transform = Transform3D(-0.632935, 0, 0.774205, 0, 1, 0, -0.774205, 0, -0.632935, 2.30476, 0, -1.16371) 84 | 85 | [node name="LightShaft" type="MeshInstance3D" parent="."] 86 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.057, 0) 87 | mesh = ExtResource("12") 88 | skeleton = NodePath("") 89 | surface_material_override/0 = ExtResource("10") 90 | 91 | [node name="Stairs" type="MeshInstance3D" parent="."] 92 | transform = Transform3D(0.707, 0, 0, 0, 0.707, 0, 0, 0, 0.707, 0.601188, 0, 0) 93 | mesh = ExtResource("14") 94 | surface_material_override/0 = ExtResource("19") 95 | surface_material_override/1 = ExtResource("20") 96 | -------------------------------------------------------------------------------- /world/world_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" format=3 uid="uid://v0ricrcvgxa4"] 2 | 3 | [resource] 4 | background_mode = 1 5 | background_color = Color(0.666667, 0.764706, 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 | fog_enabled = true 10 | fog_light_color = Color(0.666667, 0.764706, 1, 1) 11 | fog_density = 0.035 12 | --------------------------------------------------------------------------------