mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sharp/small-fixes' into 'master'
LOD, shadow maps, greedy meshing, new lighting, world size refactoring, and other performance fixes. See merge request veloren/veloren!1300
This commit is contained in:
commit
14fd023854
@ -20,15 +20,15 @@ benchmarks:
|
||||
retry:
|
||||
max: 2
|
||||
|
||||
# Coverage is needed on master for the README.md badge to work
|
||||
coverage:
|
||||
extends: .recompile
|
||||
stage: build
|
||||
script:
|
||||
- ln -s /dockercache/cache-tarpaulin target
|
||||
- cargo tarpaulin -v
|
||||
retry:
|
||||
max: 2
|
||||
# # Coverage is needed on master for the README.md badge to work
|
||||
# coverage:
|
||||
# extends: .recompile
|
||||
# stage: build
|
||||
# script:
|
||||
# - ln -s /dockercache/cache-tarpaulin target
|
||||
# - cargo tarpaulin -v
|
||||
# retry:
|
||||
# max: 2
|
||||
|
||||
#linux, windows, macos builds here as template
|
||||
.tlinux:
|
||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -9,11 +9,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- New level of detail feature, letting you see all the world's terrain at any view distance.
|
||||
- Point and directional lights now cast realistic shadows, using shadow mapping.
|
||||
|
||||
### Changed
|
||||
- Fixed a bug where leaving the Settings menu by pressing "N" in single player kept the game paused
|
||||
- The world map has been refactored to support arbitrary sizes and compute horizon maps.
|
||||
- Veloren's lighting has been completely overhauled.
|
||||
- The graphics options were made much more flexible and configurable.
|
||||
- Many shader optimizations.
|
||||
- Voxel model creation was switched to use greedy meshing, improving performance.
|
||||
- Animation and terrain math were switched to use SIMD where possible, improving performance.
|
||||
- The way we cache glyphs was refactored, fixed, and optimized.
|
||||
- Colors for models and figures were adjusted to account for the saturation hack.
|
||||
|
||||
### Removed
|
||||
|
||||
- MSAA has been removed due to incompatibility with greedy meshing.
|
||||
- Removed a saturation hack that led to colors being improperly displayed.
|
||||
|
||||
## [0.7.0] - 2020-08-15
|
||||
|
||||
### Added
|
||||
|
136
Cargo.lock
generated
136
Cargo.lock
generated
@ -381,6 +381,12 @@ version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db7a1029718df60331e557c9e83a55523c955e5dd2a7bfeffad6bbd50b538ae9"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "0.5.3"
|
||||
@ -581,7 +587,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_core"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#09d4675c4549b0fa5b6a87eacf6e1851876a80b8"
|
||||
dependencies = [
|
||||
"conrod_derive",
|
||||
"copypasta",
|
||||
@ -596,7 +602,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_derive"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#09d4675c4549b0fa5b6a87eacf6e1851876a80b8"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
@ -606,7 +612,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "conrod_winit"
|
||||
version = "0.63.0"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#1ab6eccf94b16a8977a3274b31d4dbfef9cf9a30"
|
||||
source = "git+https://gitlab.com/veloren/conrod.git#09d4675c4549b0fa5b6a87eacf6e1851876a80b8"
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
@ -1045,9 +1051,9 @@ checksum = "72aa14c04dfae8dd7d8a2b1cb7ca2152618cd01336dbfe704b8dcbf8d41dbd69"
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.7.20"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
|
||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"byteorder 1.3.4",
|
||||
@ -1224,30 +1230,18 @@ name = "euc"
|
||||
version = "0.5.1"
|
||||
source = "git+https://github.com/zesterer/euc.git#c9a7c17a03d45fce00caeeca09afa1e1558cd183"
|
||||
dependencies = [
|
||||
"vek",
|
||||
"vek 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.19.9"
|
||||
version = "0.20.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1"
|
||||
checksum = "555d51b9a929edb14183fad621e2d5736fc8760707a24246047288d4c142b6bd"
|
||||
dependencies = [
|
||||
"euclid_macros",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euclid_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"syn 0.15.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
@ -1878,8 +1872,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "guillotiere"
|
||||
version = "0.4.2"
|
||||
source = "git+https://github.com/Imberflur/guillotiere#42c298f5bcf0f95f1a004360d05e25ca3711e9ed"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47065d052e2f000066c4ffbea7051e55bff5c1532c400fc1e269492b2474ccc1"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
"svg_fmt",
|
||||
@ -2075,13 +2070,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.22.5"
|
||||
version = "0.23.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08ed2ada878397b045454ac7cfb011d73132c59f31a955d230bd1f1c2e68eb4a"
|
||||
checksum = "543904170510c1b5fb65140485d84de4a57fddb2ed685481e9020ce3d2c9f64c"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder 1.3.4",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-rational 0.3.0",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
@ -2095,15 +2091,6 @@ dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inflate"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.8.3"
|
||||
@ -2471,6 +2458,15 @@ dependencies = [
|
||||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.22"
|
||||
@ -2686,7 +2682,7 @@ dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-rational 0.2.4",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
@ -2744,6 +2740,17 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
@ -3091,14 +3098,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.15.3"
|
||||
version = "0.16.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef859a23054bbfee7811284275ae522f0434a3c8e7f4b74bd4a35ae7e1c4a283"
|
||||
checksum = "dfe7f9f1c730833200b134370e1d5098964231af8450bce9b78ee3ab5278b970"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"deflate",
|
||||
"inflate",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3553,9 +3560,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "roots"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4c67c712ab62be58b24ab8960e2b95dd4ee00aac115c76f2709657821fe376d"
|
||||
checksum = "84348444bd7ad45729d0c49a4240d7cdc11c9d512c06c5ad1835c1ad4acda6db"
|
||||
|
||||
[[package]]
|
||||
name = "route-recognizer"
|
||||
@ -3778,6 +3785,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.33",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
@ -4043,9 +4061,9 @@ checksum = "da5b4a0c9f3c7c8e891e445a7c776627e208e8bba23ab680798066dd283e6a15"
|
||||
|
||||
[[package]]
|
||||
name = "svg_fmt"
|
||||
version = "0.2.1"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20e5f95e89d737f30cd1f98a9af9a85c2a1cc162cfedfba5a0c54cf92d7206fc"
|
||||
checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
@ -4440,7 +4458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa14b9f5cd7d513bab5accebe8f403df8b1ac22302cac549a6ac99c0a007c84a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"vek",
|
||||
"vek 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4608,6 +4626,19 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vek"
|
||||
version = "0.12.0"
|
||||
source = "git+https://gitlab.com/veloren/vek.git?branch=fix_intrinsics#237a78528b505f34f6dde5dc77db3b642388fe4a"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "veloren-chat-cli"
|
||||
version = "0.7.0"
|
||||
@ -4629,11 +4660,13 @@ dependencies = [
|
||||
"futures-util",
|
||||
"hashbrown",
|
||||
"image",
|
||||
"num 0.2.1",
|
||||
"num_cpus",
|
||||
"rayon",
|
||||
"specs",
|
||||
"tracing",
|
||||
"uvth 3.1.1",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
"veloren_network",
|
||||
]
|
||||
@ -4658,14 +4691,16 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"ron",
|
||||
"roots",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"slab",
|
||||
"specs",
|
||||
"specs-idvs",
|
||||
"sum_type",
|
||||
"tracing",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4696,7 +4731,7 @@ dependencies = [
|
||||
"tiny_http",
|
||||
"tracing",
|
||||
"uvth 3.1.1",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
"veloren-world",
|
||||
"veloren_network",
|
||||
@ -4733,6 +4768,7 @@ dependencies = [
|
||||
"failure",
|
||||
"gfx",
|
||||
"gfx_device_gl",
|
||||
"gfx_gl",
|
||||
"gilrs",
|
||||
"git2",
|
||||
"glsl-include",
|
||||
@ -4757,7 +4793,7 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"treeculler",
|
||||
"uvth 3.1.1",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
"veloren-client",
|
||||
"veloren-common",
|
||||
"veloren-server",
|
||||
@ -4776,7 +4812,7 @@ dependencies = [
|
||||
"libloading 0.6.2",
|
||||
"notify",
|
||||
"tracing",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
]
|
||||
|
||||
@ -4787,6 +4823,7 @@ dependencies = [
|
||||
"arr_macro",
|
||||
"bincode",
|
||||
"bitvec",
|
||||
"criterion",
|
||||
"fxhash",
|
||||
"hashbrown",
|
||||
"image",
|
||||
@ -4801,11 +4838,10 @@ dependencies = [
|
||||
"rand_chacha 0.2.2",
|
||||
"rayon",
|
||||
"ron",
|
||||
"roots",
|
||||
"serde",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"vek",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
]
|
||||
|
||||
|
@ -47,6 +47,9 @@ opt-level = 2
|
||||
[profile.no_overflow.package."veloren-world"]
|
||||
opt-level = 3
|
||||
|
||||
[profile.no_overflow.package."veloren-voxygen-anim"]
|
||||
opt-level = 3
|
||||
|
||||
# this profile is used by developers if dev doesn't has enough debug information, the name must != debug, as debug is used by dev because....
|
||||
[profile.debuginfo]
|
||||
inherits= 'dev'
|
||||
@ -74,6 +77,7 @@ debug = false
|
||||
inherits = 'release'
|
||||
debug = 1
|
||||
|
||||
# cpal conflict fix isn't released yet
|
||||
[patch.crates-io]
|
||||
# cpal conflict fix isn't released yet
|
||||
winit = { git = "https://github.com/Imberflur/winit.git", branch = "macos-test" }
|
||||
vek = { git = "https://gitlab.com/veloren/vek.git", branch = "fix_intrinsics" }
|
||||
|
@ -598,6 +598,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"body": {
|
||||
"keyword": "object",
|
||||
"names": []
|
||||
},
|
||||
"species": null
|
||||
},
|
||||
"fish_small": {
|
||||
"body": {
|
||||
"keyword": "fish_small",
|
||||
"names": []
|
||||
},
|
||||
"species": null
|
||||
},
|
||||
"fish_medium": {
|
||||
"body": {
|
||||
"keyword": "fish_medium",
|
||||
"names": []
|
||||
},
|
||||
"species": null
|
||||
},
|
||||
"bird_small": {
|
||||
"body": {
|
||||
"keyword": "bird_small",
|
||||
"names": []
|
||||
},
|
||||
"species": null
|
||||
},
|
||||
"quadruped_low": {
|
||||
"body": {
|
||||
"keyword": "quadruped_low",
|
||||
|
@ -303,6 +303,15 @@ magischen Gegenstände ergattern?"#,
|
||||
"hud.settings.bit_depth": "Bittiefe",
|
||||
"hud.settings.refresh_rate": "Bildwiederholrate",
|
||||
"hud.settings.fullscreen": "Vollbild",
|
||||
"hud.settings.lighting_rendering_mode": "Beleuchtung",
|
||||
"hud.settings.lighting_rendering_mode.ashikhmin": "Typ A",
|
||||
"hud.settings.lighting_rendering_mode.blinnphong": "Typ B",
|
||||
"hud.settings.lighting_rendering_mode.lambertian": "Typ L",
|
||||
"hud.settings.shadow_rendering_mode": "Schatten",
|
||||
"hud.settings.shadow_rendering_mode.none": "Keine Schatten",
|
||||
"hud.settings.shadow_rendering_mode.cheap": "Gering",
|
||||
"hud.settings.shadow_rendering_mode.map": "Voll",
|
||||
"hud.settings.lod_detail": "LoD Detail",
|
||||
"hud.settings.save_window_size": "Größe speichern",
|
||||
|
||||
"hud.settings.music_volume": "Musik Lautstärke",
|
||||
|
@ -304,6 +304,18 @@ magically infused items?"#,
|
||||
"hud.settings.refresh_rate": "Refresh Rate",
|
||||
"hud.settings.fullscreen": "Fullscreen",
|
||||
"hud.settings.save_window_size": "Save window size",
|
||||
"hud.settings.lighting_rendering_mode": "Lighting Rendering Mode",
|
||||
"hud.settings.lighting_rendering_mode.ashikhmin": "Type A",
|
||||
"hud.settings.lighting_rendering_mode.blinnphong": "Type B",
|
||||
"hud.settings.lighting_rendering_mode.lambertian": "Type L",
|
||||
"hud.settings.shadow_rendering_mode": "Shadow Rendering Mode",
|
||||
"hud.settings.shadow_rendering_mode.none": "None",
|
||||
"hud.settings.shadow_rendering_mode.cheap": "Cheap",
|
||||
"hud.settings.shadow_rendering_mode.map": "Map",
|
||||
"hud.settings.shadow_rendering_mode.map.resolution": "Resolution",
|
||||
"hud.settings.lod_detail": "LoD Detail",
|
||||
"hud.settings.save_window_size": "Save window size",
|
||||
|
||||
|
||||
"hud.settings.music_volume": "Music Volume",
|
||||
"hud.settings.sound_effect_volume": "Sound Effects Volume",
|
||||
|
@ -1,16 +1,56 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_col;
|
||||
in float f_ao;
|
||||
// in float dummy;
|
||||
// in vec3 f_col;
|
||||
// in float f_ao;
|
||||
// flat in uint f_pos_norm;
|
||||
flat in vec3 f_norm;
|
||||
/*centroid */in vec2 f_uv_pos;
|
||||
// in float f_alt;
|
||||
// in vec4 f_shadow;
|
||||
// in vec3 light_pos[2];
|
||||
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// in vec4 sun_pos;
|
||||
// #elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// const vec4 sun_pos = vec4(0.0);
|
||||
// #endif
|
||||
|
||||
uniform sampler2D t_col_light;
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
mat4 model_mat;
|
||||
vec4 model_col;
|
||||
ivec4 atlas_offs;
|
||||
vec3 model_pos;
|
||||
// bit 0 - is player
|
||||
// bit 1-31 - unused
|
||||
int flags;
|
||||
@ -18,6 +58,7 @@ uniform u_locals {
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
mat4 normals_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
@ -27,41 +68,155 @@ uniform u_bones {
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
diffuse_light *= point_shadow;
|
||||
ambient_light *= point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
// vec2 texSize = textureSize(t_col_light, 0);
|
||||
// vec4 col_light = texture(t_col_light, (f_uv_pos + 0.5) / texSize);
|
||||
// vec3 f_col = col_light.rgb;
|
||||
// float f_ao = col_light.a;
|
||||
|
||||
float ao = pow(f_ao, 0.5) * 0.85 + 0.15;
|
||||
// vec4 f_col_light = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0));
|
||||
// vec3 f_col = f_col_light.rgb;
|
||||
// float f_ao = f_col_light.a;
|
||||
|
||||
ambient_light *= ao;
|
||||
diffuse_light *= ao;
|
||||
// vec2 f_uv_pos = f_uv_pos + atlas_offs.xy;
|
||||
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0);
|
||||
// vec4 f_col_light = texelFetch(t_col_light, ivec2(int(f_uv_pos.x), int(f_uv_pos.y)/* + uv_delta*//* - f_norm * 0.00001*/), 0);
|
||||
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
|
||||
// vec3 f_col = vec3(1.0);
|
||||
// vec2 texSize = textureSize(t_col_light, 0);
|
||||
float f_ao = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// float /*f_light*/f_ao = textureProj(t_col_light, vec3(f_uv_pos, texSize)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
|
||||
vec3 surf_color = illuminate(srgb_to_linear(model_col.rgb * f_col), light, diffuse_light, ambient_light);
|
||||
// vec3 my_chunk_pos = (vec3((uvec3(f_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;
|
||||
// tgt_color = vec4(hash(floor(vec4(my_chunk_pos.x, 0, 0, 0))), hash(floor(vec4(0, my_chunk_pos.y, 0, 1))), hash(floor(vec4(0, 0, my_chunk_pos.z, 2))), 1.0);
|
||||
// float f_ao = 0;
|
||||
// tgt_color = vec4(vec3(f_ao), 1.0);
|
||||
// tgt_color = vec4(f_col, 1.0);
|
||||
// return;
|
||||
|
||||
// vec3 du = dFdx(f_pos);
|
||||
// vec3 dv = dFdy(f_pos);
|
||||
// vec3 f_norm = normalize(cross(du, dv));
|
||||
|
||||
// vec4 light_pos[2];
|
||||
//#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// vec4 sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
//#elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// vec4 sun_pos = vec4(0.0);
|
||||
//#endif
|
||||
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
// float sun_light = get_sun_brightness(sun_dir);
|
||||
// float moon_light = get_moon_brightness(moon_dir);
|
||||
/* float sun_shade_frac = horizon_at(f_pos, sun_dir);
|
||||
float moon_shade_frac = horizon_at(f_pos, moon_dir); */
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;// horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
|
||||
// Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-f_norm, sun_dir)) * 10000.0), 0.0, 0.5);
|
||||
// NOTE: current assumption is that moon and sun shouldn't be out at the sae time.
|
||||
// This assumption is (or can at least easily be) wrong, but if we pretend it's true we avoids having to explicitly pass in a separate shadow
|
||||
// for the sun and moon (since they have different brightnesses / colors so the shadows shouldn't attenuate equally).
|
||||
// float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
|
||||
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac/*, light_pos*/);
|
||||
|
||||
vec3 surf_color = /*srgb_to_linear*/(model_col.rgb * f_col);
|
||||
float alpha = 1.0;
|
||||
const float n2 = 1.5;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
vec3 k_a = vec3(1.0);
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
// vec3 light_frac = /*vec3(1.0);*//*vec3(max(dot(f_norm, -sun_dir) * 0.5 + 0.5, 0.0));*/light_reflection_factor(f_norm, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
//get_sun_diffuse(f_norm, time_of_day.x, view_dir, k_a * point_shadow * (shade_frac * 0.5 + light_frac * 0.5), k_d * point_shadow * shade_frac, k_s * point_shadow * shade_frac, alpha, emitted_light, reflected_light);
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
// reflected_light *= point_shadow * shade_frac;
|
||||
// emitted_light *= point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// max_light *= point_shadow * shade_frac;
|
||||
// reflected_light *= point_shadow;
|
||||
// emitted_light *= point_shadow;
|
||||
// max_light *= point_shadow;
|
||||
|
||||
max_light += lights_at(f_pos, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
|
||||
float ao = f_ao * sqrt(f_ao);//0.25 + f_ao * 0.75; ///*pow(f_ao, 0.5)*/f_ao * 0.85 + 0.15;
|
||||
|
||||
reflected_light *= ao;
|
||||
emitted_light *= ao;
|
||||
/* vec3 point_light = light_at(f_pos, f_norm);
|
||||
emitted_light += point_light;
|
||||
reflected_light += point_light; */
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, cam_to_frag, surf_color * f_light * point_shadow, 0.5 * surf_color * f_light * point_shadow, 0.5 * surf_color * f_light * point_shadow, 2.0, emitted_light, reflected_light);
|
||||
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
// diffuse_light *= point_shadow;
|
||||
// ambient_light *= point_shadow;
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// light += point_light;
|
||||
// diffuse_light += point_light;
|
||||
// reflected_light += point_light;
|
||||
// vec3 surf_color = illuminate(srgb_to_linear(model_col.rgb * f_col), light, diffuse_light, ambient_light);
|
||||
surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds);
|
||||
vec3 fog_color = get_sky_color(cam_to_frag/*view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 0.5, false, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec3 color = surf_color;
|
||||
#endif
|
||||
|
||||
if ((flags & 1) == 1 && int(cam_mode) == 1) {
|
||||
float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
|
||||
// if ((flags & 1) == 1 && int(cam_mode) == 1) {
|
||||
// float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
|
||||
|
||||
float opacity = clamp(distance / distance_divider, 0, 1);
|
||||
// float opacity = clamp(distance / distance_divider, 0, 1);
|
||||
|
||||
if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > opacity) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
// // if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > opacity) {
|
||||
// // discard;
|
||||
// // return;
|
||||
// // }
|
||||
// }
|
||||
|
||||
tgt_color = vec4(color, 1.0);
|
||||
}
|
||||
|
@ -1,16 +1,34 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
in uint v_pos_norm;
|
||||
in vec3 v_norm;
|
||||
in uint v_col;
|
||||
in uint v_ao_bone;
|
||||
in uint v_atlas_pos;
|
||||
|
||||
// in vec3 v_norm;
|
||||
/* in uint v_col;
|
||||
// out vec3 light_pos[2];
|
||||
in uint v_ao_bone; */
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
mat4 model_mat;
|
||||
vec4 model_col;
|
||||
ivec4 atlas_offs;
|
||||
vec3 model_pos;
|
||||
// bit 0 - is player
|
||||
// bit 1-31 - unused
|
||||
int flags;
|
||||
@ -18,6 +36,7 @@ uniform u_locals {
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
mat4 normals_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
@ -26,38 +45,96 @@ uniform u_bones {
|
||||
BoneData bones[16];
|
||||
};
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
out vec3 f_pos;
|
||||
out vec3 f_col;
|
||||
out float f_ao;
|
||||
// flat out uint f_pos_norm;
|
||||
flat out vec3 f_norm;
|
||||
// float dummy;
|
||||
/*centroid */out vec2 f_uv_pos;
|
||||
// out vec3 f_col;
|
||||
// out float f_ao;
|
||||
// out float f_alt;
|
||||
// out vec4 f_shadow;
|
||||
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// out vec4 sun_pos;
|
||||
// #endif
|
||||
|
||||
void main() {
|
||||
// Pre-calculate bone matrix
|
||||
uint bone_idx = (v_ao_bone >> 2) & 0x3Fu;
|
||||
mat4 combined_mat = model_mat * bones[bone_idx].bone_mat;
|
||||
/* uint bone_idx = (v_ao_bone >> 2) & 0x3Fu; */
|
||||
uint bone_idx = (v_pos_norm >> 27) & 0xFu;
|
||||
BoneData bone_data = bones[bone_idx];
|
||||
mat4 bone_mat = bone_data.bone_mat;
|
||||
mat4 combined_mat = /*model_mat * */bone_mat;
|
||||
|
||||
vec3 pos = (vec3((uvec3(v_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;
|
||||
|
||||
// vec4 bone_pos = bones[bone_idx].bone_mat * vec4(pos, 1);
|
||||
|
||||
f_pos = (
|
||||
combined_mat *
|
||||
vec4(pos, 1)).xyz;
|
||||
combined_mat *
|
||||
vec4(pos, 1.0)
|
||||
).xyz + (model_pos - focus_off.xyz);
|
||||
|
||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||
/* f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); */
|
||||
|
||||
f_col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0;
|
||||
f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(2, 17)) & uvec2(0x7FFFu, 0x7FFFu));
|
||||
|
||||
f_ao = float(v_ao_bone & 0x3u) / 4.0;
|
||||
// f_col = srgb_to_linear(vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0);
|
||||
// f_col = vec3(1.0);
|
||||
|
||||
// f_ao = float(v_ao_bone & 0x3u) / 4.0;
|
||||
// f_ao = 1.0;
|
||||
/* for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
light_pos[i] = vec3(shadowMats[i].texture_mat * vec4(f_pos, 1.0));
|
||||
} */
|
||||
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
vec3 norm = normals[(v_pos_norm >> 29) & 0x7u];
|
||||
// uint normal_idx = ((v_atlas_pos & 3u) << 1u) | (v_pos_norm >> 31u);
|
||||
// const vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
// vec3 norm = normals[normal_idx];
|
||||
uint axis_idx = v_atlas_pos & 3u;
|
||||
|
||||
// Calculate normal here rather than for each pixel in the fragment shader
|
||||
f_norm = normalize((
|
||||
combined_mat *
|
||||
vec4(norm, 0.0)
|
||||
).xyz);
|
||||
vec3 norm = bone_data.normals_mat[axis_idx].xyz;
|
||||
// norm = normalize(norm);
|
||||
// vec3 norm = norm_mat * vec4(uvec3(1 << axis_idx) & uvec3(0x1u, 0x3u, 0x7u), 1);
|
||||
|
||||
gl_Position = all_mat * vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
// // Calculate normal here rather than for each pixel in the fragment shader
|
||||
// f_norm = normalize((
|
||||
// combined_mat *
|
||||
// vec4(norm, 0)
|
||||
// ).xyz);
|
||||
f_norm = mix(-norm, norm, v_pos_norm >> 31u);
|
||||
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // #elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// // vec4 sun_pos = vec4(0.0);
|
||||
// #endif
|
||||
|
||||
// f_pos_norm = v_pos_norm;
|
||||
|
||||
// Also precalculate shadow texture and estimated terrain altitude.
|
||||
// f_alt = alt_at(f_pos.xy);
|
||||
// f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
|
||||
gl_Position = all_mat/*shadowMats[0].shadowMatrices*/ * vec4(f_pos, 1);
|
||||
// gl_Position.z = -gl_Position.z / 100.0 / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = gl_Position.z / 100.0;
|
||||
// gl_Position.z = -gl_Position.z;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
|
@ -1,17 +1,47 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION)
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in uint f_pos_norm;
|
||||
in vec3 f_col;
|
||||
in float f_light;
|
||||
// in vec3 f_col;
|
||||
// in float f_light;
|
||||
// in vec3 light_pos[2];
|
||||
|
||||
// struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
// };
|
||||
//
|
||||
// layout (std140)
|
||||
// uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
// };
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
uniform sampler2D t_waves;
|
||||
@ -20,37 +50,149 @@ out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
void main() {
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[]( vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) );
|
||||
// tgt_color = vec4(1.0 - MU_WATER, 1.0);
|
||||
// return;
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
|
||||
// TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction.
|
||||
uint norm_axis = (f_pos_norm >> 30) & 0x3u;
|
||||
// Increase array access by 3 to access positive values
|
||||
uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
|
||||
// Use an array to avoid conditional branching
|
||||
vec3 f_norm = normals[norm_axis + norm_dir];
|
||||
// TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction.
|
||||
uint norm_axis = (f_pos_norm >> 30) & 0x3u;
|
||||
// Increase array access by 3 to access positive values
|
||||
uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
|
||||
// Use an array to avoid conditional branching
|
||||
vec3 f_norm = normals[norm_axis + norm_dir];
|
||||
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 light_pos[2];
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// vec4 sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// #elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// vec4 sun_pos = vec4(0.0);
|
||||
// #endif
|
||||
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 0.0);
|
||||
float point_shadow = shadow_at(f_pos,f_norm);
|
||||
diffuse_light *= f_light * point_shadow;
|
||||
ambient_light *= f_light, point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
vec3 surf_color = srgb_to_linear(vec3(0.4, 0.7, 2.0)) * light * diffuse_light * ambient_light;
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
|
||||
/*const */vec3 water_color = (1.0 - MU_WATER) * MU_SCATTER;//srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.0, 0.25, 0.5));
|
||||
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds);
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag);
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
|
||||
// float sun_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, sun_dir);
|
||||
// float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir);
|
||||
// float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
|
||||
|
||||
vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + diffuse_light)), passthrough);
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac/*, light_pos*/);
|
||||
|
||||
tgt_color = mix(color, vec4(fog_color, 0.0), 0.0);
|
||||
float fluid_alt = f_pos.z;//max(ceil(f_pos.z), floor(f_alt));// f_alt;//max(f_alt - f_pos.z, 0.0);
|
||||
|
||||
const float alpha = 0.255/* / 4.0 / sqrt(2.0)*/;
|
||||
const float n2 = 1.3325;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float R_s = (f_pos.z < fluid_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
// Water is transparent so both normals are valid.
|
||||
vec3 cam_norm = faceforward(f_norm, f_norm, cam_to_frag);
|
||||
|
||||
vec3 mu = MU_WATER;
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation = vec3(1.0);//compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
|
||||
|
||||
// NOTE: Assumes normal is vertical.
|
||||
vec3 sun_view_dir = cam_pos.z <= fluid_alt ? /*refract(view_dir, -f_norm, 1.0 / n2)*//*reflect(view_dir, -f_norm)*/-view_dir : view_dir;//vec3(view_dir.xy, -view_dir.z) : view_dir;
|
||||
|
||||
vec3 k_a = vec3(1.0);
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
// float point_shadow = shadow_at(f_pos, f_norm);
|
||||
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec3 emitted_light, reflected_light;
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
// Squared to account for prior saturation.
|
||||
// float f_light = 1.0;// pow(f_light, 1.5);
|
||||
// float vert_light = f_light;
|
||||
// vec3 light_frac = /*vec3(1.0);*/light_reflection_factor(f_norm/*vec3(0, 0, 1.0)*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
|
||||
|
||||
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, /*time_of_day.x*//*-cam_to_frag*/sun_view_dir/*view_dir*/, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, /*vec3(0.0)*/k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
// reflected_light *= f_light * point_shadow * shade_frac;
|
||||
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// max_light *= f_light * point_shadow * shade_frac;
|
||||
// reflected_light *= f_light * point_shadow;
|
||||
// emitted_light *= f_light * point_shadow;
|
||||
// max_light *= f_light * point_shadow;
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 0.0);
|
||||
// diffuse_light *= f_light * point_shadow;
|
||||
// ambient_light *= f_light, point_shadow;
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// light += point_light;
|
||||
// diffuse_light += point_light;
|
||||
// reflected_light += point_light;
|
||||
// vec3 surf_color = srgb_to_linear(vec3(0.4, 0.7, 2.0)) * light * diffuse_light * ambient_light;
|
||||
|
||||
// lights_at(f_pos, f_norm, cam_to_frag, k_a * f_light * point_shadow, k_d * f_light * point_shadow, k_s * f_light * point_shadow, alpha, emitted_light, reflected_light);
|
||||
/*vec3 point_light = light_at(f_pos, f_norm);
|
||||
emitted_light += point_light;
|
||||
reflected_light += point_light; */
|
||||
|
||||
max_light += lights_at(f_pos, /*f_norm*/cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
// vec3 diffuse_light_point = vec3(0.0);
|
||||
// max_light += lights_at(f_pos, f_norm, view_dir, k_a, vec3(1.0), k_s, alpha, emitted_light, diffuse_light_point);
|
||||
|
||||
// float reflected_light_point = length(reflected_light);///*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||
// float reflected_light_point = dot(reflected_light, reflected_light) * 0.5;///*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||
// vec3 dump_light = vec3(0.0);
|
||||
// vec3 specular_light_point = vec3(0.0);
|
||||
// lights_at(f_pos, f_norm, view_dir, vec3(0.0), vec3(0.0), /*vec3(1.0)*/k_s, alpha, dump_light, specular_light_point);
|
||||
// diffuse_light_point -= specular_light_point;
|
||||
|
||||
// float reflected_light_point = /*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||
// reflected_light += k_d * (diffuse_light_point + f_light * point_shadow * shade_frac) + specular_light_point;
|
||||
|
||||
float passthrough = /*pow(*/dot(cam_norm, -cam_to_frag/*view_dir*/)/*, 0.5)*/;
|
||||
float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b));
|
||||
|
||||
vec3 surf_color = illuminate(max_light, view_dir, water_color * /* fog_color * */emitted_light, /*surf_color * */water_color * reflected_light);
|
||||
// vec4 color = vec4(surf_color, passthrough * 1.0 / (1.0 + min_refl));// * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (2.0 - log_cam)));
|
||||
vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*//*(f_light * point_shadow + point_light)*//*4.0 * reflected_light_point*/min_refl/* * 0.25*/)), passthrough);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(cam_to_frag, time_of_day.x, cam_pos.xyz, f_pos, 0.25, false, clouds);
|
||||
vec4 final_color = mix(mix(color, vec4(fog_color, 0.0), fog_level), vec4(clouds.rgb, 0.0), clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec4 final_color = color;
|
||||
#endif
|
||||
tgt_color = final_color;
|
||||
}
|
||||
|
@ -1,17 +1,49 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION)
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// https://www.shadertoy.com/view/XdsyWf
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in uint f_pos_norm;
|
||||
in vec3 f_col;
|
||||
in float f_light;
|
||||
// in vec3 f_col;
|
||||
// in float f_light;
|
||||
// in vec3 light_pos[2];
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
uniform sampler2D t_waves;
|
||||
@ -20,6 +52,7 @@ out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
vec3 warp_normal(vec3 norm, vec3 pos, float time) {
|
||||
return normalize(norm
|
||||
@ -68,7 +101,20 @@ void main() {
|
||||
// Use an array to avoid conditional branching
|
||||
vec3 f_norm = normals[norm_axis + norm_dir];
|
||||
|
||||
// vec4 light_pos[2];
|
||||
//#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// vec4 sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
//#elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// vec4 sun_pos = vec4(0.0);
|
||||
//#endif
|
||||
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
float frag_dist = length(f_pos - cam_pos.xyz);
|
||||
|
||||
vec3 b_norm;
|
||||
@ -81,9 +127,10 @@ void main() {
|
||||
}
|
||||
vec3 c_norm = cross(f_norm, b_norm);
|
||||
|
||||
float wave00 = wave_height(f_pos);
|
||||
float wave10 = wave_height(f_pos + vec3(0.1, 0, 0));
|
||||
float wave01 = wave_height(f_pos + vec3(0, 0.1, 0));
|
||||
vec3 wave_pos = f_pos + focus_off.xyz;
|
||||
float wave00 = wave_height(wave_pos);
|
||||
float wave10 = wave_height(wave_pos + vec3(0.1, 0, 0));
|
||||
float wave01 = wave_height(wave_pos + vec3(0, 0.1, 0));
|
||||
|
||||
float slope = abs(wave00 - wave10) * abs(wave00 - wave01);
|
||||
vec3 nmap = vec3(
|
||||
@ -95,32 +142,190 @@ void main() {
|
||||
nmap = mix(f_norm, normalize(nmap), min(1.0 / pow(frag_dist, 0.75), 1));
|
||||
|
||||
vec3 norm = vec3(0, 0, 1) * nmap.z + b_norm * nmap.x + c_norm * nmap.y;
|
||||
// vec3 norm = f_norm;
|
||||
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(norm, time_of_day.x, light, diffuse_light, ambient_light, 0.0);
|
||||
float point_shadow = shadow_at(f_pos, norm);
|
||||
diffuse_light *= f_light * point_shadow;
|
||||
ambient_light *= f_light, point_shadow;
|
||||
vec3 point_light = light_at(f_pos, norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
vec3 water_color = (1.0 - MU_WATER) * MU_SCATTER;
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds);
|
||||
float fluid_alt = max(ceil(f_pos.z), floor(f_alt));// f_alt;//max(f_alt - f_pos.z, 0.0);
|
||||
const float alpha = 0.255/*/ / 4.0*//* / 4.0 / sqrt(2.0)*/;
|
||||
const float n2 = 1.3325;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float R_s = (f_pos.z < fluid_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
vec3 reflect_ray_dir = reflect(cam_to_frag, norm);
|
||||
// Water is transparent so both normals are valid.
|
||||
vec3 cam_norm = faceforward(norm, norm, cam_to_frag);
|
||||
vec4 _clouds;
|
||||
vec3 reflect_ray_dir = reflect(cam_to_frag/*-view_dir*/, norm);
|
||||
vec3 refract_ray_dir = refract(cam_to_frag/*-view_dir*/, norm, 1.0 / n2);
|
||||
vec3 sun_view_dir = view_dir;///*sign(cam_pos.z - fluid_alt) * view_dir;*/cam_pos.z <= fluid_alt ? -view_dir : view_dir;
|
||||
// vec3 sun_view_dir = cam_pos.z <= fluid_alt ? -view_dir : view_dir;
|
||||
vec3 beam_view_dir = reflect_ray_dir;//cam_pos.z <= fluid_alt ? -refract_ray_dir : reflect_ray_dir;
|
||||
/* vec4 reflect_ray_dir4 = view_mat * vec4(reflect_ray_dir, 1.0);
|
||||
reflect_ray_dir = normalize(vec3(reflect_ray_dir4) / reflect_ray_dir4.w); */
|
||||
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// Squared to account for prior saturation.
|
||||
float f_light = 1.0;// pow(f_light, 1.5);
|
||||
vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/beam_view_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, true, _clouds) * f_light;
|
||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0));
|
||||
// NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
|
||||
// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water
|
||||
// /*const */vec3 water_attenuation = MU_WATER;// vec3(0.8, 0.05, 0.01);
|
||||
// /*const */vec3 water_color = vec3(0.2, 0.95, 0.99);
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;// horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
|
||||
// float sun_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, sun_dir);
|
||||
// float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir);
|
||||
// float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
|
||||
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac/*, light_pos*/);
|
||||
|
||||
// Hack to determine water depth: color goes down with distance through water, so
|
||||
// we assume water color absorption from this point a to some other point b is the distance
|
||||
// along the the ray from a to b where it intersects with the surface plane; if it doesn't,
|
||||
// then the whole segment from a to b is considered underwater.
|
||||
// TODO: Consider doing for point lights.
|
||||
// vec3 cam_surface_dir = faceforward(vec3(0.0, 0.0, 1.0), cam_to_frag, vec3(0.0, 0.0, 1.0));
|
||||
|
||||
// vec3 water_intersection_surface_camera = vec3(cam_pos);
|
||||
// bool _water_intersects_surface_camera = IntersectRayPlane(f_pos, view_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), cam_surface_dir, water_intersection_surface_camera);
|
||||
// // Should work because we set it up so that if IntersectRayPlane returns false for camera, its default intersection point is cam_pos.
|
||||
// float water_depth_to_camera = length(water_intersection_surface_camera - f_pos);
|
||||
|
||||
// vec3 water_intersection_surface_light = f_pos;
|
||||
// bool _light_intersects_surface_water = IntersectRayPlane(f_pos, sun_dir.z <= 0.0 ? sun_dir : moon_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), vec3(0.0, 0.0, 1.0), water_intersection_surface_light);
|
||||
// // Should work because we set it up so that if IntersectRayPlane returns false for light, its default intersection point is f_pos--
|
||||
// // i.e. if a light ray can't hit the water, it shouldn't contribute to coloring at all.
|
||||
// float water_depth_to_light = length(water_intersection_surface_light - f_pos);
|
||||
|
||||
// // For ambient color, we just take the distance to the surface out of laziness.
|
||||
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
|
||||
|
||||
// // Color goes down with distance...
|
||||
// // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
|
||||
// vec3 water_color_direct = exp(-MU_WATER);//exp(-MU_WATER);//vec3(1.0);
|
||||
// vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera));
|
||||
// vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera));
|
||||
vec3 mu = MU_WATER;
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
|
||||
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
|
||||
// For ambient color, we just take the distance to the surface out of laziness.
|
||||
// See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
|
||||
// float water_depth_to_vertical = max(fluid_alt - cam_pos.z/*f_light*/, 0.0);
|
||||
// vec3 ambient_attenuation = exp(-mu * water_depth_to_vertical);
|
||||
|
||||
// For ambient reflection, we just take the water
|
||||
|
||||
vec3 k_a = vec3(1.0);
|
||||
// Oxygen is light blue.
|
||||
vec3 k_d = vec3(/*vec3(0.2, 0.9, 0.99)*/1.0);
|
||||
vec3 k_s = vec3(R_s);//2.0 * reflect_color;
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
// vec3 light_frac = /*vec3(1.0);*/light_reflection_factor(f_norm/*vec3(0, 0, 1.0)*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
|
||||
// 0 = 100% reflection, 1 = translucent water
|
||||
float passthrough = /*pow(*/dot(faceforward(norm, norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/;
|
||||
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, norm, /*time_of_day.x*/sun_view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(k_d), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
// reflected_light *= /*water_color_direct * */reflect_color * f_light * point_shadow * shade_frac;
|
||||
// emitted_light *= /*water_color_direct*//*ambient_attenuation * */f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// max_light *= f_light * point_shadow * shade_frac;
|
||||
// reflected_light *= /*water_color_direct * */reflect_color * f_light * point_shadow;
|
||||
// emitted_light *= /*water_color_direct*//*ambient_attenuation * */f_light * point_shadow;
|
||||
// max_light *= f_light * point_shadow;
|
||||
|
||||
// vec3 diffuse_light_point = vec3(0.0);
|
||||
// max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, vec3(1.0), /*vec3(0.0)*/k_s, alpha, emitted_light, diffuse_light_point);
|
||||
|
||||
// vec3 dump_light = vec3(0.0);
|
||||
// vec3 specular_light_point = vec3(0.0);
|
||||
// lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, vec3(0.0), vec3(0.0), /*vec3(1.0)*/k_s, alpha, dump_light, specular_light_point);
|
||||
// diffuse_light_point -= specular_light_point;
|
||||
// max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*/vec3(0.0), /*vec3(0.0)*/k_s, alpha, emitted_light, /*diffuse_light*/reflected_light);
|
||||
|
||||
max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*//*vec3(0.0)*/k_d, /*vec3(0.0)*/k_s, alpha, f_norm, 1.0, emitted_light, /*diffuse_light*/reflected_light);
|
||||
|
||||
float reflected_light_point = length(reflected_light);///*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||
// TODO: See if we can be smarter about this using point light distances.
|
||||
// reflected_light += k_d * (diffuse_light_point/* + f_light * point_shadow * shade_frac*/) + /*water_color_ambient*/specular_light_point;
|
||||
|
||||
/* vec3 point_light = light_at(f_pos, norm);
|
||||
emitted_light += point_light;
|
||||
reflected_light += point_light; */
|
||||
|
||||
// get_sun_diffuse(norm, time_of_day.x, light, diffuse_light, ambient_light, 0.0);
|
||||
// diffuse_light *= f_light * point_shadow;
|
||||
// ambient_light *= f_light * point_shadow;
|
||||
// vec3 point_light = light_at(f_pos, norm);
|
||||
// light += point_light;
|
||||
// diffuse_light += point_light;
|
||||
// reflected_light += point_light;
|
||||
// vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)) * light * diffuse_light * ambient_light;
|
||||
vec3 surf_color = illuminate(max_light, view_dir, water_color * emitted_light/* * log(1.0 - MU_WATER)*/, /*cam_attenuation * *//*water_color * */reflect_color * reflected_light/* * log(1.0 - MU_WATER)*/);
|
||||
|
||||
// passthrough = pow(passthrough, 1.0 / (1.0 + water_depth_to_camera));
|
||||
/* surf_color = cam_attenuation.g < 0.5 ?
|
||||
vec3(1.0, 0.0, 0.0) :
|
||||
vec3(0.0, 1.0, 1.0)
|
||||
; */
|
||||
// passthrough = passthrough * length(cam_attenuation);
|
||||
|
||||
// vec3 reflect_ray_dir = reflect(cam_to_frag, norm);
|
||||
// Hack to prevent the reflection ray dipping below the horizon and creating weird blue spots in the water
|
||||
reflect_ray_dir.z = max(reflect_ray_dir.z, 0.01);
|
||||
// reflect_ray_dir.z = max(reflect_ray_dir.z, 0.01);
|
||||
|
||||
vec4 _clouds;
|
||||
vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, false, _clouds) * f_light;
|
||||
// vec4 _clouds;
|
||||
// vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, false, _clouds) * f_light;
|
||||
// Tint
|
||||
reflect_color = reflect_color * 0.5 * (diffuse_light + ambient_light);
|
||||
// reflect_color = mix(reflect_color, surf_color, 0.6);
|
||||
|
||||
// vec4 color = mix(vec4(reflect_color * 2.0, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*/(f_light * point_shadow + point_light) * 0.25)), passthrough);
|
||||
// vec4 color = mix(vec4(reflect_color * 2.0, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*/(/*f_light * point_shadow*/f_light * point_shadow + reflected_light_point/* + point_light*//*reflected_light*/) * 0.25)), passthrough);
|
||||
// vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 0.0), passthrough);
|
||||
//vec4 color = vec4(surf_color, 1.0);
|
||||
// vec4 color = mix(vec4(reflect_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point/* + point_light*//*reflected_light*/))), passthrough);
|
||||
|
||||
// float log_cam = log(min(cam_attenuation.r, min(cam_attenuation.g, cam_attenuation.b)));
|
||||
float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b));
|
||||
vec4 color = vec4(surf_color, (1.0 - passthrough) * 1.0 / (1.0 + min_refl));// * (1.0 - /*log(1.0 + cam_attenuation)*//*cam_attenuation*/1.0 / (2.0 - log_cam)));
|
||||
// vec4 color = vec4(surf_color, mix(1.0, 1.0 / (1.0 + /*0.25 * *//*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point)), passthrough));
|
||||
// vec4 color = vec4(surf_color, mix(1.0, length(cam_attenuation), passthrough));
|
||||
|
||||
/* reflect_color = reflect_color * 0.5 * (diffuse_light + ambient_light);
|
||||
// 0 = 100% reflection, 1 = translucent water
|
||||
float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag);
|
||||
|
||||
vec4 color = mix(vec4(reflect_color, 1.0), vec4(vec3(0), 1.0 / (1.0 + diffuse_light * 0.25)), passthrough);
|
||||
vec4 color = mix(vec4(reflect_color, 1.0), vec4(vec3(0), 1.0 / (1.0 + diffuse_light * 0.25)), passthrough); */
|
||||
|
||||
tgt_color = mix(mix(color, vec4(fog_color, 0.0), fog_level), vec4(clouds.rgb, 0.0), clouds.a);
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(cam_to_frag/*-view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 0.25, false, clouds);
|
||||
vec4 final_color = mix(mix(color, vec4(fog_color, 0.0), fog_level), vec4(clouds.rgb, 0.0), clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec4 final_color = color;
|
||||
#endif
|
||||
tgt_color = final_color;
|
||||
}
|
||||
|
@ -1,46 +1,83 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION)
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
in uint v_pos_norm;
|
||||
in uint v_col_light;
|
||||
// in uint v_col_light;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
// struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
// };
|
||||
//
|
||||
// layout (std140)
|
||||
// uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
// };
|
||||
|
||||
out vec3 f_pos;
|
||||
flat out uint f_pos_norm;
|
||||
flat out vec3 f_norm;
|
||||
out vec3 f_col;
|
||||
out float f_light;
|
||||
// out vec3 f_col;
|
||||
// out float f_light;
|
||||
// out vec3 light_pos[2];
|
||||
|
||||
const float EXTRA_NEG_Z = 65536.0;
|
||||
const float EXTRA_NEG_Z = 65536.0/*65536.1*/;
|
||||
|
||||
void main() {
|
||||
f_pos = vec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0x1FFFFu)) - vec3(0, 0, EXTRA_NEG_Z) + model_offs;
|
||||
f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
|
||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||
f_pos = vec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0x1FFFFu)) - vec3(0, 0, EXTRA_NEG_Z) + model_offs - focus_off.xyz;
|
||||
// f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
|
||||
// f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0));
|
||||
|
||||
// Small waves
|
||||
f_pos.xy += 0.01; // Avoid z-fighting
|
||||
f_pos.z -= 0.1 + 0.1 * (sin(tick.x * 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5;
|
||||
// Small waves
|
||||
// f_pos.xy += 0.01; // Avoid z-fighting
|
||||
// f_pos.x += 0.1 * sin(tick.x / 60 * hash(vec4(f_pos.xyz, 1.0)));
|
||||
// f_pos.y += 0.1 * sin(tick.x / 60 * hash(vec4(f_pos.xyz, 2.0)));
|
||||
#if (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
// f_pos.z -= 0.1 + 0.1 * (sin(tick.x/* / 60.0*/* 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5;
|
||||
#endif
|
||||
|
||||
f_col = vec3(
|
||||
float((v_col_light >> 8) & 0xFFu),
|
||||
float((v_col_light >> 16) & 0xFFu),
|
||||
float((v_col_light >> 24) & 0xFFu)
|
||||
/* f_col = vec3(
|
||||
float((v_col_light >> 8) & 0xFFu),
|
||||
float((v_col_light >> 16) & 0xFFu),
|
||||
float((v_col_light >> 24) & 0xFFu)
|
||||
) / 255.0;
|
||||
|
||||
f_light = float(v_col_light & 0xFFu) / 255.0;
|
||||
f_light = float(v_col_light & 0xFFu) / 255.0; */
|
||||
/* for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
light_pos[i] = vec3(shadowMats[i].texture_mat * vec4(f_pos, 1.0));
|
||||
} */
|
||||
|
||||
f_pos_norm = v_pos_norm;
|
||||
f_pos_norm = v_pos_norm;
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
uniform sampler2D t_noise;
|
||||
|
||||
vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, float quality) {
|
||||
return vec4(0.0);
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
uniform sampler2D t_noise;
|
||||
#include <random.glsl>
|
||||
|
||||
const float CLOUD_AVG_HEIGHT = 1025.0;
|
||||
const float CLOUD_HEIGHT_MIN = CLOUD_AVG_HEIGHT - 60.0;
|
||||
const float CLOUD_HEIGHT_MAX = CLOUD_AVG_HEIGHT + 60.0;
|
||||
const float CLOUD_THRESHOLD = 0.27;
|
||||
const float CLOUD_SCALE = 5.0;
|
||||
const float CLOUD_DENSITY = 100.0;
|
||||
@ -11,7 +8,15 @@ float vsum(vec3 v) {
|
||||
return v.x + v.y + v.z;
|
||||
}
|
||||
|
||||
vec3 get_cloud_heights() {
|
||||
float CLOUD_AVG_HEIGHT = /*1025.0*/view_distance.z + 0.7 * view_distance.w;
|
||||
float CLOUD_HEIGHT_MIN = CLOUD_AVG_HEIGHT - 60.0;
|
||||
float CLOUD_HEIGHT_MAX = CLOUD_AVG_HEIGHT + 60.0;
|
||||
return vec3(CLOUD_AVG_HEIGHT, CLOUD_HEIGHT_MIN, CLOUD_HEIGHT_MAX);
|
||||
}
|
||||
|
||||
vec2 cloud_at(vec3 pos) {
|
||||
vec3 max_heights = get_cloud_heights();
|
||||
vec2 scaled_pos = pos.xy / CLOUD_SCALE;
|
||||
|
||||
float tick_offs = 0.0
|
||||
@ -29,10 +34,10 @@ vec2 cloud_at(vec3 pos) {
|
||||
+ texture(t_noise, scaled_pos * 0.02 + tick_offs + time_of_day.x * 0.0002).x * 0.15
|
||||
) * value;
|
||||
|
||||
float density = max((value - CLOUD_THRESHOLD) - abs(pos.z - CLOUD_AVG_HEIGHT) / 200.0, 0.0) * CLOUD_DENSITY;
|
||||
float density = max((value - CLOUD_THRESHOLD) - abs(pos.z - max_heights.x) / 200.0, 0.0) * CLOUD_DENSITY;
|
||||
|
||||
const float SHADE_GRADIENT = 1.5 / (CLOUD_AVG_HEIGHT - CLOUD_HEIGHT_MIN);
|
||||
float shade = (pos.z - CLOUD_AVG_HEIGHT) / (CLOUD_HEIGHT_MAX - CLOUD_HEIGHT_MIN) * 5.0 + 0.3;
|
||||
float SHADE_GRADIENT = 1.5 / (max_heights.x - max_heights.y);
|
||||
float shade = ((pos.z - max_heights.x) / (max_heights.z - max_heights.y)) * 5.0 + 0.3;
|
||||
|
||||
return vec2(shade, density / (1.0 + vsum(abs(pos - cam_pos.xyz)) / 5000));
|
||||
}
|
||||
@ -40,9 +45,11 @@ vec2 cloud_at(vec3 pos) {
|
||||
vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, float quality) {
|
||||
const int ITERS = 12;
|
||||
const float INCR = 1.0 / ITERS;
|
||||
origin = origin + focus_off.xyz;
|
||||
|
||||
float mind = (CLOUD_HEIGHT_MIN - origin.z) / dir.z;
|
||||
float maxd = (CLOUD_HEIGHT_MAX - origin.z) / dir.z;
|
||||
vec3 max_heights = get_cloud_heights();
|
||||
float mind = (max_heights.y - origin.z) / dir.z;
|
||||
float maxd = (max_heights.z - origin.z) / dir.z;
|
||||
|
||||
float start = max(min(mind, maxd), 0.0);
|
||||
float delta = min(abs(mind - maxd), max_dist);
|
||||
@ -57,11 +64,11 @@ vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, f
|
||||
dist += fuzz * 0.01 * min(pow(dist * 0.005, 2.0), 1.0);
|
||||
|
||||
vec3 pos = origin + dir * min(dist, max_dist);
|
||||
vec2 sample = cloud_at(pos);
|
||||
vec2 sample_ = cloud_at(pos);
|
||||
|
||||
float integral = sample.y * INCR;
|
||||
float integral = sample_.y * INCR;
|
||||
passthrough *= 1.0 - integral;
|
||||
cloud_shade = mix(cloud_shade, sample.x, passthrough * integral);
|
||||
cloud_shade = mix(cloud_shade, sample_.x, passthrough * integral);
|
||||
dist += INCR * delta;
|
||||
|
||||
if (passthrough < 0.1) {
|
||||
@ -70,7 +77,7 @@ vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, f
|
||||
}
|
||||
}
|
||||
|
||||
float total_density = 1.0 - passthrough / (1.0 + delta * 0.0001);
|
||||
float total_density = 1.0 - passthrough / (1.0 + pow(max_dist, 0.5) * 0.0001 + max((0.015 - dir.z) * 0.0001, 0.0) * max_dist);
|
||||
|
||||
total_density = max(total_density - 1.0 / pow(max_dist, 0.25), 0.0); // Hack
|
||||
|
||||
|
73
assets/voxygen/shaders/include/constants.glsl
Normal file
73
assets/voxygen/shaders/include/constants.glsl
Normal file
@ -0,0 +1,73 @@
|
||||
/* NOTE: When included, this file will contain values for the automatically defined settings specified below. */
|
||||
|
||||
/* TODO: Add the ability to control the tendency to do stuff in the vertex vs. fragment shader.
|
||||
* Currently this flag is ignored and always set to prefer fragment, but this tradeoff is not correct on all
|
||||
* machines in all cases (mine, for instance). */
|
||||
#define VOXYGEN_COMPUTATION_PREERENCE_FRAGMENT 0
|
||||
#define VOXYGEN_COMPUTATION_PREERENCE_VERTEX 1
|
||||
|
||||
#define FLUID_MODE_CHEAP 0
|
||||
#define FLUID_MODE_SHINY 1
|
||||
|
||||
#define CLOUD_MODE_NONE 0
|
||||
#define CLOUD_MODE_REGULAR 1
|
||||
|
||||
#define LIGHTING_ALGORITHM_LAMBERTIAN 0
|
||||
#define LIGHTING_ALGORITHM_BLINN_PHONG 1
|
||||
#define LIGHTING_ALGORITHM_ASHIKHMIN 2
|
||||
|
||||
#define SHADOW_MODE_NONE 0
|
||||
#define SHADOW_MODE_CHEAP 1
|
||||
#define SHADOW_MODE_MAP 2
|
||||
|
||||
/* Unlike the other flags (for now anyway), these are bitmask values */
|
||||
#define LIGHTING_TYPE_REFLECTION 0x01
|
||||
#define LIGHTING_TYPE_TRANSMISSION 0x02
|
||||
|
||||
/* Currently ignored, but ideally shoud be helpful for determining light transport properties. */
|
||||
#define LIGHTING_REFLECTION_KIND_DIFFUSE 0
|
||||
#define LIGHTING_REFLECTION_KIND_GLOSSY 1
|
||||
#define LIGHTING_REFLECTION_KIND_SPECULAR 2
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE_IMPORTANCE 0
|
||||
/* Radiance mode is currently used as a proxy for "attenuation and medium materials
|
||||
* matter," but we may make it more granular. */
|
||||
#define LIGHTING_TRANSPORT_MODE_RADIANCE 1
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME_MICROFACET 0
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME_VOXEL 1
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_BECKMANN 0
|
||||
#define LIGHTING_DISTRIBUTION_TROWBRIDGE 1
|
||||
|
||||
/* Constants expected to be defined automatically by configuration: */
|
||||
|
||||
/*
|
||||
#define VOXYGEN_COMPUTATION_PREERENCE <preference>
|
||||
#define FLUID_MODE <mode>
|
||||
#define CLOUD_MODE <mode>
|
||||
#define LIGHTING_ALGORITHM <algorithm>
|
||||
#define SHADOW_MODE <mode>
|
||||
*/
|
||||
|
||||
/* Constants expected to be defined by any shader that needs to perform lighting calculations
|
||||
* (but whose values may take automatically defined constants into account): */
|
||||
|
||||
/*
|
||||
// At least one of LIGHTING_TYPE_REFLECTION or LIGHTING_TYPE_TRANSMISSION should be set.
|
||||
#define LIGHTING_TYPE <type bitmask>
|
||||
#define LIGHTING_REFLECTION_KIND <kind>
|
||||
#define LIGHTING_TRANSPORT_MODE <mode>
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME <scheme>
|
||||
#define LIGHTING_DISTRIBUTION <distribution>
|
||||
*/
|
||||
|
||||
/* Constants that *may* be defined by any shader.
|
||||
* (and whose values may take automatically defined constants into account): */
|
||||
|
||||
/*
|
||||
// When sets, shadow maps are used to cast shadows.
|
||||
#define HAS_SHADOW_MAPS
|
||||
// When set, "full" LOD terrain informatino is available (e.g. terrain colors).
|
||||
#define HAS_LOD_FULL_INFO
|
||||
*/
|
@ -4,12 +4,16 @@ uniform u_globals {
|
||||
mat4 proj_mat;
|
||||
mat4 all_mat;
|
||||
vec4 cam_pos;
|
||||
vec4 focus_off;
|
||||
vec4 focus_pos;
|
||||
vec4 view_distance;
|
||||
vec4 time_of_day;
|
||||
vec4 sun_dir;
|
||||
vec4 moon_dir;
|
||||
vec4 tick;
|
||||
vec4 screen_res;
|
||||
uvec4 light_shadow_count;
|
||||
vec4 shadow_proj_factors;
|
||||
uvec4 medium;
|
||||
ivec4 select_pos;
|
||||
vec4 gamma;
|
||||
|
@ -1,11 +1,15 @@
|
||||
#include <srgb.glsl>
|
||||
#include <shadows.glsl>
|
||||
|
||||
struct Light {
|
||||
vec4 light_pos;
|
||||
vec4 light_col;
|
||||
// mat4 light_proj;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_lights {
|
||||
Light lights[32];
|
||||
Light lights[31];
|
||||
};
|
||||
|
||||
struct Shadow {
|
||||
@ -17,21 +21,45 @@ uniform u_shadows {
|
||||
Shadow shadows[24];
|
||||
};
|
||||
|
||||
#include <srgb.glsl>
|
||||
|
||||
vec3 illuminate(vec3 color, vec3 light, vec3 diffuse, vec3 ambience) {
|
||||
float avg_col = (color.r + color.g + color.b) / 3.0;
|
||||
return ((color - avg_col) * light + (diffuse + ambience) * avg_col) * (diffuse + ambience);
|
||||
}
|
||||
|
||||
float attenuation_strength(vec3 rpos) {
|
||||
// This is not how light attenuation works at all, but it produces visually pleasing and mechanically useful properties
|
||||
float d2 = rpos.x * rpos.x + rpos.y * rpos.y + rpos.z * rpos.z;
|
||||
return max(2.0 / pow(d2 + 10, 0.35) - pow(d2 / 50000.0, 0.8), 0.0);
|
||||
}
|
||||
|
||||
// // Compute attenuation due to light passing through a substance that fills an area below a horizontal plane
|
||||
// // (e.g. in most cases, water below the water surface depth).
|
||||
// //
|
||||
// // wpos is the position of the point being hit.
|
||||
// // ray_dir is the reversed direction of the ray (going "out" of the point being hit).
|
||||
// // surface_alt is the estimated altitude of the horizontal surface separating the substance from air.
|
||||
// // defaultpos is the position to use in computing the distance along material at this point if there was a failure.
|
||||
// //
|
||||
// // Ideally, defaultpos is set so we can avoid branching on error.
|
||||
// float compute_attenuation_beam(vec3 wpos, vec3 ray_dir, float surface_alt, vec3 defaultpos, float attenuation_depth) {
|
||||
// vec3 water_intersection_surface_camera = vec3(cam_pos);
|
||||
// bool _water_intersects_surface_camera = IntersectRayPlane(f_pos, view_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), cam_surface_dir, water_intersection_surface_camera);
|
||||
// // Should work because we set it up so that if IntersectRayPlane returns false for camera, its default intersection point is cam_pos.
|
||||
// float water_depth_to_camera = length(water_intersection_surface_camera - f_pos);
|
||||
//
|
||||
// vec3 water_intersection_surface_light = f_pos;
|
||||
// bool _light_intersects_surface_water = IntersectRayPlane(f_pos, sun_dir.z <= 0.0 ? sun_dir : moon_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), vec3(0.0, 0.0, 1.0), water_intersection_surface_light);
|
||||
// // Should work because we set it up so that if IntersectRayPlane returns false for light, its default intersection point is f_pos--
|
||||
// // i.e. if a light ray can't hit the water, it shouldn't contribute to coloring at all.
|
||||
// float water_depth_to_light = length(water_intersection_surface_light - f_pos);
|
||||
//
|
||||
// // For ambient color, we just take the distance to the surface out of laziness.
|
||||
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
|
||||
//
|
||||
// // Color goes down with distance...
|
||||
// // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
|
||||
// vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera));
|
||||
// vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera));
|
||||
//
|
||||
// }
|
||||
|
||||
vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
const float LIGHT_AMBIENCE = 0.025;
|
||||
const float LIGHT_AMBIANCE = 0.025;
|
||||
|
||||
vec3 light = vec3(0);
|
||||
|
||||
@ -40,7 +68,7 @@ vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
// Only access the array once
|
||||
Light L = lights[i];
|
||||
|
||||
vec3 light_pos = L.light_pos.xyz;
|
||||
vec3 light_pos = L.light_pos.xyz - focus_off.xyz;
|
||||
|
||||
// Pre-calculate difference between light and fragment
|
||||
vec3 difference = light_pos - wpos;
|
||||
@ -50,7 +78,7 @@ vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
// Multiply the vec3 only once
|
||||
vec3 color = srgb_to_linear(L.light_col.rgb) * (strength * L.light_col.a);
|
||||
|
||||
light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIENCE);
|
||||
light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIANCE);
|
||||
}
|
||||
return light;
|
||||
}
|
||||
@ -58,12 +86,15 @@ vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
float shadow_at(vec3 wpos, vec3 wnorm) {
|
||||
float shadow = 1.0;
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_NONE || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
return shadow;
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_CHEAP)
|
||||
for (uint i = 0u; i < light_shadow_count.y; i ++) {
|
||||
|
||||
// Only access the array once
|
||||
Shadow S = shadows[i];
|
||||
|
||||
vec3 shadow_pos = S.shadow_pos_radius.xyz;
|
||||
vec3 shadow_pos = S.shadow_pos_radius.xyz - focus_off.xyz;
|
||||
float radius = S.shadow_pos_radius.w;
|
||||
|
||||
vec3 diff = shadow_pos - wpos;
|
||||
@ -72,8 +103,130 @@ float shadow_at(vec3 wpos, vec3 wnorm) {
|
||||
}
|
||||
|
||||
float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.25) / pow(radius * radius * 0.5, 0.25), 0.5);
|
||||
// float shade = max(pow(dot(diff, diff) / (radius * radius * 0.5), 0.25), 0.5);
|
||||
// float shade = dot(diff, diff) / (radius * radius * 0.5);
|
||||
|
||||
shadow = min(shadow, shade);
|
||||
}
|
||||
// NOTE: Squared to compenate for prior saturation.
|
||||
return min(shadow, 1.0);
|
||||
// return min(shadow * shadow, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns computed maximum intensity.
|
||||
//
|
||||
// mu is the attenuation coefficient for any substance on a horizontal plane.
|
||||
// cam_attenuation is the total light attenuation due to the substance for beams between the point and the camera.
|
||||
// surface_alt is the altitude of the attenuating surface.
|
||||
float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 voxel_norm, float voxel_lighting, inout vec3 emitted_light, inout vec3 reflected_light/*, out float shadow*/) {
|
||||
// return 0.0;
|
||||
// shadow = 0.0;
|
||||
// vec3 ambient_light = vec3(0.0);
|
||||
vec3 directed_light = vec3(0.0);
|
||||
vec3 max_light = vec3(0.0);
|
||||
|
||||
const float LIGHT_AMBIANCE = 0.0;//0.015625;
|
||||
|
||||
for (uint i = 0u; i < /*light_shadow_count.x*//*0u*/light_shadow_count.x/*32u*/; i ++) {
|
||||
|
||||
// Only access the array once
|
||||
Light L = lights[i];
|
||||
|
||||
vec3 light_pos = L.light_pos.xyz - focus_off.xyz;
|
||||
|
||||
// Pre-calculate difference between light and fragment
|
||||
vec3 difference = light_pos - wpos;
|
||||
float distance_2 = dot(difference, difference);
|
||||
|
||||
// float strength = attenuation_strength(difference);// pow(attenuation_strength(difference), 0.6);
|
||||
// // NOTE: This normalizes strength to 1.0 at the center of the point source.
|
||||
// float strength = 1.0 / (1.0 + distance_2);
|
||||
float strength = 1.0 / distance_2;
|
||||
|
||||
// Multiply the vec3 only once
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
const float PI_2 = 2 * PI;
|
||||
float square_factor = /*2.0 * PI_2 * *//*2.0 * */L.light_col.a;
|
||||
vec3 color = /*srgb_to_linear*/L.light_col.rgb;
|
||||
|
||||
// // Only access the array once
|
||||
// Shadow S = shadows[i];
|
||||
|
||||
// vec3 shadow_pos = S.shadow_pos_radius.xyz;
|
||||
// float radius = S.shadow_pos_radius.w;
|
||||
|
||||
// vec3 diff = shadow_pos - wpos;
|
||||
// if (diff.z >= 0.0) {
|
||||
// diff.z = -sign(diff.z) * diff.z * 0.1;
|
||||
// }
|
||||
|
||||
// float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.25) / pow(radius * radius * 0.5, 0.25), /*0.5*/0.0);
|
||||
|
||||
// shadow = min(shadow, shade);
|
||||
|
||||
// Compute reflectance.
|
||||
float light_distance = sqrt(distance_2);
|
||||
vec3 light_dir = -difference / light_distance; // normalize(-difference);
|
||||
// light_dir = faceforward(light_dir, wnorm, light_dir);
|
||||
bool is_direct = dot(-light_dir, wnorm) > 0.0;
|
||||
// reflected_light += color * (distance_2 == 0.0 ? vec3(1.0) : light_reflection_factor(wnorm, cam_to_frag, light_dir, k_d, k_s, alpha));
|
||||
vec3 direct_light_dir = is_direct ? light_dir : -light_dir;
|
||||
// vec3 direct_norm_dir = is_direct ? wnorm : -wnorm;
|
||||
// Compute attenuation due to fluid.
|
||||
// Default is light_pos, so we take the whole segment length for this beam if it never intersects the surface, unlesss the beam itself
|
||||
// is above the surface, in which case we take zero (wpos).
|
||||
color *= cam_attenuation * compute_attenuation_point(wpos, -direct_light_dir, mu, surface_alt, light_pos.z < surface_alt ? light_pos : wpos);
|
||||
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
is_direct = true;
|
||||
#endif
|
||||
vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(/*direct_norm_dir*/wnorm, /*cam_to_frag*/view_dir, direct_light_dir, k_d, k_s, alpha, voxel_norm, voxel_lighting);
|
||||
float computed_shadow = ShadowCalculationPoint(i, -difference, wnorm, wpos/*, light_distance*/);
|
||||
// directed_light += is_direct ? max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light * square_factor : vec3(0.0);
|
||||
directed_light += is_direct ? mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light * square_factor : vec3(0.0);
|
||||
// directed_light += (is_direct ? 1.0 : LIGHT_AMBIANCE) * max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light * square_factor;// : vec3(0.0);
|
||||
// directed_light += mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light * square_factor;
|
||||
// ambient_light += is_direct ? vec3(0.0) : vec3(0.0); // direct_light * square_factor * LIGHT_AMBIANCE;
|
||||
// ambient_light += is_direct ? direct_light * (1.0 - square_factor * LIGHT_AMBIANCE) : vec3(0.0);
|
||||
|
||||
vec3 cam_light_diff = light_pos - focus_pos.xyz;
|
||||
float cam_distance_2 = dot(cam_light_diff, cam_light_diff);// + 0.0001;
|
||||
float cam_strength = 1.0 / (/*4.0 * *//*PI * *//*1.0 + */cam_distance_2);
|
||||
|
||||
// vec3 cam_pos_diff = cam_to_frag.xyz - wpos;
|
||||
// float pos_distance_2 = dot(cam_pos_diff, cam_pos_diff);// + 0.0001;
|
||||
|
||||
// float cam_distance = sqrt(cam_distance_2);
|
||||
// float distance = sqrt(distance_2);
|
||||
float both_strength = cam_distance_2 == 0.0 ? distance_2 == 0.0 ? 0.0 : strength/* * strength*//*1.0*/ : distance_2 == 0.0 ? cam_strength/* * cam_strength*//*1.0*/ :
|
||||
// 1.0 / (cam_distance * distance);
|
||||
// sqrt(cam_strength * strength);
|
||||
cam_strength + strength;
|
||||
// (cam_strength * strength);
|
||||
// max(cam_strength, strength);
|
||||
// mix(cam_strength, strength, distance_2 / (cam_distance_2 + distance_2));
|
||||
// mix(cam_strength, strength, cam_distance_2 / (cam_distance_2 + distance_2));
|
||||
// max(cam_strength, strength);//mix(cam_strength, strength, clamp(distance_2 / /*pos_distance_2*/cam_distance_2, 0.0, 1.0));
|
||||
// float both_strength = mix(cam_strength, strength, cam_distance_2 / sqrt(cam_distance_2 + distance_2));
|
||||
max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*//*max(both_strength, 1.0) * *//*cam_strength*/computed_shadow * both_strength * square_factor * square_factor * PI * color;
|
||||
// max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*/max(cam_strength, 1.0/*, strength*//*1.0*/) * square_factor * square_factor * PI * color;
|
||||
// light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIANCE);
|
||||
// Compute emiittance.
|
||||
// float ambient_sides = clamp(mix(0.15, 0.0, abs(dot(wnorm, light_dir)) * 10000.0), 0.0, 0.15);
|
||||
// float ambient_sides = 0.0;// max(dot(wnorm, light_dir) - 0.15, 0.15);
|
||||
// // float ambient_sides = 0.0;
|
||||
// ambient_light += color * (ambient_sides + LIGHT_AMBIANCE);
|
||||
}
|
||||
|
||||
// shadow = shadow_at(wpos, wnorm);
|
||||
// float shadow = shadow_at(wpos, wnorm);
|
||||
reflected_light += directed_light;
|
||||
// emitted_light += k_a * ambient_light/* * shadow*/;// min(shadow, 1.0);
|
||||
return /*rel_luminance(ambient_light + directed_light)*/rel_luminance(max_light);//ambient_light;
|
||||
}
|
||||
|
||||
// Same as lights_at, but with no assumed attenuation due to fluid.
|
||||
float lights_at(vec3 wpos, vec3 wnorm, vec3 view_dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light) {
|
||||
return lights_at(wpos, wnorm, view_dir, vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, wnorm, 1.0, emitted_light, reflected_light);
|
||||
}
|
||||
|
289
assets/voxygen/shaders/include/lod.glsl
Normal file
289
assets/voxygen/shaders/include/lod.glsl
Normal file
@ -0,0 +1,289 @@
|
||||
#include <random.glsl>
|
||||
#include <sky.glsl>
|
||||
#include <srgb.glsl>
|
||||
|
||||
uniform sampler2D t_alt;
|
||||
uniform sampler2D t_horizon;
|
||||
|
||||
const float MIN_SHADOW = 0.33;
|
||||
|
||||
vec2 pos_to_uv(sampler2D sampler, vec2 pos) {
|
||||
// Want: (pixel + 0.5) / W
|
||||
vec2 texSize = textureSize(sampler, 0);
|
||||
vec2 uv_pos = (focus_off.xy + pos + 16) / (32.0 * texSize);
|
||||
return vec2(uv_pos.x, /*1.0 - */uv_pos.y);
|
||||
}
|
||||
|
||||
vec2 pos_to_tex(vec2 pos) {
|
||||
// Want: (pixel + 0.5)
|
||||
vec2 uv_pos = (focus_off.xy + pos + 16) / 32.0;
|
||||
return vec2(uv_pos.x, uv_pos.y);
|
||||
}
|
||||
|
||||
// textureBicubic from https://stackoverflow.com/a/42179924
|
||||
vec4 cubic(float v) {
|
||||
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
|
||||
vec4 s = n * n * n;
|
||||
float x = s.x;
|
||||
float y = s.y - 4.0 * s.x;
|
||||
float z = s.z - 4.0 * s.y + 6.0 * s.x;
|
||||
float w = 6.0 - x - y - z;
|
||||
return vec4(x, y, z, w) * (1.0/6.0);
|
||||
}
|
||||
|
||||
// NOTE: We assume the sampled coordinates are already in "texture pixels".
|
||||
vec4 textureBicubic(sampler2D sampler, vec2 texCoords) {
|
||||
vec2 texSize = textureSize(sampler, 0);
|
||||
vec2 invTexSize = 1.0 / texSize;
|
||||
/* texCoords.y = texSize.y - texCoords.y; */
|
||||
|
||||
texCoords = texCoords/* * texSize */ - 0.5;
|
||||
|
||||
|
||||
vec2 fxy = fract(texCoords);
|
||||
texCoords -= fxy;
|
||||
|
||||
vec4 xcubic = cubic(fxy.x);
|
||||
vec4 ycubic = cubic(fxy.y);
|
||||
|
||||
vec4 c = texCoords.xxyy + vec2 (-0.5, +1.5).xyxy;
|
||||
// vec4 c = texCoords.xxyy + vec2 (-1, +1).xyxy;
|
||||
|
||||
vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
||||
vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s;
|
||||
|
||||
offset *= invTexSize.xxyy;
|
||||
/* // Correct for map rotaton.
|
||||
offset.zw = 1.0 - offset.zw; */
|
||||
|
||||
vec4 sample0 = texture(sampler, offset.xz);
|
||||
vec4 sample1 = texture(sampler, offset.yz);
|
||||
vec4 sample2 = texture(sampler, offset.xw);
|
||||
vec4 sample3 = texture(sampler, offset.yw);
|
||||
// vec4 sample0 = texelFetch(sampler, offset.xz, 0);
|
||||
// vec4 sample1 = texelFetch(sampler, offset.yz, 0);
|
||||
// vec4 sample2 = texelFetch(sampler, offset.xw, 0);
|
||||
// vec4 sample3 = texelFetch(sampler, offset.yw, 0);
|
||||
|
||||
float sx = s.x / (s.x + s.y);
|
||||
float sy = s.z / (s.z + s.w);
|
||||
|
||||
return mix(
|
||||
mix(sample3, sample2, sx), mix(sample1, sample0, sx)
|
||||
, sy);
|
||||
}
|
||||
|
||||
float alt_at(vec2 pos) {
|
||||
return (/*round*/(texture/*textureBicubic*/(t_alt, pos_to_uv(t_alt, pos)).r * (/*1300.0*//*1278.7266845703125*/view_distance.w)) + /*140.0*/view_distance.z - focus_off.z);
|
||||
//+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0;
|
||||
|
||||
// return 0.0
|
||||
// + pow(texture(t_noise, pos * 0.00005).x * 1.4, 3.0) * 1000.0
|
||||
// + texture(t_noise, pos * 0.001).x * 100.0
|
||||
// + texture(t_noise, pos * 0.003).x * 30.0;
|
||||
}
|
||||
|
||||
float alt_at_real(vec2 pos) {
|
||||
// Basic idea: only really need the real altitude for an accurate water height estimation, so if we are in the cheap shader take a shortcut.
|
||||
// #if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
// return alt_at(pos);
|
||||
// #elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
return (/*round*/(textureBicubic(t_alt, pos_to_tex(pos)).r * (/*1300.0*//*1278.7266845703125*/view_distance.w)) + /*140.0*/view_distance.z - focus_off.z);
|
||||
// #endif
|
||||
//+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0;
|
||||
|
||||
// return 0.0
|
||||
// + pow(texture(t_noise, pos * 0.00005).x * 1.4, 3.0) * 1000.0
|
||||
// + texture(t_noise, pos * 0.001).x * 100.0
|
||||
// + texture(t_noise, pos * 0.003).x * 30.0;
|
||||
}
|
||||
|
||||
|
||||
float horizon_at2(vec4 f_horizons, float alt, vec3 pos, /*float time_of_day*/vec4 light_dir) {
|
||||
// vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
const float PI_2 = 3.1415926535897932384626433832795 / 2.0;
|
||||
const float MIN_LIGHT = 0.0;//0.115/*0.0*/;
|
||||
|
||||
// return 1.0;
|
||||
/*
|
||||
|
||||
let shade_frac = horizon_map
|
||||
.and_then(|(angles, heights)| {
|
||||
chunk_idx
|
||||
.and_then(|chunk_idx| angles.get(chunk_idx))
|
||||
.map(|&e| (e as f64, heights))
|
||||
})
|
||||
.and_then(|(e, heights)| {
|
||||
chunk_idx
|
||||
.and_then(|chunk_idx| heights.get(chunk_idx))
|
||||
.map(|&f| (e, f as f64))
|
||||
})
|
||||
.map(|(angle, height)| {
|
||||
let w = 0.1;
|
||||
if angle != 0.0 && light_direction.x != 0.0 {
|
||||
let deltax = height / angle;
|
||||
let lighty = (light_direction.y / light_direction.x * deltax).abs();
|
||||
let deltay = lighty - height;
|
||||
let s = (deltay / deltax / w).min(1.0).max(0.0);
|
||||
// Smoothstep
|
||||
s * s * (3.0 - 2.0 * s)
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
})
|
||||
.unwrap_or(1.0);
|
||||
*/
|
||||
// vec2 f_horizon;
|
||||
/* if (light_dir.z >= 0) {
|
||||
return 0.0;
|
||||
} */
|
||||
/* if (light_dir.x >= 0) {
|
||||
f_horizon = f_horizons.rg;
|
||||
// f_horizon = f_horizons.ba;
|
||||
} else {
|
||||
f_horizon = f_horizons.ba;
|
||||
// f_horizon = f_horizons.rg;
|
||||
}
|
||||
return 1.0; */
|
||||
/* bvec2 f_mode = lessThan(vec2(light_dir.x), vec2(1.0));
|
||||
f_horizon = mix(f_horizons.ba, f_horizons.rg, f_mode); */
|
||||
// f_horizon = mix(f_horizons.rg, f_horizons.ba, clamp(light_dir.x * 10000.0, 0.0, 1.0));
|
||||
vec2 f_horizon = mix(f_horizons.rg, f_horizons.ba, bvec2(light_dir.x < 0.0));
|
||||
// vec2 f_horizon = mix(f_horizons.ba, f_horizons.rg, clamp(light_dir.x * 10000.0, 0.0, 1.0));
|
||||
// f_horizon = mix(f_horizons.ba, f_horizons.rg, bvec2(lessThan(light_dir.xx, vec2(0.0))));
|
||||
/* if (f_horizon.x <= 0) {
|
||||
return 1.0;
|
||||
} */
|
||||
float angle = tan(f_horizon.x * PI_2);
|
||||
/* if (angle <= 0.0001) {
|
||||
return 1.0;
|
||||
} */
|
||||
float height = f_horizon.y * /*1300.0*//*1278.7266845703125*/view_distance.w + view_distance.z;
|
||||
const float w = 0.1;
|
||||
float deltah = height - alt - focus_off.z;
|
||||
//if (deltah < 0.0001/* || angle < 0.0001 || abs(light_dir.x) < 0.0001*/) {
|
||||
// return 1.0;
|
||||
/*} else */{
|
||||
float lighta = /*max*/(-light_dir.z/*, 0.0*/) / max(abs(light_dir.x), 0.0001);
|
||||
// NOTE: Ideally, deltah <= 0.0 is a sign we have an oblique horizon angle.
|
||||
float deltax = deltah / max(angle, 0.0001)/*angle*/;
|
||||
float lighty = lighta * deltax;
|
||||
float deltay = lighty - deltah + max(pos.z - alt, 0.0);
|
||||
// NOTE: the "real" deltah should always be >= 0, so we know we're only handling the 0 case with max.
|
||||
float s = mix(max(min(max(deltay, 0.0) / max(deltax, 0.0001) / w, 1.0), 0.0), 1.0, deltah <= 0);
|
||||
return max(/*0.2 + 0.8 * */(s * s * (3.0 - 2.0 * s)), MIN_LIGHT);
|
||||
/* if (lighta >= angle) {
|
||||
return 1.0;
|
||||
} else {
|
||||
return MIN_LIGHT;
|
||||
} */
|
||||
// float deltah = height - alt;
|
||||
// float deltah = max(height - alt, 0.0);
|
||||
// float lighty = abs(sun_dir.z / sun_dir.x * deltax);
|
||||
// float lighty = abs(sun_dir.z / sun_dir.x * deltax);
|
||||
// float deltay = lighty - /*pos.z*//*deltah*/(deltah + max(pos.z - alt, 0.0))/*deltah*/;
|
||||
// float s = max(min(max(deltay, 0.0) / deltax / w, 1.0), 0.0);
|
||||
// Smoothstep
|
||||
// return max(/*0.2 + 0.8 * */(s * s * (3.0 - 2.0 * s)), MIN_LIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
// float horizon_at(vec3 pos, /*float time_of_day*/vec3 light_dir) {
|
||||
// vec4 f_horizons = textureBicubic(t_horizon, pos_to_tex(pos.xy));
|
||||
// // f_horizons.xyz = /*linear_to_srgb*/(f_horizons.xyz);
|
||||
// float alt = alt_at_real(pos.xy);
|
||||
// return horizon_at2(f_horizons, alt, pos, light_dir);
|
||||
// }
|
||||
|
||||
vec2 splay(vec2 pos) {
|
||||
// const float SPLAY_MULT = 1048576.0;
|
||||
float len_2 = dot(pos, pos);
|
||||
float len_pow = len_2 * sqrt(len_2);
|
||||
// float len_pow = pow(len/* * SQRT_2*//* * 0.5*/, 3.0);
|
||||
// vec2 splayed = pos * pow(len * 0.5, 3.0) * SPLAY_MULT;
|
||||
const float SQRT_2 = sqrt(2.0) / 2.0;
|
||||
// /const float CBRT_2 = cbrt(2.0) / 2.0;
|
||||
// vec2 splayed = pos * (view_distance.x * SQRT_2 + pow(len * 0.5, 3.0) * (SPLAY_MULT - view_distance.x));
|
||||
vec2 splayed = pos * (view_distance.x * SQRT_2 + len_pow * (textureSize(t_alt, 0) * 32.0/* - view_distance.x*/));
|
||||
return splayed;
|
||||
|
||||
// Radial: pos.x = r - view_distance.x from focus_pos, pos.y = θ from cam_pos to focus_pos on xy plane.
|
||||
// const float PI_2 = 3.1415926535897932384626433832795;
|
||||
// float squared = pos.x * pos.x;
|
||||
// // // vec2 splayed2 = pos * vec2(squared * (SPLAY_MULT - view_distance.x), PI);
|
||||
// vec2 splayed2 = pos * vec2(squared * (textureSize(t_alt, 0).x * 32.0 - view_distance.x), PI);
|
||||
// float r = splayed2.x + view_distance.x;
|
||||
// vec2 theta = vec2(cos(splayed2.y), sin(splayed2.y));
|
||||
// return r * theta;
|
||||
// // mat2 rot_mat = mat2(vec2(theta.x, -theta.y), theta.yx);
|
||||
// // return r * /*normalize(normalize(focus_pos.xy - cam_pos.xy) + theta);*/rot_mat * normalize(focus_pos.xy - cam_pos.xy);
|
||||
// return splayed;
|
||||
}
|
||||
|
||||
vec3 lod_norm(vec2 f_pos/*vec3 pos*/, vec4 square) {
|
||||
// const float SAMPLE_W = 32;
|
||||
|
||||
// vec2 f_pos = pos.xy;
|
||||
// float altx0 = alt_at_real(f_pos + vec2(-1.0, 0) * SAMPLE_W);
|
||||
// float altx1 = alt_at_real(f_pos + vec2(1.0, 0) * SAMPLE_W);
|
||||
// float alty0 = alt_at_real(f_pos + vec2(0, -1.0) * SAMPLE_W);
|
||||
// float alty1 = alt_at_real(f_pos + vec2(0, 1.0) * SAMPLE_W);
|
||||
float altx0 = alt_at(vec2(square.x, f_pos.y));
|
||||
float altx1 = alt_at(vec2(square.z, f_pos.y));
|
||||
float alty0 = alt_at(vec2(f_pos.x, square.y));
|
||||
float alty1 = alt_at(vec2(f_pos.x, square.w));
|
||||
float slope = abs(altx1 - altx0) + abs(alty0 - alty1);
|
||||
|
||||
// vec3 norm = normalize(cross(
|
||||
// vec3(/*2.0 * SAMPLE_W*/square.z - square.x, 0.0, altx1 - altx0),
|
||||
// vec3(0.0, /*2.0 * SAMPLE_W*/square.w - square.y, alty1 - alty0)
|
||||
// ));
|
||||
vec3 norm = normalize(vec3(
|
||||
(altx0 - altx1) / (square.z - square.x),
|
||||
(alty0 - alty1) / (square.w - square.y),
|
||||
1.0
|
||||
//(abs(square.w - square.y) + abs(square.z - square.x)) / (slope + 0.00001) // Avoid NaN
|
||||
));
|
||||
/* vec3 norm = normalize(vec3(
|
||||
(altx0 - altx1) / (2.0 * SAMPLE_W),
|
||||
(alty0 - alty1) / (2.0 * SAMPLE_W),
|
||||
(2.0 * SAMPLE_W) / (slope + 0.00001) // Avoid NaN
|
||||
)); */
|
||||
|
||||
return faceforward(norm, vec3(0.0, 0.0, -1.0)/*pos - cam_pos.xyz*/, norm);
|
||||
}
|
||||
|
||||
vec3 lod_norm(vec2 f_pos/*vec3 pos*/) {
|
||||
const float SAMPLE_W = 32;
|
||||
|
||||
return lod_norm(f_pos, vec4(f_pos - vec2(SAMPLE_W), f_pos + vec2(SAMPLE_W)));
|
||||
}
|
||||
|
||||
|
||||
vec3 lod_pos(vec2 pos, vec2 focus_pos) {
|
||||
// Remove spiking by "pushing" vertices towards local optima
|
||||
vec2 delta = splay(pos);
|
||||
vec2 hpos = focus_pos + delta;
|
||||
vec2 nhpos = hpos;
|
||||
// vec2 lod_shift = splay(abs(pos) - 1.0 / view_distance.y);
|
||||
float shift = 15.0;// min(lod_shift.x, lod_shift.y) * 0.5;
|
||||
for (int i = 0; i < 3; i ++) {
|
||||
// vec4 square = focus_pos.xy + vec4(splay(pos - vec2(1.0, 1.0), splay(pos + vec2(1.0, 1.0))));
|
||||
nhpos -= lod_norm(hpos).xy * shift;
|
||||
}
|
||||
hpos = hpos + normalize(nhpos - hpos + 0.001) * min(length(nhpos - hpos), 32);
|
||||
|
||||
return vec3(hpos, alt_at_real(hpos));
|
||||
}
|
||||
|
||||
#ifdef HAS_LOD_FULL_INFO
|
||||
uniform sampler2D t_map;
|
||||
|
||||
vec3 lod_col(vec2 pos) {
|
||||
//return vec3(0, 0.5, 0);
|
||||
// return /*linear_to_srgb*/vec3(alt_at(pos), textureBicubic(t_map, pos_to_tex(pos)).gb);
|
||||
return /*linear_to_srgb*/(textureBicubic(t_map, pos_to_tex(pos)).rgb)
|
||||
;//+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1;
|
||||
//+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1;
|
||||
}
|
||||
#endif
|
@ -1,3 +1,5 @@
|
||||
uniform sampler2D t_noise;
|
||||
|
||||
float hash(vec4 p) {
|
||||
p = fract(p * 0.3183099 + 0.1) - fract(p + 23.22121);
|
||||
p *= 17.0;
|
||||
|
218
assets/voxygen/shaders/include/shadows.glsl
Normal file
218
assets/voxygen/shaders/include/shadows.glsl
Normal file
@ -0,0 +1,218 @@
|
||||
#ifdef HAS_SHADOW_MAPS
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
struct ShadowLocals {
|
||||
mat4 shadowMatrices;
|
||||
mat4 texture_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_light_shadows {
|
||||
ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
};
|
||||
|
||||
uniform sampler2DShadow t_directed_shadow_maps;
|
||||
// uniform sampler2DArrayShadow t_directed_shadow_maps;
|
||||
|
||||
// uniform samplerCubeArrayShadow t_shadow_maps;
|
||||
// uniform samplerCubeArray t_shadow_maps;
|
||||
uniform samplerCubeShadow t_point_shadow_maps;
|
||||
// uniform samplerCube t_shadow_maps;
|
||||
|
||||
// uniform sampler2DArray t_directed_shadow_maps;
|
||||
|
||||
float VectorToDepth (vec3 Vec)
|
||||
{
|
||||
// return length(Vec) / screen_res.w;
|
||||
vec3 AbsVec = abs(Vec);
|
||||
float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));
|
||||
// float LocalZcomp = length(Vec);
|
||||
|
||||
// Replace f and n with the far and near plane values you used when
|
||||
// you drew your cube map.
|
||||
// const float f = 2048.0;
|
||||
// const float n = 1.0;
|
||||
|
||||
// float NormZComp = (screen_res.w+screen_res.z) / (screen_res.w-screen_res.z) - (2*screen_res.w*screen_res.z)/(screen_res.w-screen_res.z)/LocalZcomp;
|
||||
// float NormZComp = 1.0 - shadow_proj_factors.y / shadow_proj_factors.x / LocalZcomp;
|
||||
float NormZComp = shadow_proj_factors.x - shadow_proj_factors.y / LocalZcomp;
|
||||
// NormZComp = -1000.0 / (NormZComp + 10000.0);
|
||||
return (NormZComp + 1.0) * 0.5;
|
||||
|
||||
// float NormZComp = length(LocalZcomp);
|
||||
// NormZComp = -NormZComp / screen_res.w;
|
||||
// // return (NormZComp + 1.0) * 0.5;
|
||||
// return NormZComp;
|
||||
}
|
||||
|
||||
const vec3 sampleOffsetDirections[20] = vec3[]
|
||||
(
|
||||
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
|
||||
vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
|
||||
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
|
||||
// vec3(0, 0, 0)
|
||||
);
|
||||
|
||||
float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /*float currentDepth*/vec3 fragPos)
|
||||
{
|
||||
if (lightIndex != 0u) {
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
{
|
||||
float currentDepth = VectorToDepth(fragToLight);// + bias;
|
||||
|
||||
float visibility = texture(t_point_shadow_maps, vec4(fragToLight, currentDepth));// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
/* if (visibility == 1.0 || visibility == 0.0) {
|
||||
return visibility;
|
||||
} */
|
||||
/* if (visibility >= 0.75) {
|
||||
return 1.0;
|
||||
}
|
||||
if (visibility <= 0.25) {
|
||||
return 0.0;
|
||||
} */
|
||||
/* if (visibility < 1.0) {
|
||||
return 0.0;
|
||||
} */
|
||||
// return visibility;
|
||||
/* if (visibility == 1.0) {
|
||||
return visibility;
|
||||
} */
|
||||
return visibility;
|
||||
// return visibility == 1.0 ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
// float shadow = 0.0;
|
||||
// float bias = 0.0;//0.003;//-0.003;//-0.005;//0.001;//-1.0;//-0.001;//0.001;//0.003;//-0.05;//-0.1;//0.0;//0.1
|
||||
// float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// vec3 firstDelta = vec3(0.0);///*min(viewDistance, 5.0) * *//**normalize(cam_pos - fragPos)*/fragNorm * 0.5;
|
||||
// fragToLight += firstDelta;
|
||||
// // viewDistance -= length(firstDelta);
|
||||
// fragPos -= firstDelta;
|
||||
|
||||
// int samples = 20;
|
||||
// // float lightDistance = length(fragToLight);
|
||||
// // float diskRadius = 0.00001;
|
||||
// // float diskRadius = 1.0;
|
||||
// // float diskRadius = 0.05;
|
||||
// float diskRadius = 5.0 / screen_res.w;// (1.0 + (/*viewDistance*/viewDistance / screen_res.w)) / 25.0;
|
||||
// // float diskRadius = lightDistance;
|
||||
// for(int i = 0; i < samples; ++i)
|
||||
// {
|
||||
// float currentDepth = VectorToDepth(fragToLight + sampleOffsetDirections[i] * diskRadius) + bias;
|
||||
// // float closestDepth = texture(depthMap, fragToLight).r;
|
||||
// // closestDepth *= far_plane; // Undo mapping [0;1]
|
||||
// /* if(currentDepth - bias > closestDepth)
|
||||
// shadow += 1.0;*/
|
||||
// float visibility = texture(t_point_shadow_maps, vec4(fragToLight, currentDepth)/*, -2.5*/);
|
||||
// shadow += visibility;
|
||||
// // float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).r;
|
||||
// // shadow += closestDepth > currentDepth ? 1.0 : 0.0;
|
||||
// }
|
||||
// shadow /= float(samples);
|
||||
// // shadow = shadow * shadow * (3.0 - 2.0 * shadow);
|
||||
|
||||
// // use the light to fragment vector to sample from the depth map
|
||||
// // float bias = 0.0;///*0.05*/0.01;//0.05;// 0.05;
|
||||
// // float closestDepth = texture(t_shadow_maps, /*vec4*/vec3(fragToLight/*, (lightIndex + 1)*//* * 6*/)/*, 0.0*//*, 0.0*//*, bias*/).r;
|
||||
// // // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // // // it is currently in linear range between [0,1]. Re-transform back to original value
|
||||
// // closestDepth = (closestDepth + 0.0) * screen_res.w; // far plane
|
||||
// // // // now test for shadows
|
||||
// // // // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0;
|
||||
// // float shadow = currentDepth - bias < closestDepth ? 1.0 : 0.0;
|
||||
// // float visibility = textureProj(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // float visibility = texture(t_shadow_maps, vec4(fragToLight, lightIndex + 1), -(currentDepth/* + screen_res.z*/) / screen_res.w);// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// // currentDepth += bias;
|
||||
// // currentDepth = -1000.0 / (currentDepth + 10000.0);
|
||||
// // currentDepth /= screen_res.w;
|
||||
// // float currentDepth = VectorToDepth(fragToLight) + bias;
|
||||
|
||||
// // float visibility = texture(t_shadow_maps, vec4(fragToLight, currentDepth));// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// // return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// return shadow;
|
||||
}
|
||||
|
||||
float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_pos, vec3 fragPos)
|
||||
{
|
||||
float bias = 0.000;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
||||
float diskRadius = 0.01;
|
||||
const vec3 sampleOffsetDirections[20] = vec3[]
|
||||
(
|
||||
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
|
||||
vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
|
||||
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
|
||||
// vec3(0, 0, 0)
|
||||
);
|
||||
/* if (lightIndex >= light_shadow_count.z) {
|
||||
return 1.0;
|
||||
} */
|
||||
// vec3 fragPos = sun_pos.xyz;// / sun_pos.w;//light_pos[lightIndex].xyz;
|
||||
// sun_pos.z += sun_pos.w * bias;
|
||||
ShadowLocals sun_shadow = shadowMats[0];
|
||||
vec4 sun_pos = sun_shadow.texture_mat * vec4(fragPos, 1.0);
|
||||
// sun_pos.z -= sun_pos.w * bias;
|
||||
float visibility = textureProj(t_directed_shadow_maps, sun_pos);
|
||||
/* float visibilityLeft = textureProj(t_directed_shadow_maps, sun_shadow.texture_mat * vec4(fragPos + vec3(0.0, -diskRadius, 0.0), 1.0));
|
||||
float visibilityRight = textureProj(t_directed_shadow_maps, sun_shadow.texture_mat * vec4(fragPos + vec3(0.0, diskRadius, 0.0), 1.0)); */
|
||||
// float nearVisibility = textureProj(t_directed_shadow_maps + vec3(0.001, sun_pos));
|
||||
// float visibility = textureProj(t_directed_shadow_maps, vec4(fragPos.xy, /*lightIndex, */fragPos.z + bias, sun_pos.w));
|
||||
// return visibility;
|
||||
// return min(visibility, min(visibilityLeft, visibilityRight));
|
||||
// return mix(visibility, 0.0, sun_pos.z < -1.0);
|
||||
// return mix(mix(0.0, 1.0, visibility == 1.0), 1.0, sign(sun_pos.w) * sun_pos.z > /*1.0*/abs(sun_pos.w));
|
||||
// return (visibility - 0.5) * (visibility - 0.5) * 2.0 * sign(visibility - 0.5) + 0.5;// visibility > 0.75 ? visibility : 0.0;// visibility > 0.9 ? 1.0 : 0.0;
|
||||
return visibility;
|
||||
// return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// return abs(fragPos.y - round(fragPos.y)) <= 0.1 || abs(fragPos.x - round(fragPos.x)) <= 0.1 ? ( visibility == 1.0 ? 1.0 : 0.0) : visibility;
|
||||
/* if (visibility == 1.0) {
|
||||
return 1.0;
|
||||
} */
|
||||
// return visibility;
|
||||
/* if (fragPos.z > 1.0) {
|
||||
return 1.0;
|
||||
} */
|
||||
// vec3 snapToZ = abs(fragPos - vec3(ivec3(fragPos))); // fract(abs(fragPos));
|
||||
// // snapToZ = min(snapToZ, 1.0 - snapToZ);
|
||||
// const float EDGE_DIST = 0.01;
|
||||
// snapToZ = mix(vec3(0.0), vec3(1.0), lessThanEqual(snapToZ, vec3(EDGE_DIST)));
|
||||
// // float snapToZDist = dot(snapToZ, snapToZ);
|
||||
// if (visibility <= 0.75 && /*fract(abs(fragPos.xy)), vec2(0.1)))*/ /*snapToZDist <= 0.25*//*all(lessThan(snapToZ, vec3(0.1)))(*/
|
||||
// snapToZ.x + snapToZ.y + snapToZ.z >= 2.0) {
|
||||
// return 0.0;
|
||||
// }
|
||||
// int samples = 20;
|
||||
// float shadow = 0.0;
|
||||
// // float bias = 0.0001;
|
||||
// // float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// // float diskRadius = 0.2 * (1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// // float diskRadius = 0.0003;//0.005;// / (2.0 * view_distance.x);//(1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// fragPos = sun_pos.xyz / sun_pos.w;
|
||||
// for(int i = 0; i < samples; ++i)
|
||||
// {
|
||||
// vec3 currentDepth = fragPos + vec3(sampleOffsetDirections[i].xyz) * diskRadius + bias;
|
||||
// visibility = texture(t_directed_shadow_maps, currentDepth);//vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// // visibility = texture(t_directed_shadow_maps, vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// shadow += visibility;
|
||||
// // mix(visibility, 1.0, visibility >= 0.5);
|
||||
// }
|
||||
// shadow /= float(samples);
|
||||
// return shadow;
|
||||
}
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || SHADOW_MODE == SHADOW_MODE_CHEAP)
|
||||
float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /*float currentDepth*/vec3 fragPos)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /*float currentDepth*/vec3 fragPos)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
#endif
|
@ -1,215 +1,589 @@
|
||||
#include <random.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <cloud.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <shadows.glsl>
|
||||
|
||||
// Information about an approximately directional light, like the sun or moon.
|
||||
struct DirectionalLight {
|
||||
// vec3 dir;
|
||||
float shadow;
|
||||
// vec3 color;
|
||||
// float brightness;
|
||||
};
|
||||
|
||||
const float PI = 3.141592;
|
||||
|
||||
const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9);
|
||||
const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8);
|
||||
const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3);
|
||||
const vec3 DAY_LIGHT = vec3(1.2, 1.0, 1.0);
|
||||
const vec3 DAY_LIGHT = vec3(1.9, 1.75, 0.9);//vec3(1.5, 1.4, 1.0);
|
||||
const vec3 SUN_HALO_DAY = vec3(0.35, 0.35, 0.0);
|
||||
|
||||
const vec3 SKY_DUSK_TOP = vec3(0.06, 0.1, 0.20);
|
||||
const vec3 SKY_DUSK_MID = vec3(0.35, 0.1, 0.15);
|
||||
const vec3 SKY_DUSK_BOT = vec3(0.0, 0.1, 0.23);
|
||||
const vec3 DUSK_LIGHT = vec3(3.0, 1.5, 0.3);
|
||||
const vec3 DUSK_LIGHT = vec3(9.0, 1.5, 0.15);
|
||||
const vec3 SUN_HALO_DUSK = vec3(1.2, 0.15, 0.0);
|
||||
|
||||
const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025);
|
||||
const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02);
|
||||
const vec3 SKY_NIGHT_BOT = vec3(0.002, 0.004, 0.004);
|
||||
const vec3 NIGHT_LIGHT = vec3(0.002, 0.01, 0.03);
|
||||
const vec3 NIGHT_LIGHT = vec3(0.002, 0.02, 0.02);
|
||||
// const vec3 NIGHT_LIGHT = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// Linear RGB, scattering coefficients for atmosphere at roughly R, G, B wavelengths.
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/Diffuse_sky_radiation
|
||||
const vec3 MU_SCATTER = vec3(0.05, 0.10, 0.23) * 1.5;
|
||||
|
||||
const float SUN_COLOR_FACTOR = 5.0;//6.0;// * 1.5;//1.8;
|
||||
|
||||
const float UNDERWATER_MIST_DIST = 100.0;
|
||||
|
||||
vec3 get_sun_dir(float time_of_day) {
|
||||
const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0);
|
||||
const float PERSISTENT_AMBIANCE = 1.0 / 32.0;// 1.0 / 80; // 1.0 / 512; // 0.00125 // 0.1;// 0.025; // 0.1;
|
||||
|
||||
float sun_angle_rad = time_of_day * TIME_FACTOR;
|
||||
return vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad));
|
||||
//vec3 get_sun_dir(float time_of_day) {
|
||||
// const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0);
|
||||
//
|
||||
// float sun_angle_rad = time_of_day * TIME_FACTOR;
|
||||
// // return vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad));
|
||||
// return vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad));
|
||||
//}
|
||||
//
|
||||
//vec3 get_moon_dir(float time_of_day) {
|
||||
// const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0);
|
||||
//
|
||||
// float moon_angle_rad = time_of_day * TIME_FACTOR;
|
||||
// // -cos((60+60*4)/360*2*pi)-0.5 = 0
|
||||
// // -cos((60+60*5)/360*2*pi)-0.5 = -0.5
|
||||
// // -cos((60+60*6)/360*2*pi)-0.5 = 0
|
||||
// //
|
||||
// // i.e. moon out from (60*5)/360*24 = 20:00 to (60*7/360*24) = 28:00 = 04:00.
|
||||
// //
|
||||
// // Then sun out from 04:00 to 20:00.
|
||||
// return normalize(-vec3(sin(moon_angle_rad), 0.0, cos(moon_angle_rad) - 0.5));
|
||||
//}
|
||||
|
||||
float get_sun_brightness(/*vec3 sun_dir*/) {
|
||||
return max(-sun_dir.z + 0.6, 0.0) * 0.9;
|
||||
}
|
||||
|
||||
vec3 get_moon_dir(float time_of_day) {
|
||||
const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0);
|
||||
|
||||
float moon_angle_rad = time_of_day * TIME_FACTOR;
|
||||
return normalize(-vec3(sin(moon_angle_rad), 0.0, cos(moon_angle_rad) - 0.5));
|
||||
float get_moon_brightness(/*vec3 moon_dir*/) {
|
||||
return max(-moon_dir.z + 0.6, 0.0) * 0.4;
|
||||
}
|
||||
|
||||
const float PERSISTENT_AMBIANCE = 0.1;
|
||||
|
||||
float get_sun_brightness(vec3 sun_dir) {
|
||||
return max(-sun_dir.z + 0.6, 0.0) * 0.9;
|
||||
vec3 get_sun_color(/*vec3 sun_dir*/) {
|
||||
return mix(
|
||||
mix(
|
||||
DUSK_LIGHT,
|
||||
NIGHT_LIGHT,
|
||||
max(sun_dir.z, 0)
|
||||
),
|
||||
DAY_LIGHT,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
}
|
||||
|
||||
float get_moon_brightness(vec3 moon_dir) {
|
||||
return max(-moon_dir.z + 0.6, 0.0) * 0.07;
|
||||
vec3 get_moon_color(/*vec3 moon_dir*/) {
|
||||
return vec3(0.05, 0.05, 0.6);
|
||||
}
|
||||
|
||||
vec3 get_sun_color(vec3 sun_dir) {
|
||||
return mix(
|
||||
mix(
|
||||
DUSK_LIGHT,
|
||||
NIGHT_LIGHT,
|
||||
max(sun_dir.z, 0)
|
||||
),
|
||||
DAY_LIGHT,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
DirectionalLight get_sun_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/, /*vec4 sun_pos*/vec3 f_pos) {
|
||||
float shadow = shade_frac;
|
||||
#ifdef HAS_SHADOW_MAPS
|
||||
#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
if (sun_dir.z < /*0.6*/0.0) {
|
||||
/* ShadowLocals sun_shadow = shadowMats[0];
|
||||
vec4 sun_pos = sun_shadow.texture_mat * vec4(f_pos, 1.0); */
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// #elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// vec4 sun_pos = vec4(0.0);
|
||||
// #endif
|
||||
shadow = min(shadow, ShadowCalculationDirected(/*sun_pos, *//*0u*/f_pos));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return DirectionalLight(/*dir, */shadow/*, get_sun_color(dir), get_sun_brightness(dir)*/);
|
||||
}
|
||||
|
||||
vec3 get_moon_color(vec3 moon_dir) {
|
||||
return vec3(0.05, 0.05, 0.6);
|
||||
DirectionalLight get_moon_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/) {
|
||||
float shadow = shade_frac;
|
||||
// #ifdef HAS_SHADOW_MAPS
|
||||
// shadow = min(shade_frac, ShadowCalculationDirected(light_pos, 1u));
|
||||
// #endif
|
||||
return DirectionalLight(/*dir, */shadow/*, get_moon_color(dir), get_moon_brightness(dir)*/);
|
||||
}
|
||||
|
||||
void get_sun_diffuse(vec3 norm, float time_of_day, out vec3 light, out vec3 diffuse_light, out vec3 ambient_light, float diffusion) {
|
||||
const float SUN_AMBIANCE = 0.1;
|
||||
// // Calculates extra emission and reflectance (due to sunlight / moonlight).
|
||||
// //
|
||||
// // reflectence = k_a * i_a + i_a,persistent
|
||||
// // emittence = Σ { m ∈ lights } i_m * shadow_m * get_light_reflected(light_m)
|
||||
// //
|
||||
// // Note that any shadowing to be done that would block the sun and moon, aside from heightmap shadowing (that will be
|
||||
// // implemented sooon), should be implicitly provided via k_a, k_d, and k_s. For instance, shadowing via ambient occlusion.
|
||||
// //
|
||||
// // Also note that the emitted light calculation is kind of lame... we probabbly need something a bit nicer if we ever want to do
|
||||
// // anything interesting here.
|
||||
// // void get_sun_diffuse(vec3 norm, float time_of_day, out vec3 light, out vec3 diffuse_light, out vec3 ambient_light, float diffusion
|
||||
// void get_sun_diffuse(vec3 norm, float time_of_day, vec3 dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, out vec3 emitted_light, out vec3 reflected_light) {
|
||||
// const float SUN_AMBIANCE = 0.1 / 2.0;// 0.1 / 3.0;
|
||||
//
|
||||
// vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
// vec3 moon_dir = get_moon_dir(time_of_day);
|
||||
//
|
||||
// float sun_light = get_sun_brightness(sun_dir);
|
||||
// float moon_light = get_moon_brightness(moon_dir);
|
||||
//
|
||||
// vec3 sun_color = get_sun_color(sun_dir);
|
||||
// vec3 moon_color = get_moon_color(moon_dir);
|
||||
//
|
||||
// vec3 sun_chroma = sun_color * sun_light;
|
||||
// vec3 moon_chroma = moon_color * moon_light;
|
||||
//
|
||||
// /* float NLsun = max(dot(-norm, sun_dir), 0);
|
||||
// float NLmoon = max(dot(-norm, moon_dir), 0);
|
||||
// vec3 E = -dir; */
|
||||
//
|
||||
// // Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// // Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-norm, sun_dir)) * mix(0.0, 1.0, abs(sun_dir.z) * 10000.0) * 10000.0), 0.0, 0.5);
|
||||
// // float ambient_sides = 0.5 - 0.5 * abs(dot(-norm, sun_dir));
|
||||
//
|
||||
// emitted_light = k_a * (ambient_sides + vec3(SUN_AMBIANCE * sun_light + moon_light)) + PERSISTENT_AMBIANCE;
|
||||
// // TODO: Add shadows.
|
||||
// reflected_light =
|
||||
// sun_chroma * light_reflection_factor(norm, dir, sun_dir, k_d, k_s, alpha) +
|
||||
// moon_chroma * 1.0 * /*4.0 * */light_reflection_factor(norm, dir, moon_dir, k_d, k_s, alpha);
|
||||
//
|
||||
// /* light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
|
||||
// diffuse_light =
|
||||
// sun_chroma * mix(1.0, max(dot(-norm, sun_dir) * 0.5 + 0.5, 0.0), diffusion) +
|
||||
// moon_chroma * mix(1.0, pow(dot(-norm, moon_dir) * 2.0, 2.0), diffusion) +
|
||||
// PERSISTENT_AMBIANCE;
|
||||
// ambient_light = vec3(SUN_AMBIANCE * sun_light + moon_light); */
|
||||
// }
|
||||
|
||||
vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day);
|
||||
// Returns computed maximum intensity.
|
||||
//
|
||||
// wpos is the position of this fragment.
|
||||
// mu is the attenuation coefficient for any substance on a horizontal plane.
|
||||
// cam_attenuation is the total light attenuation due to the substance for beams between the point and the camera.
|
||||
// surface_alt is the altitude of the attenuating surface.
|
||||
float get_sun_diffuse2(DirectionalLight sun_info, DirectionalLight moon_info, vec3 norm, vec3 dir, vec3 wpos, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 voxel_norm, float voxel_lighting, out vec3 emitted_light, out vec3 reflected_light) {
|
||||
const float MIN_SHADOW = 0.15;
|
||||
const vec3 SUN_AMBIANCE = MU_SCATTER;//0.23;/* / 1.8*/;// 0.1 / 3.0;
|
||||
const vec3 MOON_AMBIANCE = MU_SCATTER;//0.23;//0.1;
|
||||
|
||||
float sun_light = get_sun_brightness(sun_dir);
|
||||
float moon_light = get_moon_brightness(moon_dir);
|
||||
/* vec3 sun_dir = sun_info.dir;
|
||||
vec3 moon_dir = moon_info.dir; */
|
||||
vec3 sun_dir = sun_dir.xyz;
|
||||
vec3 moon_dir = moon_dir.xyz;
|
||||
|
||||
vec3 sun_color = get_sun_color(sun_dir);
|
||||
vec3 moon_color = get_moon_color(moon_dir);
|
||||
float sun_light = get_sun_brightness(/*sun_dir*/);//sun_info.brightness;;
|
||||
float moon_light = get_moon_brightness(/*moon_dir*/);//moon_info.brightness;
|
||||
|
||||
vec3 sun_chroma = sun_color * sun_light;
|
||||
vec3 moon_chroma = moon_color * moon_light;
|
||||
vec3 sun_color = get_sun_color(/*sun_dir*/) * SUN_COLOR_FACTOR;//sun_info.color * SUN_COLOR_FACTOR;
|
||||
vec3 moon_color = get_moon_color(/*moon_dir*/);//moon_info.color;
|
||||
|
||||
light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
|
||||
diffuse_light =
|
||||
sun_chroma * mix(1.0, max(dot(-norm, sun_dir) * 0.5 + 0.5, 0.0), diffusion) +
|
||||
moon_chroma * mix(1.0, pow(dot(-norm, moon_dir) * 2.0, 2.0), diffusion) +
|
||||
PERSISTENT_AMBIANCE;
|
||||
ambient_light = vec3(SUN_AMBIANCE * sun_light + moon_light);
|
||||
// If the sun is facing the wrong way, we currently just want zero light, hence default point is wpos.
|
||||
vec3 sun_attenuation = compute_attenuation(wpos, -sun_dir, mu, surface_alt, wpos);
|
||||
vec3 moon_attenuation = compute_attenuation(wpos, -moon_dir, mu, surface_alt, wpos);
|
||||
|
||||
vec3 sun_chroma = sun_color * sun_light * cam_attenuation * sun_attenuation;
|
||||
vec3 moon_chroma = moon_color * moon_light * cam_attenuation * moon_attenuation;
|
||||
|
||||
// #ifdef HAS_SHADOW_MAPS
|
||||
// float sun_shadow = ShadowCalculationDirected(light_pos, 0u);
|
||||
// float moon_shadow = ShadowCalculationDirected(light_pos, 1u);
|
||||
// #else
|
||||
// float sun_shadow = 1.0;
|
||||
// float moon_shadow = 1.0;
|
||||
// #endif
|
||||
float sun_shadow = sun_info.shadow;
|
||||
float moon_shadow = moon_info.shadow;
|
||||
|
||||
// https://en.m.wikipedia.org/wiki/Diffuse_sky_radiation
|
||||
//
|
||||
// HdRd radiation should come in at angle normal to us.
|
||||
// const float H_d = 0.23;
|
||||
//
|
||||
// Let β be the angle from horizontal
|
||||
// (for objects exposed to the sky, where positive when sloping towards south and negative when sloping towards north):
|
||||
//
|
||||
// sin β = (north ⋅ norm) / |north||norm|
|
||||
// = dot(vec3(0, 1, 0), norm)
|
||||
//
|
||||
// cos β = sqrt(1.0 - dot(vec3(0, 1, 0), norm))
|
||||
//
|
||||
// Let h be the hour angle (180/0.0 at midnight, 90/1.0 at dawn, 0/0.0 at noon, -90/-1.0 at dusk, -180 at midnight/0.0):
|
||||
// cos h = (midnight ⋅ -light_dir) / |midnight||-light_dir|
|
||||
// = (noon ⋅ light_dir) / |noon||light_dir|
|
||||
// = dot(vec3(0, 0, 1), light_dir)
|
||||
//
|
||||
// Let φ be the latitude at this point. 0 at equator, -90 at south pole / 90 at north pole.
|
||||
//
|
||||
// Let δ be the solar declination (angular distance of the sun's rays north [or south[]
|
||||
// of the equator), i.e. the angle made by the line joining the centers of the sun and Earth with its projection on the
|
||||
// equatorial plane. Caused by axial tilt, and 0 at equinoxes. Normally varies between -23.45 and 23.45 degrees.
|
||||
//
|
||||
// Let α (the solar altitude / altitud3 angle) be the vertical angle between the projection of the sun's rays on the
|
||||
// horizontal plane and the direction of the sun's rays (passing through a point).
|
||||
//
|
||||
// Let Θ_z be the vertical angle between sun's rays and a line perpendicular to the horizontal plane through a point,
|
||||
// i.e.
|
||||
//
|
||||
// Θ_z = (π/2) - α
|
||||
//
|
||||
// i.e. cos Θ_z = sin α and
|
||||
// cos α = sin Θ_z
|
||||
//
|
||||
// Let γ_s be the horizontal angle measured from north to the horizontal projection of the sun's rays (positive when
|
||||
// measured westwise).
|
||||
//
|
||||
// cos Θ_z = cos φ cos h cos δ + sin φ sin δ
|
||||
// cos γ_s = sec α (cos φ sin δ - cos δ sin φ cos h)
|
||||
// = (1 / √(1 - cos² Θ_z)) (cos φ sin δ - cos δ sin φ cos h)
|
||||
// sin γ_s = sec α cos δ sin h
|
||||
// = (1 / cos α) cos δ sin h
|
||||
// = (1 / sin Θ_z) cos δ sin h
|
||||
// = (1 / √(1 - cos² Θ_z)) cos δ sin h
|
||||
//
|
||||
// R_b = (sin(δ)sin(φ - β) + cos(δ)cos(h)cos(φ - β))/(sin(δ)sin(φ) + cos(δ)cos(h)cos(φ))
|
||||
//
|
||||
// Assuming we are on the equator (i.e. φ = 0), and there is no axial tilt or we are at an equinox (i.e. δ = 0):
|
||||
//
|
||||
// cos Θ_z = 1 * cos h * 1 + 0 * 0 = cos h
|
||||
// cos γ_s = (1 / √(1 - cos² h)) (1 * 0 - 1 * 0 * cos h)
|
||||
// = (1 / √(1 - cos² h)) * 0
|
||||
// = 0
|
||||
// sin γ_s = (1 / √(1 - cos² h)) * sin h
|
||||
// = sin h / sin h
|
||||
// = 1
|
||||
//
|
||||
// R_b = (0 * sin(0 - β) + 1 * cos(h) * cos(0 - β))/(0 * 0 + 1 * cos(h) * 1)
|
||||
// = (cos(h)cos(-β)) / cos(H)
|
||||
// = cos(-β), the angle from horizontal.
|
||||
//
|
||||
// NOTE: cos(-β) = cos(β).
|
||||
// float cos_sun = dot(norm, /*-sun_dir*/vec3(0, 0, 1));
|
||||
// float cos_moon = dot(norm, -moon_dir);
|
||||
//
|
||||
// Let ζ = diffuse reflectance of surrounding ground for solar radiation, then we have
|
||||
//
|
||||
// R_d = (1 + cos β) / 2
|
||||
// R_r = ζ (1 - cos β) / 2
|
||||
//
|
||||
// H_t = H_b R_b + H_d R_d + (H_b + H_d) R_r
|
||||
float sin_beta = dot(vec3(0, 1, 0), norm);
|
||||
float R_b = sqrt(1.0 - sin_beta * sin_beta);
|
||||
// Rough estimate of diffuse reflectance of rest of ground.
|
||||
// NOTE: zeta should be close to 0.7 with snow cover, 0.2 normally? Maybe?
|
||||
vec3 zeta = max(vec3(0.2), k_d * (1.0 - k_s));//vec3(0.2);// k_d * (1.0 - k_s);
|
||||
float R_d = (1 + R_b) * 0.5;
|
||||
vec3 R_r = zeta * (1.0 - R_b) * 0.5;
|
||||
//
|
||||
// We can break this down into:
|
||||
// H_t_b = H_b * (R_b + R_r) = light_intensity * (R_b + R_r)
|
||||
// H_t_r = H_d * (R_d + R_r) = light_intensity * (R_d + R_r)
|
||||
vec3 R_t_b = R_b + R_r;
|
||||
vec3 R_t_r = R_d + R_r;
|
||||
|
||||
// vec3 half_vec = normalize(-norm + dir);
|
||||
vec3 light_frac = R_t_b * (sun_chroma * SUN_AMBIANCE + moon_chroma * MOON_AMBIANCE) * light_reflection_factor(norm, /*norm*//*dir*/dir, /*-norm*/-/*dir*/norm, /*k_d*/k_d/* * (1.0 - k_s)*/, /*k_s*/vec3(0.0), alpha, voxel_norm, voxel_lighting);
|
||||
// vec3 light_frac = /*vec3(1.0)*//*H_d * */
|
||||
// SUN_AMBIANCE * /*sun_light*/sun_chroma * light_reflection_factor(norm, dir, /*vec3(0, 0, -1.0)*/-norm, vec3((1.0 + cos_sun) * 0.5), vec3(k_s * (1.0 - cos_sun) * 0.5), alpha) +
|
||||
// MOON_AMBIANCE * /*sun_light*/moon_chroma * light_reflection_factor(norm, dir, /*vec3(0, 0, -1.0)*/-norm, vec3((1.0 + cos_moon) * 0.5), vec3(k_s * (1.0 - cos_moon) * 0.5), alpha);
|
||||
/* float NLsun = max(dot(-norm, sun_dir), 0);
|
||||
float NLmoon = max(dot(-norm, moon_dir), 0);
|
||||
vec3 E = -dir; */
|
||||
|
||||
// Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// float ambient_sides = 0.0;
|
||||
// float ambient_sides = 0.5 - 0.5 * min(abs(dot(-norm, sun_dir)), abs(dot(-norm, moon_dir)));
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-norm, sun_dir)) * mix(0.0, 1.0, abs(sun_dir.z) * 10000.0) * 10000.0), 0.0, 0.5);
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-norm, sun_dir)) * mix(0.0, 1.0, abs(sun_dir.z) * 10000.0) * 10000.0), 0.0, 0.5);
|
||||
|
||||
emitted_light = light_frac + k_a * PERSISTENT_AMBIANCE * MU_SCATTER;
|
||||
// emitted_light = k_a * light_frac * (/*ambient_sides + */SUN_AMBIANCE * /*sun_light*/sun_chroma + /*vec3(moon_light)*/MOON_AMBIANCE * moon_chroma) + PERSISTENT_AMBIANCE;
|
||||
|
||||
reflected_light = R_t_r * (
|
||||
(1.0 - SUN_AMBIANCE) * sun_chroma * sun_shadow * (light_reflection_factor(norm, dir, sun_dir, k_d, k_s, alpha, voxel_norm, voxel_lighting) /*+
|
||||
light_reflection_factor(norm, dir, normalize(sun_dir + vec3(0.0, 0.1, 0.0)), k_d, k_s, alpha) +
|
||||
light_reflection_factor(norm, dir, normalize(sun_dir - vec3(0.0, 0.1, 0.0)), k_d, k_s, alpha)*/) +
|
||||
(1.0 - MOON_AMBIANCE) * moon_chroma * moon_shadow * 1.0 * /*4.0 * */light_reflection_factor(norm, dir, moon_dir, k_d, k_s, alpha, voxel_norm, voxel_lighting)
|
||||
);
|
||||
|
||||
/* light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
|
||||
diffuse_light =
|
||||
sun_chroma * mix(1.0, max(dot(-norm, sun_dir) * 0.5 + 0.5, 0.0), diffusion) +
|
||||
moon_chroma * mix(1.0, pow(dot(-norm, moon_dir) * 2.0, 2.0), diffusion) +
|
||||
PERSISTENT_AMBIANCE;
|
||||
ambient_light = vec3(SUN_AMBIANCE * sun_light + moon_light); */
|
||||
return rel_luminance(emitted_light + reflected_light);//rel_luminance(emitted_light + reflected_light);//sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
|
||||
}
|
||||
|
||||
float get_sun_diffuse2(DirectionalLight sun_info, DirectionalLight moon_info, vec3 norm, vec3 dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 voxel_norm, float voxel_lighting, out vec3 emitted_light, out vec3 reflected_light) {
|
||||
return get_sun_diffuse2(sun_info, moon_info, norm, dir, vec3(0.0), vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, voxel_norm, voxel_lighting, emitted_light, reflected_light);
|
||||
}
|
||||
|
||||
float get_sun_diffuse2(DirectionalLight sun_info, DirectionalLight moon_info, vec3 norm, vec3 dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, out vec3 emitted_light, out vec3 reflected_light) {
|
||||
return get_sun_diffuse2(sun_info, moon_info, norm, dir, vec3(0.0), vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, norm, 1.0, emitted_light, reflected_light);
|
||||
}
|
||||
|
||||
// This has been extracted into a function to allow quick exit when detecting a star.
|
||||
float is_star_at(vec3 dir) {
|
||||
float star_scale = 80.0;
|
||||
float star_scale = 80.0;
|
||||
|
||||
// Star positions
|
||||
vec3 pos = (floor(dir * star_scale) - 0.5) / star_scale;
|
||||
// Star positions
|
||||
vec3 pos = (floor(dir * star_scale) - 0.5) / star_scale;
|
||||
|
||||
// Noisy offsets
|
||||
pos += (3.0 / star_scale) * (1.0 + hash(pos.yxzz) * 0.85);
|
||||
// Noisy offsets
|
||||
pos += (3.0 / star_scale) * (1.0 + hash(pos.yxzz) * 0.85);
|
||||
|
||||
// Find distance to fragment
|
||||
float dist = length(pos - dir);
|
||||
// Find distance to fragment
|
||||
float dist = length(pos - dir);
|
||||
|
||||
// Star threshold
|
||||
if (dist < 0.0015) {
|
||||
return 1.0;
|
||||
}
|
||||
// Star threshold
|
||||
if (dist < 0.0015) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars, float refractionIndex, out vec4 clouds) {
|
||||
#if (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
const bool has_clouds = false;
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
const bool has_clouds = true;
|
||||
#endif
|
||||
|
||||
if (with_stars || has_clouds) {
|
||||
// Sky color
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day); */
|
||||
vec3 sun_dir = sun_dir.xyz;
|
||||
vec3 moon_dir = moon_dir.xyz;
|
||||
|
||||
// sun_dir = sun_dir.z <= 0 ? refract(sun_dir/*-view_dir*/, vec3(0.0, 0.0, 1.0), refractionIndex) : sun_dir;
|
||||
// moon_dir = moon_dir.z <= 0 ? refract(moon_dir/*-view_dir*/, vec3(0.0, 0.0, 1.0), refractionIndex) : moon_dir;
|
||||
|
||||
// Add white dots for stars. Note these flicker and jump due to FXAA
|
||||
float star = 0.0;
|
||||
if (with_stars) {
|
||||
vec3 star_dir = normalize(sun_dir * dir.z + cross(sun_dir, vec3(0, 1, 0)) * dir.x + vec3(0, 1, 0) * dir.y);
|
||||
star = is_star_at(star_dir);
|
||||
}
|
||||
|
||||
// Sun
|
||||
const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.0;
|
||||
|
||||
vec3 sun_halo_color = mix(
|
||||
SUN_HALO_DUSK,
|
||||
SUN_HALO_DAY,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sun_halo = pow(max(dot(dir, -sun_dir) + 0.1, 0.0), 8.0) * sun_halo_color;
|
||||
vec3 sun_surf = pow(max(dot(dir, -sun_dir) - 0.001, 0.0), 3000.0) * SUN_SURF_COLOR * SUN_COLOR_FACTOR;
|
||||
vec3 sun_light = (sun_halo + sun_surf) * clamp(dir.z * 10.0, 0, 1);
|
||||
|
||||
// Moon
|
||||
const vec3 MOON_SURF_COLOR = vec3(0.7, 1.0, 1.5) * 500.0;
|
||||
const vec3 MOON_HALO_COLOR = vec3(0.015, 0.015, 0.05);
|
||||
|
||||
vec3 moon_halo = pow(max(dot(dir, -moon_dir) + 0.1, 0.0), 8.0) * MOON_HALO_COLOR;
|
||||
vec3 moon_surf = pow(max(dot(dir, -moon_dir) - 0.001, 0.0), 3000.0) * MOON_SURF_COLOR;
|
||||
vec3 moon_light = clamp(moon_halo + moon_surf, vec3(0), vec3(max(dir.z * 3.0, 0)));
|
||||
|
||||
// Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1
|
||||
|
||||
vec3 sky_top = mix(
|
||||
mix(
|
||||
SKY_DUSK_TOP + star / (1.0 + moon_surf * 100.0),
|
||||
SKY_NIGHT_TOP + star / (1.0 + moon_surf * 100.0),
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_TOP,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_mid = mix(
|
||||
mix( SKY_DUSK_MID,
|
||||
SKY_NIGHT_MID,
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_MID,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_bot = mix(
|
||||
mix(
|
||||
SKY_DUSK_BOT,
|
||||
SKY_NIGHT_BOT,
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_BOT,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_color = mix(
|
||||
mix(
|
||||
sky_mid,
|
||||
sky_bot,
|
||||
pow(max(-dir.z, 0), 0.4)
|
||||
),
|
||||
sky_top,
|
||||
max(dir.z, 0)
|
||||
);
|
||||
|
||||
// Approximate distance to fragment
|
||||
float f_dist = distance(origin, f_pos);
|
||||
|
||||
// Clouds
|
||||
#if (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
clouds = vec4(0.0);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
clouds = get_cloud_color(dir, origin, time_of_day, f_dist, quality);
|
||||
clouds.rgb *= get_sun_brightness(/*sun_dir*/) * (sun_halo * 1.5 + get_sun_color(/*sun_dir*/)) + get_moon_brightness(/*moon_dir*/) * (moon_halo * 80.0 + get_moon_color(/*moon_dir*/) + 0.25);
|
||||
#endif
|
||||
|
||||
if (f_dist > 5000.0) {
|
||||
sky_color += sun_light + moon_light;
|
||||
}
|
||||
return mix(sky_color, clouds.rgb, clouds.a);
|
||||
} else {
|
||||
clouds = vec4(0.0);
|
||||
return vec3(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars, out vec4 clouds) {
|
||||
// Sky color
|
||||
vec3 sun_dir = get_sun_dir(time_of_day);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day);
|
||||
|
||||
// Add white dots for stars. Note these flicker and jump due to FXAA
|
||||
float star = 0.0;
|
||||
if (with_stars) {
|
||||
vec3 star_dir = normalize(sun_dir * dir.z + cross(sun_dir, vec3(0, 1, 0)) * dir.x + vec3(0, 1, 0) * dir.y);
|
||||
star = is_star_at(star_dir);
|
||||
}
|
||||
|
||||
// Sun
|
||||
const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 200.0;
|
||||
|
||||
vec3 sun_halo_color = mix(
|
||||
SUN_HALO_DUSK,
|
||||
SUN_HALO_DAY,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sun_halo = pow(max(dot(dir, -sun_dir) + 0.1, 0.0), 8.0) * sun_halo_color;
|
||||
vec3 sun_surf = pow(max(dot(dir, -sun_dir) - 0.001, 0.0), 3000.0) * SUN_SURF_COLOR;
|
||||
vec3 sun_light = (sun_halo + sun_surf) * clamp(dir.z * 10.0, 0, 1);
|
||||
|
||||
// Moon
|
||||
const vec3 MOON_SURF_COLOR = vec3(0.7, 1.0, 1.5) * 500.0;
|
||||
const vec3 MOON_HALO_COLOR = vec3(0.015, 0.015, 0.05);
|
||||
|
||||
vec3 moon_halo = pow(max(dot(dir, -moon_dir) + 0.1, 0.0), 8.0) * MOON_HALO_COLOR;
|
||||
vec3 moon_surf = pow(max(dot(dir, -moon_dir) - 0.001, 0.0), 3000.0) * MOON_SURF_COLOR;
|
||||
vec3 moon_light = clamp(moon_halo + moon_surf, vec3(0), vec3(max(dir.z * 3.0, 0)));
|
||||
|
||||
// Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1
|
||||
|
||||
vec3 sky_top = mix(
|
||||
mix(
|
||||
SKY_DUSK_TOP + star / (1.0 + moon_surf * 100.0),
|
||||
SKY_NIGHT_TOP + star / (1.0 + moon_surf * 100.0),
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_TOP,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_mid = mix(
|
||||
mix(
|
||||
SKY_DUSK_MID,
|
||||
SKY_NIGHT_MID,
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_MID,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_bot = mix(
|
||||
mix(
|
||||
SKY_DUSK_BOT,
|
||||
SKY_NIGHT_BOT,
|
||||
max(pow(sun_dir.z, 0.2), 0)
|
||||
),
|
||||
SKY_DAY_BOT,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
|
||||
vec3 sky_color = mix(
|
||||
mix(
|
||||
sky_mid,
|
||||
sky_bot,
|
||||
pow(max(-dir.z, 0), 0.4)
|
||||
),
|
||||
sky_top,
|
||||
max(dir.z, 0)
|
||||
);
|
||||
|
||||
// Approximate distance to fragment
|
||||
float f_dist = distance(origin, f_pos);
|
||||
|
||||
// Clouds
|
||||
clouds = get_cloud_color(dir, origin, time_of_day, f_dist, quality);
|
||||
clouds.rgb *= get_sun_brightness(sun_dir) * (sun_halo * 1.5 + get_sun_color(sun_dir)) + get_moon_brightness(moon_dir) * (moon_halo * 80.0 + get_moon_color(moon_dir) + 0.25);
|
||||
|
||||
if (f_dist > 5000.0) {
|
||||
sky_color += sun_light + moon_light;
|
||||
}
|
||||
|
||||
return mix(sky_color, clouds.rgb, clouds.a);
|
||||
return get_sky_color(dir, time_of_day, origin, f_pos, quality, with_stars, 1.0, clouds);
|
||||
}
|
||||
|
||||
float fog(vec3 f_pos, vec3 focus_pos, uint medium) {
|
||||
float fog_radius = view_distance.x;
|
||||
float mist_radius = 10000000.0;
|
||||
return max(1.0 - 5000.0 / (1.0 + distance(f_pos.xy, focus_pos.xy)), 0.0);
|
||||
|
||||
float min_fog = 0.5;
|
||||
float max_fog = 1.0;
|
||||
float fog_radius = view_distance.x;
|
||||
float mist_radius = 10000000.0;
|
||||
|
||||
if (medium == 1u) {
|
||||
mist_radius = UNDERWATER_MIST_DIST;
|
||||
min_fog = 0.0;
|
||||
}
|
||||
float min_fog = 0.5;
|
||||
float max_fog = 1.0;
|
||||
|
||||
float fog = distance(f_pos.xy, focus_pos.xy) / fog_radius;
|
||||
float mist = distance(f_pos, focus_pos) / mist_radius;
|
||||
if (medium == 1u) {
|
||||
mist_radius = UNDERWATER_MIST_DIST;
|
||||
min_fog = 0.0;
|
||||
}
|
||||
|
||||
return pow(clamp((max(fog, mist) - min_fog) / (max_fog - min_fog), 0.0, 1.0), 1.7);
|
||||
float fog = distance(f_pos.xy, focus_pos.xy) / fog_radius;
|
||||
float mist = distance(f_pos, focus_pos) / mist_radius;
|
||||
|
||||
return pow(clamp((max(fog, mist) - min_fog) / (max_fog - min_fog), 0.0, 1.0), 1.7);
|
||||
}
|
||||
|
||||
/* vec3 illuminate(vec3 color, vec3 light, vec3 diffuse, vec3 ambience) {
|
||||
float avg_col = (color.r + color.g + color.b) / 3.0;
|
||||
return ((color - avg_col) * light + (diffuse + ambience) * avg_col) * (diffuse + ambience);
|
||||
} */
|
||||
vec3 illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitted, vec3 reflected) {
|
||||
return emitted + reflected;
|
||||
const float NIGHT_EXPOSURE = 10.0;
|
||||
const float DUSK_EXPOSURE = 2.0;//0.8;
|
||||
const float DAY_EXPOSURE = 1.0;//0.7;
|
||||
|
||||
#if (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_ASHIKHMIN)
|
||||
const float DAY_SATURATION = 1.1;
|
||||
#else
|
||||
const float DAY_SATURATION = 1.0;
|
||||
#endif
|
||||
const float DUSK_SATURATION = 0.6;
|
||||
const float NIGHT_SATURATION = 0.1;
|
||||
|
||||
const float gamma = /*0.5*//*1.*0*/1.0;//1.0;
|
||||
/* float light = length(emitted + reflected);
|
||||
float color = srgb_to_linear(emitted + reflected);
|
||||
float avg_col = (color.r + color.g + color.b) / 3.0;
|
||||
return ((color - avg_col) * light + reflected * avg_col) * (emitted + reflected); */
|
||||
// float max_intensity = vec3(1.0);
|
||||
vec3 color = emitted + reflected;
|
||||
float lum = rel_luminance(color);
|
||||
// float lum_sky = lum - max_light;
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
float sky_light = rel_luminance(
|
||||
get_sun_color(/*sun_dir*/) * get_sun_brightness(/*sun_dir*/) * SUN_COLOR_FACTOR +
|
||||
get_moon_color(/*moon_dir*/) * get_moon_brightness(/*moon_dir*/));
|
||||
|
||||
// Tone mapped value.
|
||||
// vec3 T = /*color*//*lum*/color;//normalize(color) * lum / (1.0 + lum);
|
||||
// float alpha = 0.5;//2.0;
|
||||
float alpha = mix(
|
||||
mix(
|
||||
DUSK_EXPOSURE,
|
||||
NIGHT_EXPOSURE,
|
||||
max(sun_dir.z, 0)
|
||||
),
|
||||
DAY_EXPOSURE,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
vec3 now_light = moon_dir.z < 0 ? moon_dir.xyz : sun_dir.xyz;
|
||||
float cos_view_light = dot(-now_light, view_dir);
|
||||
// alpha *= exp(1.0 - cos_view_light);
|
||||
// sky_light *= 1.0 - log(1.0 + view_dir.z);
|
||||
float alph = sky_light > 0.0 && max_light > 0.0 ? mix(1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light / (0.0 + sky_light)), 1.0, clamp(max_light - sky_light, 0.0, 1.0)) : 1.0;
|
||||
alpha = alpha * min(alph, 1.0);//((max_light > 0.0 && max_light > sky_light /* && sky_light > 0.0*/) ? /*1.0*/1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light - (0.0 + sky_light)) : 1.0);
|
||||
// alpha = alpha * min(1.0, (max_light == 0.0 ? 1.0 : (1.0 + abs(lum_sky)) / /*(1.0 + max_light)*/max_light));
|
||||
|
||||
vec3 col_adjusted = lum == 0.0 ? vec3(0.0) : color / lum;
|
||||
|
||||
// float L = lum == 0.0 ? 0.0 : log(lum);
|
||||
|
||||
|
||||
// // float B = T;
|
||||
// // float B = L + log(alpha);
|
||||
// float B = lum;
|
||||
|
||||
// float D = L - B;
|
||||
|
||||
// float o = 0.0;//log(PERSISTENT_AMBIANCE);
|
||||
// float scale = /*-alpha*/-alpha;//1.0;
|
||||
|
||||
// float B_ = (B - o) * scale;
|
||||
|
||||
// // float T = lum;
|
||||
// float O = exp(B_ + D);
|
||||
|
||||
float T = 1.0 - exp(-alpha * lum);//lum / (1.0 + lum);
|
||||
// float T = lum;
|
||||
|
||||
// Heuristic desaturation
|
||||
// const float s = 0.8;
|
||||
float s = mix(
|
||||
mix(
|
||||
DUSK_SATURATION,
|
||||
NIGHT_SATURATION,
|
||||
max(sun_dir.z, 0)
|
||||
),
|
||||
DAY_SATURATION,
|
||||
max(-sun_dir.z, 0)
|
||||
);
|
||||
// s = max(s, (max_light) / (1.0 + s));
|
||||
s = max(s, max_light / (1.0 + max_light));
|
||||
|
||||
vec3 c = pow(col_adjusted, vec3(s)) * T;
|
||||
// vec3 c = col_adjusted * T;
|
||||
// vec3 c = sqrt(col_adjusted) * T;
|
||||
// vec3 c = /*col_adjusted * */col_adjusted * T;
|
||||
|
||||
// return color;
|
||||
return c;
|
||||
// float sum_col = color.r + color.g + color.b;
|
||||
// return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma)));
|
||||
}
|
||||
|
@ -1,3 +1,24 @@
|
||||
// Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
|
||||
// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water
|
||||
const vec3 MU_WATER = vec3(0.6, 0.04, 0.01);
|
||||
|
||||
// // NOTE: Automatic in v4.0
|
||||
// float
|
||||
// mip_map_level(in vec2 texture_coordinate)
|
||||
// {
|
||||
// // The OpenGL Graphics System: A Specification 4.2
|
||||
// // - chapter 3.9.11, equation 3.21
|
||||
//
|
||||
//
|
||||
// vec2 dx_vtc = dFdx(texture_coordinate);
|
||||
// vec2 dy_vtc = dFdy(texture_coordinate);
|
||||
// float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
||||
//
|
||||
//
|
||||
// //return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0); // == log2(sqrt(delta_max_sqr));
|
||||
// return 0.5 * log2(delta_max_sqr); // == log2(sqrt(delta_max_sqr));
|
||||
// }
|
||||
|
||||
//https://gamedev.stackexchange.com/questions/92015/optimized-linear-to-srgb-glsl
|
||||
vec3 srgb_to_linear(vec3 srgb) {
|
||||
bvec3 cutoff = lessThan(srgb, vec3(0.04045));
|
||||
@ -7,10 +28,592 @@ vec3 srgb_to_linear(vec3 srgb) {
|
||||
return mix(higher, lower, cutoff);
|
||||
}
|
||||
|
||||
vec3 linear_to_srgb(vec3 linear) {
|
||||
bvec3 cutoff = lessThan(linear, vec3(0.0031308));
|
||||
vec3 higher = vec3(1.055) * pow(linear, vec3(1.0 / 2.4)) - vec3(0.055);
|
||||
vec3 lower = linear * vec3(12.92);
|
||||
|
||||
return mix(higher, lower, cutoff);
|
||||
vec3 linear_to_srgb(vec3 col) {
|
||||
// bvec3 cutoff = lessThan(col, vec3(0.0060));
|
||||
// return mix(11.500726 * col, , cutoff);
|
||||
vec3 s1 = vec3(sqrt(col.r), sqrt(col.g), sqrt(col.b));
|
||||
vec3 s2 = vec3(sqrt(s1.r), sqrt(s1.g), sqrt(s1.b));
|
||||
vec3 s3 = vec3(sqrt(s2.r), sqrt(s2.g), sqrt(s2.b));
|
||||
return vec3(
|
||||
mix(11.500726 * col.r, (0.585122381 * s1.r + 0.783140355 * s2.r - 0.368262736 * s3.r), clamp((col.r - 0.0060) * 10000.0, 0.0, 1.0)),
|
||||
mix(11.500726 * col.g, (0.585122381 * s1.g + 0.783140355 * s2.g - 0.368262736 * s3.g), clamp((col.g - 0.0060) * 10000.0, 0.0, 1.0)),
|
||||
mix(11.500726 * col.b, (0.585122381 * s1.b + 0.783140355 * s2.b - 0.368262736 * s3.b), clamp((col.b - 0.0060) * 10000.0, 0.0, 1.0))
|
||||
);
|
||||
}
|
||||
|
||||
float pow5(float x) {
|
||||
float x2 = x * x;
|
||||
return x2 * x2 * x;
|
||||
}
|
||||
|
||||
vec4 pow5(vec4 x) {
|
||||
vec4 x2 = x * x;
|
||||
return x2 * x2 * x;
|
||||
}
|
||||
|
||||
// Fresnel angle for perfectly specular dialectric materials.
|
||||
|
||||
// Schlick approximation
|
||||
vec3 schlick_fresnel(vec3 Rs, float cosTheta) {
|
||||
// auto pow5 = [](Float v) { return (v * v) * (v * v) * v; };
|
||||
// return Rs + pow5(1 - cosTheta) * (Spectrum(1.) - Rs);
|
||||
return Rs + pow5(1.0 - cosTheta) * (1.0 - Rs);
|
||||
}
|
||||
|
||||
// Beckmann Distribution
|
||||
float BeckmannDistribution_D(float NdotH, float alpha) {
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
float NdotH2m2 = NdotH2 * alpha * alpha;
|
||||
float k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2);
|
||||
return mix(k_spec, 0.0, NdotH == 0.0);
|
||||
}
|
||||
|
||||
// Voxel Distribution
|
||||
float BeckmannDistribution_D_Voxel(vec3 wh, vec3 voxel_norm, float alpha) {
|
||||
vec3 sides = sign(voxel_norm);
|
||||
// vec3 cos_sides_i = /*sides * */sides * norm;
|
||||
// vec3 cos_sides_o = max(sides * view_dir, 0.0);
|
||||
|
||||
vec3 NdotH = wh * sides;//max(wh * sides, 0.0);/*cos_sides_i*///max(sides * wh, 0.0);
|
||||
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
vec3 NdotH2 = NdotH * NdotH;
|
||||
vec3 NdotH2m2 = NdotH2 * alpha * alpha;
|
||||
vec3 k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2);
|
||||
return dot(mix(k_spec, /*cos_sides_o*/vec3(0.0), equal(NdotH, vec3(0.0))), /*cos_sides_i*/abs(voxel_norm));
|
||||
// // const float PI = 3.1415926535897932384626433832795;
|
||||
// const vec3 normals[6] = vec3[](vec3(1,0,0), vec3(0,1,0), vec3(0,0,1), vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1));
|
||||
|
||||
// float voxel_norm = 0.0;
|
||||
// for (int i = 0; i < 6; i ++) {
|
||||
// // Light reflecting off the half-angle can shine on up to three sides.
|
||||
// // So, the idea here is to figure out the ratio of visibility of each of these
|
||||
// // three sides such that their sum adds to 1, then computing a Beckmann Distribution for each side times
|
||||
// // the this ratio.
|
||||
// //
|
||||
// // The ratio of these normals in each direction should be the sum of their cosines with the light over π,
|
||||
// // I think.
|
||||
// //
|
||||
// // cos (wh, theta)
|
||||
// //
|
||||
// // - one normal
|
||||
// //
|
||||
// // The ratio of each of the three exposed sides should just be the slope.
|
||||
// vec3 side = normals[i];
|
||||
// float side_share = max(dot(norm, side), 0.0);
|
||||
// float NdotH = max(dot(wh, side), 0.0);
|
||||
// voxel_norm += side_share * BeckmannDistribution_D(NdotH, alpha);
|
||||
// // voxel_norm += normals[i] * side_visible * max(dot(-cam_dir, normals[i]), 0.0);
|
||||
// // voxel_norm += normals[i] * side_visible * max(dot(-cam_dir, normals[i]), 0.0);
|
||||
// }
|
||||
|
||||
// /* float NdotH = dot(wh, norm);
|
||||
// float NdotH2 = NdotH * NdotH;
|
||||
// float NdotH2m2 = NdotH2 * alpha * alpha;
|
||||
|
||||
// float k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2);
|
||||
// return mix(k_spec, 0.0, NdotH == 0.0); */
|
||||
// return voxel_norm;
|
||||
}
|
||||
|
||||
float TrowbridgeReitzDistribution_D_Voxel(vec3 wh, vec3 voxel_norm, float alpha) {
|
||||
vec3 sides = sign(voxel_norm);
|
||||
// vec3 cos_sides_i = /*sides * */sides * norm;
|
||||
// vec3 cos_sides_o = max(sides * view_dir, 0.0);
|
||||
|
||||
vec3 NdotH = wh * sides;//max(wh * sides, 0.0);/*cos_sides_i*///max(sides * wh, 0.0);
|
||||
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
vec3 NdotH2 = NdotH * NdotH;
|
||||
// vec3 m2 = alpha * alpha;
|
||||
// vec3 NdotH2m2 = NdotH2 * m2;
|
||||
vec3 NdotH2m2 = NdotH2 * alpha * alpha;
|
||||
// vec3 Tan2Theta = (1 - NdotH2) / NdotH2;
|
||||
// vec3 e = (NdotH2 / m2 + (1 - NdotH2) / m2) * Tan2Theta;
|
||||
// vec3 e = 1 / m2 * (1 - NdotH2) / NdotH2;
|
||||
vec3 e = (1 - NdotH2) / NdotH2m2;
|
||||
vec3 k_spec = 1.0 / (PI * NdotH2m2 * NdotH2 * (1 + e) * (1 + e));
|
||||
// vec3 k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2);
|
||||
return dot(mix(k_spec, /*cos_sides_o*/vec3(0.0), equal(NdotH, vec3(0.0))), /*cos_sides_i*/abs(voxel_norm));
|
||||
}
|
||||
|
||||
float BeckmannDistribution_Lambda(vec3 norm, vec3 dir, float alpha) {
|
||||
float CosTheta = /*max(dot(norm, dir), 0.0);*/dot(norm, dir);
|
||||
/* if (CosTheta == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
|
||||
float TanTheta = SinTheta / CosTheta;
|
||||
float absTanTheta = abs(TanTheta); */
|
||||
// vec3 w = normalize(dir - dot(dir, norm) * (norm));
|
||||
// float CosTheta = w.z;
|
||||
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
|
||||
float TanTheta = SinTheta / CosTheta;
|
||||
float absTanTheta = abs(TanTheta);
|
||||
/* if (isinf(absTanTheta)) {
|
||||
return 0.0;
|
||||
} */
|
||||
/* float CosPhi = mix(clamp(projDirNorm.x / sinTheta, -1.0, 1.0), 0.0, sinTheta == 0.0);
|
||||
float SinPhi = mix(clamp(projDirNorm.y / sinTheta, -1.0, 1.0), 0.0, sinTheta == 0.0);
|
||||
float alpha = sqrt(CosPhi * CosPhi * alphax * alphax + SinPhi * SinPhi * alphay * alphay); */
|
||||
// Float absTanTheta = std::abs(TanTheta(w));
|
||||
// if (std::isinf(absTanTheta)) return 0.;
|
||||
// <<Compute alpha for direction w>>
|
||||
// Float alpha = std::sqrt(Cos2Phi(w) * alphax * alphax +
|
||||
// Sin2Phi(w) * alphay * alphay);
|
||||
float a = 1.0 / (alpha * absTanTheta);
|
||||
/* if (a >= 1.6) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return (1.0 - 1.259 * a + 0.396 * a * a) / (3.535 * a + 2.181 * a * a); */
|
||||
|
||||
return mix(max(0.0, (1.0 - 1.259 * a + 0.396 * a * a) / (3.535 * a + 2.181 * a * a)), 0.0, isinf(absTanTheta) || a >= 1.6);
|
||||
// Float a = 1 / (alpha * absTanTheta);
|
||||
// if (a >= 1.6f)
|
||||
// return 0;
|
||||
// return (1 - 1.259f * a + 0.396f * a * a) /
|
||||
// (3.535f * a + 2.181f * a * a);
|
||||
// return 1 / (1 + Lambda(wo) + Lambda(wi));
|
||||
}
|
||||
|
||||
float BeckmannDistribution_G(vec3 norm, vec3 dir, vec3 light_dir, float alpha) {
|
||||
// return 1 / (1 + Lambda(wo) + Lambda(wi));
|
||||
return 1.0 / (1.0 + BeckmannDistribution_Lambda(norm, dir, alpha) + BeckmannDistribution_Lambda(norm, -light_dir, alpha));
|
||||
}
|
||||
|
||||
// Fresnel blending
|
||||
//
|
||||
// http://www.pbr-book.org/3ed-2018/Reflection_Models/Microfacet_Models.html#fragment-MicrofacetDistributionPublicMethods-2
|
||||
// and
|
||||
// http://www.pbr-book.org/3ed-2018/Reflection_Models/Fresnel_Incidence_Effects.html
|
||||
vec3 FresnelBlend_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_s, float alpha) {
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
alpha = alpha * sqrt(2.0);
|
||||
float cos_wi = /*max(*/dot(-light_dir, norm)/*, 0.0)*/;
|
||||
float cos_wo = /*max(*/dot(dir, norm)/*, 0.0)*/;
|
||||
|
||||
vec3 diffuse = (28.0 / (23.0 * PI)) * R_d *
|
||||
(1.0 - R_s) *
|
||||
(1.0 - pow5(1.0 - 0.5 * abs(cos_wi))) *
|
||||
(1.0 - pow5(1.0 - 0.5 * abs(cos_wo)));
|
||||
/* Spectrum diffuse = (28.f/(23.f*Pi)) * Rd *
|
||||
(Spectrum(1.f) - Rs) *
|
||||
(1 - pow5(1 - .5f * AbsCosTheta(wi))) *
|
||||
(1 - pow5(1 - .5f * AbsCosTheta(wo))); */
|
||||
// Vector3f wh = wi + wo;
|
||||
vec3 wh = -light_dir + dir;
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
bool is_blocked = cos_wi == 0.0 || cos_wo == 0.0;
|
||||
#else
|
||||
bool is_blocked = cos_wi <= 0.0 || cos_wo <= 0.0;
|
||||
#endif
|
||||
if (is_blocked) {
|
||||
return vec3(/*diffuse*/0.0);
|
||||
}
|
||||
// if (cos_wo < 0.0) {
|
||||
// return /*vec3(0.0)*/diffuse;
|
||||
// }
|
||||
/* if (cos_wi == 0.0 || cos_wo == 0.0) {
|
||||
return vec3(0.0);
|
||||
} */
|
||||
/* if (wh.x == 0 && wh.y == 0 && wh.z == 0) {
|
||||
return vec3(0.0);
|
||||
// return Spectrum(0);
|
||||
} */
|
||||
wh = normalize(wh);//mix(normalize(wh), vec3(0.0), equal(light_dir, dir));
|
||||
float dot_wi_wh = dot(-light_dir, wh);
|
||||
vec3 specular = BeckmannDistribution_D(dot(wh, norm), alpha) /
|
||||
(4 * abs(dot_wi_wh) *
|
||||
max(abs(cos_wi), abs(cos_wo))) *
|
||||
schlick_fresnel(R_s, dot_wi_wh);
|
||||
// Spectrum specular = distribution->D(wh) /
|
||||
// (4 * AbsDot(wi, wh) *
|
||||
// std::max(AbsCosTheta(wi), AbsCosTheta(wo))) *
|
||||
// SchlickFresnel(Dot(wi, wh));
|
||||
return mix(/*diffuse*//* + specular*/diffuse + specular, vec3(0.0), bvec3(all(equal(light_dir, dir))));
|
||||
}
|
||||
|
||||
// Fresnel blending
|
||||
//
|
||||
// http://www.pbr-book.org/3ed-2018/Reflection_Models/Microfacet_Models.html#fragment-MicrofacetDistributionPublicMethods-2
|
||||
// and
|
||||
// http://www.pbr-book.org/3ed-2018/Reflection_Models/Fresnel_Incidence_Effects.html
|
||||
vec3 FresnelBlend_Voxel_f(vec3 norm, vec3 dir, vec3 light_dir, vec3 R_d, vec3 R_s, float alpha, vec3 voxel_norm, float dist) {
|
||||
const float PI = 3.1415926535897932384626433832795;
|
||||
alpha = alpha * sqrt(2.0);
|
||||
float cos_wi = /*max(*/dot(-light_dir, norm)/*, 0.0)*/;
|
||||
float cos_wo = /*max(*/dot(dir, norm)/*, 0.0)*/;
|
||||
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
vec4 AbsNdotL = abs(vec4(light_dir, cos_wi));
|
||||
vec4 AbsNdotV = abs(vec4(dir, cos_wo));
|
||||
#else
|
||||
vec3 sides = sign(voxel_norm);
|
||||
vec4 AbsNdotL = vec4(max(-light_dir * sides, 0.0), abs(cos_wi));
|
||||
vec4 AbsNdotV = vec4(max(dir * sides, 0.0), abs(cos_wo));
|
||||
#endif
|
||||
|
||||
// float R_r = 1.0 - R_s;
|
||||
// float R_r = 1.0 - schlick_fresnel(R_s, cos_wi);
|
||||
// // Rs + pow5(1.0 - cosTheta) * (1.0 - Rs)
|
||||
// vec4 R_r = 1.0 - (R_s + (1.0 - R_s) * schlick_fresnel(R_s, cos_wi));
|
||||
// mat4 R_r = 1.0 - (vec4(R_s, 0.0) + vec4(1.0 - R_s, 0.0) * pow5(1.0 - AbsNdotL));
|
||||
// vec4 AbsNdotL5 = pow5(1.0 - AbsNdotL);
|
||||
// vec4 R_s4 = vec4(R_s, 0.0);
|
||||
// mat4 R_r =
|
||||
// // mat4(1.0 - (R_s.r + (1.0 - R_s.r) * AbsNdotL5),
|
||||
// // 1.0 - (R_s.g + (1.0 - R_s.g) * AbsNdotL5),
|
||||
// // 1.0 - (R_s.b + (1.0 - R_s.b) * AbsNdotL5),
|
||||
// // vec4(0.0)
|
||||
// // );
|
||||
// mat4(1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.x),
|
||||
// 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.y),
|
||||
// 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.z),
|
||||
// 1.0 - (R_s4 + (1.0 - R_s4) * AbsNdotL5.w)
|
||||
// );
|
||||
// * ) (R1.0 - R_s.r) 1.0 - (vec4(R_s, 0.0) + vec4(1.0 - R_s, 0.0) * pow5(1.0 - AbsNdotL));
|
||||
|
||||
vec4 diffuse_factor =
|
||||
// vec4(abs(vec4(-light_dir * sides, cos_wi)))
|
||||
(1.0 - pow5(1.0 - 0.5 * AbsNdotL)) *
|
||||
// (1.0 - pow5(1.0 - 0.5 * abs(vec4(-light_dir * sides, cos_wi)))) *
|
||||
// (1.0 - pow5(1.0 - 0.5 * abs(vec4(dir * sides, cos_wo))))
|
||||
(1.0 - pow5(1.0 - 0.5 * AbsNdotV))
|
||||
// vec4(1.0)
|
||||
;
|
||||
/* vec4 diffuse_factor =
|
||||
(1.0 - pow5(1.0 - 0.5 * max(vec4(-light_dir * sides, abs(cos_wi)), 0.0))) *
|
||||
(1.0 - pow5(1.0 - 0.5 * max(vec4(dir * sides, abs(cos_wo)), 0.0))); */
|
||||
|
||||
vec3 diffuse = (28.0 / (23.0 * PI))/*(1.0 / PI)*/ * R_d *
|
||||
(1.0 - R_s) *
|
||||
//vec3(
|
||||
dot(diffuse_factor, /*R_r * */vec4(abs(norm) * (1.0 - dist), dist))
|
||||
//)
|
||||
;
|
||||
|
||||
vec3 wh = -light_dir + dir;
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
bool is_blocked = cos_wi == 0.0 || cos_wo == 0.0;
|
||||
#else
|
||||
bool is_blocked = cos_wi <= 0.0 || cos_wo <= 0.0;
|
||||
#endif
|
||||
if (is_blocked) {
|
||||
return vec3(/*diffuse*/0.0);
|
||||
}
|
||||
wh = normalize(wh);//mix(normalize(wh), vec3(0.0), equal(light_dir, dir));
|
||||
float dot_wi_wh = dot(-light_dir, wh);
|
||||
// float distr = TrowbridgeReitzDistribution_D_Voxel(wh, voxel_norm, alpha);
|
||||
float distr = BeckmannDistribution_D_Voxel(wh, voxel_norm, alpha);
|
||||
// float distr = BeckmannDistribution_D(dot(wh, norm), alpha);
|
||||
vec3 specular = distr /
|
||||
(4 * abs(dot_wi_wh) *
|
||||
max(abs(cos_wi), abs(cos_wo))) *
|
||||
schlick_fresnel(R_s, dot_wi_wh);
|
||||
return mix(/*diffuse*//* + specular*/diffuse + specular, vec3(0.0), bvec3(all(equal(light_dir, dir))));
|
||||
}
|
||||
|
||||
// Phong reflection.
|
||||
//
|
||||
// Note: norm, dir, light_dir must all be normalizd.
|
||||
vec3 light_reflection_factor2(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 k_s, float alpha) {
|
||||
// TODO: These are supposed to be the differential changes in the point location p, in tangent space.
|
||||
// That is, assuming we can parameterize a 2D surface by some function p : R² → R³, mapping from
|
||||
// points in a plane to 3D points on the surface, we can define
|
||||
// ∂p(u,v)/∂u and ∂p(u,v)/∂v representing the changes in the pont location as we move along these
|
||||
// coordinates.
|
||||
//
|
||||
// Then we can define the normal at a point, n(u,v) = ∂p(u,v)/∂u × ∂p(u,v)/∂v.
|
||||
//
|
||||
// Additionally, we can define the change in *normals* at each point using the
|
||||
// Weingarten equations (see http://www.pbr-book.org/3ed-2018/Shapes/Spheres.html):
|
||||
//
|
||||
// ∂n/∂u = (fF - eG) / (EG - F²) ∂p/∂u + (eF - fE) / (EG - F²) ∂p/∂v
|
||||
// ∂n/∂v = (gF - fG) / (EG - F²) ∂p/∂u + (fF - gE) / (EG - F²) ∂p/∂v
|
||||
//
|
||||
// where
|
||||
//
|
||||
// E = |∂p/∂u ⋅ ∂p/∂u|
|
||||
// F = ∂p/∂u ⋅ ∂p/∂u
|
||||
// G = |∂p/∂v ⋅ ∂p/∂v|
|
||||
//
|
||||
// and
|
||||
//
|
||||
// e = n ⋅ ∂²p/∂u²
|
||||
// f = n ⋅ ∂²p/(∂u∂v)
|
||||
// g = n ⋅ ∂²p/∂v²
|
||||
//
|
||||
// For planes (see http://www.pbr-book.org/3ed-2018/Shapes/Triangle_Meshes.html) we have
|
||||
// e = f = g = 0 (since the plane has no curvature of any sort) so we get:
|
||||
//
|
||||
// ∂n/∂u = (0, 0, 0)
|
||||
// ∂n/∂v = (0, 0, 0)
|
||||
//
|
||||
// To find ∂p/∂u and ∂p/∂v, we first write p and u parametrically:
|
||||
// p(u, v) = p0 + u ∂p/∂u + v ∂p/∂v
|
||||
//
|
||||
// ( u₀ - u₂ v₀ - v₂
|
||||
// u₁ - u₂ v₁ - v₂ )
|
||||
//
|
||||
// Basis: plane norm = norm = (0, 0, 1), x vector = any orthgonal vector on the plane.
|
||||
// vec3 w_i =
|
||||
// vec3 w_i = vec3(view_mat * vec4(-light_dir, 1.0));
|
||||
// vec3 w_o = vec3(view_mat * vec4(light_dir, 1.0));
|
||||
float g = 1.0;// BeckmannDistribution_G(norm, dir, light_dir, alpha);
|
||||
return FresnelBlend_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s * g, alpha);
|
||||
// const float PI = 3.141592;
|
||||
// alpha = alpha * sqrt(2.0);
|
||||
// float ndotL = /*max*/(dot(norm, -light_dir)/*, 0.0*/);
|
||||
|
||||
// //if (ndotL > 0.0/* && dot(s_norm, -light_dir) > 0.0*/) {
|
||||
// vec3 H = normalize(-light_dir + dir);
|
||||
|
||||
// float NdotH = dot(norm, H);
|
||||
// float NdotH2 = NdotH * NdotH;
|
||||
// float NdotH2m2 = NdotH2 * alpha * alpha;
|
||||
// float k_spec = exp((NdotH2 - 1) / NdotH2m2) / (PI * NdotH2m2 * NdotH2);
|
||||
// return mix(k_s * k_spec, vec3(0.0), bvec3(ndotL <= 0.0 || NdotH == 0.0));
|
||||
// //
|
||||
// // (k_d * (L ⋅ N) + k_s * (R ⋅ V)^α)
|
||||
// // return k_d * ndotL + mix(k_s * pow(max(dot(norm, H), 0.0), alpha * 4.0), vec3(0.0), bvec3(ndotL == 0.0));
|
||||
// // }
|
||||
// // return vec3(0.0);
|
||||
}
|
||||
|
||||
vec3 light_reflection_factor(vec3 norm, vec3 dir, vec3 light_dir, vec3 k_d, vec3 k_s, float alpha, vec3 voxel_norm, float voxel_lighting) {
|
||||
#if (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_LAMBERTIAN)
|
||||
const float PI = 3.141592;
|
||||
#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL)
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
vec4 AbsNdotL = abs(vec4(light_dir, dot(norm, light_dir)));
|
||||
#else
|
||||
vec3 sides = sign(voxel_norm);
|
||||
vec4 AbsNdotL = max(vec4(-light_dir * sides, dot(norm, -light_dir)), 0.0);
|
||||
#endif
|
||||
float diffuse = dot(AbsNdotL, vec4(abs(voxel_norm) * (1.0 - voxel_lighting), voxel_lighting));
|
||||
#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET)
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
float diffuse = abs(dot(norm, light_dir));
|
||||
#else
|
||||
float diffuse = max(dot(norm, -light_dir), 0.0);
|
||||
#endif
|
||||
#endif
|
||||
return k_d / PI * diffuse;
|
||||
#elif (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_BLINN_PHONG)
|
||||
const float PI = 3.141592;
|
||||
alpha = alpha * sqrt(2.0);
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
float ndotL = abs(dot(norm, light_dir));
|
||||
#else
|
||||
float ndotL = max(dot(norm, -light_dir), 0.0);
|
||||
#endif
|
||||
|
||||
if (ndotL > 0.0) {
|
||||
#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL)
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
vec4 AbsNdotL = abs(vec4(light_dir, ndotL));
|
||||
#else
|
||||
vec3 sides = sign(voxel_norm);
|
||||
vec4 AbsNdotL = max(vec4(-light_dir * sides, ndotL), 0.0);
|
||||
#endif
|
||||
float diffuse = dot(AbsNdotL, vec4(abs(voxel_norm) * (1.0 - voxel_lighting), voxel_lighting));
|
||||
#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET)
|
||||
float diffuse = ndotL;
|
||||
#endif
|
||||
vec3 H = normalize(-light_dir + dir);
|
||||
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
float NdotH = abs(dot(norm, H));
|
||||
#else
|
||||
float NdotH = max(dot(norm, H), 0.0);
|
||||
#endif
|
||||
return (1.0 - k_s) / PI * k_d * diffuse + k_s * pow(NdotH, alpha/* * 4.0*/);
|
||||
}
|
||||
|
||||
return vec3(0.0);
|
||||
#elif (LIGHTING_ALGORITHM == LIGHTING_ALGORITHM_ASHIKHMIN)
|
||||
#if (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_VOXEL)
|
||||
return FresnelBlend_Voxel_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha, voxel_norm, voxel_lighting);
|
||||
#elif (LIGHTING_DISTRIBUTION_SCHEME == LIGHTING_DISTRIBUTION_SCHEME_MICROFACET)
|
||||
//if (voxel_lighting < 1.0) {
|
||||
return FresnelBlend_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha);
|
||||
//} else {
|
||||
// return FresnelBlend_f(norm, dir, light_dir, k_d/* * max(dot(norm, -light_dir), 0.0)*/, k_s, alpha);
|
||||
//}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
float rel_luminance(vec3 rgb)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Relative_luminance
|
||||
const vec3 W = vec3(0.2126, 0.7152, 0.0722);
|
||||
return dot(rgb, W);
|
||||
}
|
||||
|
||||
// From https://discourse.vvvv.org/t/infinite-ray-intersects-with-infinite-plane/10537
|
||||
// out of laziness.
|
||||
bool IntersectRayPlane(vec3 rayOrigin, vec3 rayDirection, vec3 posOnPlane, vec3 planeNormal, inout vec3 intersectionPoint)
|
||||
{
|
||||
float rDotn = dot(rayDirection, planeNormal);
|
||||
|
||||
//parallel to plane or pointing away from plane?
|
||||
if (rDotn < 0.0000001 )
|
||||
return false;
|
||||
|
||||
float s = dot(planeNormal, (posOnPlane - rayOrigin)) / rDotn;
|
||||
|
||||
intersectionPoint = rayOrigin + s * rayDirection;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compute uniform attenuation due to beam passing through a substance that fills an area below a horizontal plane
|
||||
// (e.g. in most cases, water below the water surface depth) using the simplest form of the Beer-Lambert law
|
||||
// (https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law):
|
||||
//
|
||||
// I(z) = I₀ e^(-μz)
|
||||
//
|
||||
// We compute this value, except for the initial intensity which may be multiplied out later.
|
||||
//
|
||||
// wpos is the position of the point being hit.
|
||||
// ray_dir is the reversed direction of the ray (going "out" of the point being hit).
|
||||
// mu is the attenuation coefficient for R, G, and B wavelenghts.
|
||||
// surface_alt is the estimated altitude of the horizontal surface separating the substance from air.
|
||||
// defaultpos is the position to use in computing the distance along material at this point if there was a failure.
|
||||
//
|
||||
// Ideally, defaultpos is set so we can avoid branching on error.
|
||||
vec3 compute_attenuation(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) {
|
||||
#if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE)
|
||||
return vec3(1.0);
|
||||
#elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE)
|
||||
#if (LIGHTING_TYPE & LIGHTING_TYPE_TRANSMISSION) != 0
|
||||
return vec3(1.0);
|
||||
#else
|
||||
// return vec3(1.0);
|
||||
/*if (mu == vec3(0.0)) {
|
||||
return vec3(1.0);
|
||||
}*//* else {
|
||||
return vec3(0.0);
|
||||
}*/
|
||||
// return vec3(0.0);
|
||||
// vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(surface_alt - wpos.z));
|
||||
ray_dir = faceforward(ray_dir, vec3(0.0, 0.0, -1.0), ray_dir);
|
||||
vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0);
|
||||
// vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0));
|
||||
bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos);
|
||||
float depth = length(defaultpos - wpos);
|
||||
return exp(-mu * depth);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// vec3 compute_attenuation2(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) {
|
||||
// #if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE)
|
||||
// return vec3(1.0);
|
||||
// #elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE)
|
||||
// // return vec3(1.0);
|
||||
// /*if (mu == vec3(0.0)) {
|
||||
// return vec3(1.0);
|
||||
// }*//* else {
|
||||
// return vec3(0.0);
|
||||
// }*/
|
||||
// // return vec3(0.0);
|
||||
// // vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(surface_alt - wpos.z));
|
||||
// vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
|
||||
// // vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0));
|
||||
// bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos);
|
||||
// float depth = length(defaultpos - wpos);
|
||||
// return exp(-mu * depth);
|
||||
// #endif
|
||||
// }
|
||||
|
||||
// Same as compute_attenuation but since both point are known, set a maximum to make sure we don't exceed the length
|
||||
// from the default point.
|
||||
vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) {
|
||||
#if (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_IMPORTANCE)
|
||||
return vec3(1.0);
|
||||
#elif (LIGHTING_TRANSPORT_MODE == LIGHTING_TRANSPORT_MODE_RADIANCE)
|
||||
// return vec3(1.0);
|
||||
/*if (mu == vec3(0.0)) {
|
||||
return vec3(1.0);
|
||||
}*//* else {
|
||||
return vec3(0.0);
|
||||
}*/
|
||||
// return vec3(0.0);
|
||||
vec3 surface_dir = /*surface_alt < wpos.z ? vec3(0.0, 0.0, -1.0) : vec3(0.0, 0.0, 1.0)*/vec3(0.0, 0.0, sign(wpos.z - surface_alt));
|
||||
// vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
|
||||
// vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0));
|
||||
float max_length = dot(defaultpos - wpos, defaultpos - wpos);
|
||||
bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos);
|
||||
float depth2 = min(max_length, dot(defaultpos - wpos, defaultpos - wpos));
|
||||
return exp(-mu * sqrt(depth2));
|
||||
#endif
|
||||
}
|
||||
|
||||
//#ifdef HAS_SHADOW_MAPS
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
//uniform sampler2DShadow t_directed_shadow_maps;
|
||||
//// uniform sampler2DArrayShadow t_directed_shadow_maps;
|
||||
//
|
||||
//float ShadowCalculationDirected(in vec4 /*light_pos[2]*/sun_pos, uint lightIndex)
|
||||
//{
|
||||
// float bias = 0.0;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
||||
// // const vec3 sampleOffsetDirections[20] = vec3[]
|
||||
// // (
|
||||
// // vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
|
||||
// // vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
|
||||
// // vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
|
||||
// // vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
|
||||
// // vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
|
||||
// // // vec3(0, 0, 0)
|
||||
// // );
|
||||
// /* if (lightIndex >= light_shadow_count.z) {
|
||||
// return 1.0;
|
||||
// } */
|
||||
// // vec3 fragPos = sun_pos.xyz;// / sun_pos.w;//light_pos[lightIndex].xyz;
|
||||
// float visibility = textureProj(t_directed_shadow_maps, sun_pos);
|
||||
// // float visibility = textureProj(t_directed_shadow_maps, vec4(fragPos.xy, /*lightIndex, */fragPos.z + bias, sun_pos.w));
|
||||
// return visibility;
|
||||
// // return mix(visibility, 0.0, sun_pos.z < -1.0);
|
||||
// // return mix(mix(0.0, 1.0, visibility == 1.0), 1.0, sign(sun_pos.w) * sun_pos.z > /*1.0*/abs(sun_pos.w));
|
||||
// // return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// /* if (visibility == 1.0) {
|
||||
// return 1.0;
|
||||
// } */
|
||||
// // return visibility;
|
||||
// /* if (fragPos.z > 1.0) {
|
||||
// return 1.0;
|
||||
// } */
|
||||
// // if (visibility <= 0.75) {
|
||||
// // return 0.0;
|
||||
// // }
|
||||
// // int samples = 20;
|
||||
// // float shadow = 0.0;
|
||||
// // // float bias = 0.0001;
|
||||
// // float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// // // float diskRadius = 0.2 * (1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// // float diskRadius = 0.0008;//0.005;// / (2.0 * view_distance.x);//(1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// // for(int i = 0; i < samples; ++i)
|
||||
// // {
|
||||
// // vec3 currentDepth = fragPos + vec3(sampleOffsetDirections[i].xyz) * diskRadius + bias;
|
||||
// // visibility = texture(t_directed_shadow_maps, vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// // shadow += mix(visibility, 1.0, visibility >= 0.5);
|
||||
// // }
|
||||
// // shadow /= float(samples);
|
||||
// // return shadow;
|
||||
//}
|
||||
// #elif (SHADOW_MODE == SHADOW_MODE_NONE || SHADOW_MODE == SHADOW_MODE_CHEAP)
|
||||
//float ShadowCalculationDirected(in vec4 light_pos[2], uint lightIndex)
|
||||
//{
|
||||
// return 1.0;
|
||||
//}
|
||||
// #endif
|
||||
//#else
|
||||
//float ShadowCalculationDirected(in vec4 light_pos[2], uint lightIndex)
|
||||
//{
|
||||
// return 1.0;
|
||||
//}
|
||||
//#endif
|
||||
|
48
assets/voxygen/shaders/light-shadows-directed-frag.glsl
Normal file
48
assets/voxygen/shaders/light-shadows-directed-frag.glsl
Normal file
@ -0,0 +1,48 @@
|
||||
// NOTE: We currently do nothing, and just rely on the default shader behavior.
|
||||
//
|
||||
// However, in the future we might apply some depth transforms here.
|
||||
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
// // Currently, we only need globals for the far plane.
|
||||
// #include <globals.glsl>
|
||||
// // Currently, we only need lights for the light position
|
||||
// #include <light.glsl>
|
||||
|
||||
// in vec3 FragPos; // FragPos from GS (output per emitvertex)
|
||||
// flat in int FragLayer;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Only need to do anything with point lights, since sun and moon should already have nonlinear
|
||||
// distance.
|
||||
/*if (FragLayer > 0) */{
|
||||
// get distance between fragment and light source
|
||||
// float lightDistance = length(FragPos - lights[FragLayer & 31].light_pos.xyz);
|
||||
|
||||
// // // map to [0;1] range by dividing by far_plane
|
||||
// lightDistance = lightDistance / screen_res.w;//FragPos.w;//screen_res.w;
|
||||
|
||||
// // // write this as modified depth
|
||||
// // // lightDistance = -1000.0 / (lightDistance + 10000.0);
|
||||
// // // lightDistance /= screen_res.w;
|
||||
// gl_FragDepth = lightDistance;// / /*FragPos.w;*/screen_res.w;//-1000.0 / (lightDistance + 1000.0);//lightDistance
|
||||
}
|
||||
}
|
63
assets/voxygen/shaders/light-shadows-directed-vert.glsl
Normal file
63
assets/voxygen/shaders/light-shadows-directed-vert.glsl
Normal file
@ -0,0 +1,63 @@
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// Currently, we only need globals for focus_off.
|
||||
#include <globals.glsl>
|
||||
// For shadow locals.
|
||||
#include <shadows.glsl>
|
||||
|
||||
/* Accurate packed shadow maps for many lights at once!
|
||||
*
|
||||
* Ideally, we would just write to a bitmask...
|
||||
*
|
||||
* */
|
||||
|
||||
in uint v_pos_norm;
|
||||
// in uint v_col_light;
|
||||
// in vec4 v_pos;
|
||||
|
||||
// Light projection matrices.
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
// out vec4 shadowMapCoord;
|
||||
|
||||
const int EXTRA_NEG_Z = 32768;
|
||||
|
||||
void main() {
|
||||
#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec3 f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
vec3 f_pos = f_chunk_pos + model_offs - focus_off.xyz;
|
||||
// f_pos = v_pos;
|
||||
// vec3 f_pos = f_chunk_pos + model_offs;
|
||||
|
||||
// gl_Position = v_pos + vec4(model_offs, 0.0);
|
||||
gl_Position = /*all_mat * */shadowMats[/*layer_face*/0].shadowMatrices * vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*//*uintBitsToFloat(v_pos_norm)*/1.0);
|
||||
// gl_Position.z = -gl_Position.z;
|
||||
// gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w));
|
||||
// shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex;
|
||||
// vec4(v_pos, 0.0, 1.0);
|
||||
#endif
|
||||
}
|
74
assets/voxygen/shaders/light-shadows-figure-vert.glsl
Normal file
74
assets/voxygen/shaders/light-shadows-figure-vert.glsl
Normal file
@ -0,0 +1,74 @@
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// Currently, we only need globals for focus_off.
|
||||
#include <globals.glsl>
|
||||
// For shadow locals.
|
||||
#include <shadows.glsl>
|
||||
|
||||
/* Accurate packed shadow maps for many lights at once!
|
||||
*
|
||||
* Ideally, we would just write to a bitmask...
|
||||
*
|
||||
* */
|
||||
|
||||
in uint v_pos_norm;
|
||||
in uint v_atlas_pos;
|
||||
// in uint v_col_light;
|
||||
// in vec4 v_pos;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
mat4 model_mat;
|
||||
vec4 model_col;
|
||||
ivec4 atlas_offs;
|
||||
vec3 model_pos;
|
||||
// bit 0 - is player
|
||||
// bit 1-31 - unused
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
mat4 normals_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_bones {
|
||||
// Warning: might not actually be 16 elements long. Don't index out of bounds!
|
||||
BoneData bones[16];
|
||||
};
|
||||
|
||||
// out vec4 shadowMapCoord;
|
||||
|
||||
void main() {
|
||||
#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
uint bone_idx = (v_pos_norm >> 27) & 0xFu;
|
||||
vec3 pos = (vec3((uvec3(v_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;
|
||||
|
||||
vec3 f_pos = (
|
||||
bones[bone_idx].bone_mat *
|
||||
vec4(pos, 1.0)
|
||||
).xyz + (model_pos - focus_off.xyz/* + vec3(0.0, 0.0, 0.0001)*/);
|
||||
|
||||
gl_Position = shadowMats[/*layer_face*/0].shadowMatrices * vec4(f_pos, 1.0);
|
||||
#endif
|
||||
}
|
49
assets/voxygen/shaders/light-shadows-frag.glsl
Normal file
49
assets/voxygen/shaders/light-shadows-frag.glsl
Normal file
@ -0,0 +1,49 @@
|
||||
// NOTE: We currently do nothing, and just rely on the default shader behavior.
|
||||
//
|
||||
// However, in the future we might apply some depth transforms here.
|
||||
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
// Currently, we only need globals for the far plane.
|
||||
#include <globals.glsl>
|
||||
// // Currently, we only need lights for the light position
|
||||
// #include <light.glsl>
|
||||
|
||||
// in vec3 FragPos; // FragPos from GS (output per emitvertex)
|
||||
// flat in int FragLayer;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Only need to do anything with point lights, since sun and moon should already have nonlinear
|
||||
// distance.
|
||||
///*if (FragLayer > 0) */{
|
||||
// // get distance between fragment and light source
|
||||
// float lightDistance = length(FragPos);
|
||||
// // float lightDistance = length(FragPos - lights[((/*FragLayer*/1 - 1) & 31)].light_pos.xyz);
|
||||
|
||||
// // // map to [0;1] range by dividing by far_plane
|
||||
// lightDistance = lightDistance / screen_res.w;//FragPos.w;//screen_res.w;
|
||||
|
||||
// // // write this as modified depth
|
||||
// // // lightDistance = -1000.0 / (lightDistance + 10000.0);
|
||||
// // // lightDistance /= screen_res.w;
|
||||
// gl_FragDepth = lightDistance;// / /*FragPos.w;*/screen_res.w;//-1000.0 / (lightDistance + 1000.0);//lightDistance
|
||||
//}
|
||||
}
|
277
assets/voxygen/shaders/light-shadows-geom.glsl
Normal file
277
assets/voxygen/shaders/light-shadows-geom.glsl
Normal file
@ -0,0 +1,277 @@
|
||||
// Adapted from https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows
|
||||
|
||||
// NOTE: We only technically need this for cube map arrays and geometry shader
|
||||
// instancing.
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// Currently, we only need globals for the max light count (light_shadow_count.x)
|
||||
// and the far plane (scene_res.z).
|
||||
#include <globals.glsl>
|
||||
#include <shadows.glsl>
|
||||
// // Currently, we only need lights for the light position
|
||||
// #include <light.glsl>
|
||||
|
||||
/* struct Light {
|
||||
vec4 light_pos;
|
||||
vec4 light_col;
|
||||
// mat4 light_proj;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_lights {
|
||||
Light lights[31];
|
||||
}; */
|
||||
|
||||
// Since our output primitive is a triangle strip, we have to render three vertices
|
||||
// each.
|
||||
#define VERTICES_PER_FACE 3
|
||||
|
||||
// Since we render our depth texture to a cube map, we need to render each face
|
||||
// six times. If we used other shadow mapping methods with fewer outputs, this would
|
||||
// shrink considerably.
|
||||
#define FACES_PER_POINT_LIGHT 6
|
||||
|
||||
// If MAX_VERTEX_UNIFORM_COMPONENTS_ARB = 512 on many platforms, and we want a mat4
|
||||
// for each of 6 directions for each light, 20 is close to the maximum allowable
|
||||
// size. We could add a final matrix for the directional light of the sun or moon
|
||||
// to bring us to 126 matrices, which is just 2 off.
|
||||
//
|
||||
// To improve this limit, we could do many things, such as:
|
||||
// - choose an implementation that isn't cube maps (e.g. tetrahedrons or curves;
|
||||
// if there were an easy way to sample from tetrahedrons, we'd be at 32 * 4 = 128
|
||||
// exactly, leaving no room for a solar body, though).
|
||||
// - Do more work in the geometry shader (e.g. just have a single projection
|
||||
// matrix per light, and derive the different-facing components; or there may be
|
||||
// other ways of greatly simplifying this). The tradeoff would be losing performance
|
||||
// here.
|
||||
// - Use ARB_instanced_arrays and switch lights with indexing, instead of a uniform
|
||||
// buffer. This would probably work fine (and ARB_instanced_arrays is supported on
|
||||
// pretty much every platform), but AFAIK it's possible that instanced arrays are
|
||||
// slower than uniform arraay access on many platforms.
|
||||
// - Don't try to do everything in one call (break this out into multiple passes).
|
||||
//
|
||||
// Actually, according to what I'm reading, MAX_GEOM_UNIFORM_COMPONENTS = 1024, and
|
||||
// gl_MaxGeometryUniformComponents = 1024.
|
||||
//
|
||||
// Also, this only applies to uniforms defined *outside* of uniform blocks, of which
|
||||
// there can be up to 12 (14 in OpenGL 4.3, which we definitely can't support).
|
||||
// GL_MAX_UNIFORM_BLOCK_SIZE has a minimum of 16384, which *easily* exceeds our usage
|
||||
// constraints. So this part might not matter.
|
||||
//
|
||||
// Other restrictions are easy to satisfy:
|
||||
//
|
||||
// gl_MaxGeometryVaryingComponents has a minimum of 64 and is the maximum number of
|
||||
// varying components; I think this is the number of out components per vertex, which
|
||||
// is technically 0, but would be 4 if we wrote FragPos. But it might also
|
||||
// be the *total* number of varying components, in which case if we wrote FragPos
|
||||
// it would be 4 * 20 * 6 * 3 = 1440, which would blow it out of the water. However,
|
||||
// I kind of doubt this interpretation because writing FragPos for each of 18 vertices,
|
||||
// as the original shader did, already yields 4 * 18 = 72, and it seems unlikely that
|
||||
// the original example exceeds OpenGL limits.
|
||||
//
|
||||
// gl_MaxGeometryOutputComponents has a minimum of 128 and is the maximum number of
|
||||
// components allowed in out variables; we easily fall under this since we actually
|
||||
// have 0 of these. However, if we were to write FragPos for each vertex, it *might*
|
||||
// cause us to exceed this limit, depending on whether it refers to the total output
|
||||
// component count *including* varying components, or not. See the previous
|
||||
// discussion; since 72 < 128 it's more plausible that this interpretation might be
|
||||
// correct, but hopefully it's not.
|
||||
//
|
||||
// gl_MaxGeometryInputComponents has a minimum of 64 and we easily fall under that
|
||||
// limit (I'm actually not sure we even have any user-defined input components?).
|
||||
//
|
||||
// gl_MaxGeometryTextureImageUnits = 16 and we have no texture image units (or maybe
|
||||
// 1, the one we bound?). This might come into play if we were to have attached
|
||||
// cubemaps instead of a single cubemap array, in which case it would limit us to
|
||||
// 16 lights *regardless* of any of the fixes mentioned above (i.e., we'd just have
|
||||
// to split up draw calls, I think).
|
||||
//
|
||||
// ---
|
||||
//
|
||||
// However, there is another limit to consider: GL_MAX_GEOMETRY_OUTPUT_VERTICES. Its
|
||||
// minimum is 256, and 20 * 6 * 3 = 360, which exceeds that. This introduces a new
|
||||
// limit of at most 14 point lights.
|
||||
//
|
||||
// Another, related limit is GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS. This counts
|
||||
// every component output ("component" is usually a 4-byte field of a vector, but maybe
|
||||
// this would improve with something like half-floats?), and has a minimum (as of
|
||||
// OpenGL 3.3) of 1024. Since even builtin outputs gl_Layer count against this total,
|
||||
// this means we issue 5 components per vertex, and 14 * 6 * 3 * 5 = 1260 > 1024.
|
||||
//
|
||||
// Ultimately, we find our maximum output limit of 11, ≤ 1024/5/3/6.
|
||||
//
|
||||
// If we choose to reserve a slot for a non-point light (and/or other uniforms), it
|
||||
// is just 10, or half what we got from VERTICES_PER_FACE (we could also round down to
|
||||
// 8 as a power of 2, if we had to).
|
||||
//
|
||||
// Unlike the input limits, whwich we can get around with "clever" solutions, it seems
|
||||
// likely that the only real way to defeat the vertex limits is to use instancing of
|
||||
// some sort (be it geometry shader or otherwise). This would restrict us to OpenGL
|
||||
// 4.0 or above.
|
||||
//
|
||||
// A further consideration (were we to switch to OpenGL 4.1-supported features, but
|
||||
// actually it is often supported on 3.3 hardware with ARB_viewport_array--whereas
|
||||
// geometry shader instancing is *not* supported on any 3.3 hardware, so would actually
|
||||
// require us to upgrade) would be setting gl_ViewportIndex. The main reason to consider
|
||||
// this is that it allows specifying a separate scissor rectangle per viewport. This
|
||||
// introduces two new constraints. Firstly, it adds an extra component to each vertex
|
||||
// (lowering our maximum to 9 faces per light ≤ 1024/6/3/6, or 8 if we want to support a
|
||||
// directional light).
|
||||
//
|
||||
// Secondly, a new constant (MAX_VIEWPORTS) is introduced, which would restrict the
|
||||
// total number of active viewports; the minimum value for this is 16. While this may
|
||||
// not seem all that relevant since our current hard limit is 11, the difference is that
|
||||
// this limit would apply *across* instanced calls (since it may be a "global"
|
||||
// restriction, tied to the OpenGL context; this means it couldn't even be a multiple
|
||||
// frame buffer thing, as there is usually one per window). This would also tie in
|
||||
// with gl_MaxGeometryTextureImageUnits, I guess.
|
||||
//
|
||||
// --
|
||||
//
|
||||
// I just realized tht using cube map arrays at all bumps our required OpenGL
|
||||
// version to 4.0, so let's just do instancing...
|
||||
//
|
||||
// The instancing limit on MAX_GEOMETRY_SHADER_INVOCATIONS has a minimum of 32, which
|
||||
// would be sufficient to run through all 32 lights with a different cube map and
|
||||
// completely removes any imits on ight count.
|
||||
//
|
||||
// This should instantly bring us below all relevant limits in all cases considered
|
||||
// except for the two that would require 16. Unfortunately, 32 is also the *maximum*
|
||||
// number of point lights, which is much higher than the usual value, and the instance
|
||||
// count has to be a constant. If we were to instead geometry-shader-instance each
|
||||
// *face*, we'd get a maximum light count of 56 ≤ 1024/6/3, which is not as elegant
|
||||
// but is easily higher than 32. So, let's try using that instead.
|
||||
//
|
||||
// It is *possible* that using instancing on the *vertex* shader with the (dynamically
|
||||
// uniform) total number of instances set to the actual number of point lights, would
|
||||
// improve performance, since it would give us a 1:1 vertex input:output ratio, which
|
||||
// might be optimized in hardware.
|
||||
//
|
||||
// It also seems plausible that constructing a separate geometry shader with values
|
||||
// from 1 to 32 would be worthwhile, but that seems a little extreme.
|
||||
//
|
||||
// ---
|
||||
//
|
||||
// Since wgpu doesn't support geometry shaders anyway, it seems likely that we'll have
|
||||
// to do the multiple draw calls, anyway... I don't think gl_Layer can be set from
|
||||
// outside a geometry shader. But in wgpu, such a thing is much cheaper, anyway.
|
||||
#define MAX_POINT_LIGHTS 31
|
||||
|
||||
// We use geometry shader instancing to construct each face separately.
|
||||
#define MAX_LAYER_VERTICES_PER_FACE (MAX_POINT_LIGHTS * VERTICES_PER_FACE)
|
||||
|
||||
#define MAX_LAYER_FACES (MAX_POINT_LIGHTS * FACES_PER_POINT_LIGHT)
|
||||
|
||||
layout (triangles/*, invocations = 6*/) in;
|
||||
|
||||
layout (triangle_strip, max_vertices = /*MAX_LAYER_VERTICES_PER_FACE*//*96*/18) out;
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
// NOTE: We choose not to output FragPos currently to save on space limitations
|
||||
// (see extensive documentation above). However, as these limitations have been
|
||||
// relaxed (unless the total of all our varying output components can't exceed
|
||||
// 128, which would mean FragPos would sum to 4 * 3 * 32 = 384; this could be
|
||||
// remedied only by setting MAX_POINT_LIGHTS to ), we might enable it again soon.
|
||||
//
|
||||
// out vec3 FragPos; // FragPos from GS (output per emitvertex)
|
||||
// flat out int FragLayer; // Current layer
|
||||
|
||||
// const vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
|
||||
void main() {
|
||||
// return;
|
||||
// NOTE: Assuming that light_shadow_count.x < MAX_POINT_LIGHTS. We could min
|
||||
// it, but that might make this less optimized, and I'd like to keep this loop as
|
||||
// optimized as is reasonably possible.
|
||||
// int face = gl_InvocationID;
|
||||
|
||||
// Part 1: emit directed lights.
|
||||
/* if (face <= light_shadow_count.z) {
|
||||
// Directed light.
|
||||
for(int i = 0; i < VERTICES_PER_FACE; ++i) // for each triangle vertex
|
||||
{
|
||||
// NOTE: See above, we don't make FragPos a uniform.
|
||||
FragPos = gl_in[i].gl_Position;
|
||||
FragLayer = 0; // 0 is the directed light layer.
|
||||
// vec4 FragPos = gl_in[i].gl_Position;
|
||||
gl_Layer = i; // built-in variable that specifies to which face we render.
|
||||
gl_Position = shadowMats[i].shadowMatrices * FragPos;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
} */
|
||||
|
||||
// Part 2: emit point lights.
|
||||
/* if (light_shadow_count.x == 1) {
|
||||
return;
|
||||
} */
|
||||
#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
for (uint layer = 1u; layer <= min(light_shadow_count.x, 1u); ++layer)
|
||||
{
|
||||
int layer_base = int(layer) * FACES_PER_POINT_LIGHT;
|
||||
// We use instancing here in order to increase the number of emitted vertices.
|
||||
// int face = gl_InvocationID;
|
||||
for(int face = 0; face < FACES_PER_POINT_LIGHT; ++face)
|
||||
{
|
||||
// int layer_face = layer * FACES_PER_POINT_LIGHT + face;
|
||||
// int layer_face = layer * FACES_PER_POINT_LIGHT + face;
|
||||
// for(int i = VERTICES_PER_FACE - 1; i >= 0; --i) // for each triangle vertex
|
||||
for(int i = 0; i < VERTICES_PER_FACE; ++i) // for each triangle vertex
|
||||
{
|
||||
// NOTE: See above, we don't make FragPos a uniform.
|
||||
vec3 fragPos = gl_in[i].gl_Position.xyz;
|
||||
// FragPos = fragPos - (lights[((/*FragLayer*/layer - 1u) & 31u)].light_pos.xyz - focus_off.xyz);
|
||||
// FragLayer = layer;
|
||||
// float lightDistance = length(FragPos - lights[((layer - 1) & 31)].light_pos.xyz);
|
||||
// lightDistance /= screen_res.w;
|
||||
|
||||
// vec4 FragPos = gl_in[i].gl_Position;
|
||||
// NOTE: Our normals map to the same thing as cube map normals, *except* that their normal direction is
|
||||
// swapped; we can fix this by doing normal ^ 0x1u. However, we also want to cull back faces, not front
|
||||
// faces, so we only care about the shadow cast by the *back* of the triangle, which means we ^ 0x1u
|
||||
// again and cancel it out.
|
||||
// int face = int(((floatBitsToUint(gl_Position.w) >> 29) & 0x7u) ^ 0x1u);
|
||||
int layer_face = layer_base + face;
|
||||
gl_Layer = face;//layer_face; // built-in variable that specifies to which face we render.
|
||||
gl_Position = shadowMats[layer_face].shadowMatrices * vec4(fragPos, 1.0);
|
||||
// gl_Position.z = -((gl_Position.z + screen_res.z) / (screen_res.w - screen_res.z)) * lightDistance;
|
||||
// gl_Position.z = gl_Position.z / screen_res.w;
|
||||
// gl_Position.z = gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
// lightDistance = -(lightDistance + screen_res.z) / (screen_res.w - screen_res.z);
|
||||
// gl_Position.z = lightDistance;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
55
assets/voxygen/shaders/light-shadows-vert.glsl
Normal file
55
assets/voxygen/shaders/light-shadows-vert.glsl
Normal file
@ -0,0 +1,55 @@
|
||||
#version 330 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
// Currently, we only need globals for focus_off.
|
||||
#include <globals.glsl>
|
||||
|
||||
/* Accurate packed shadow maps for many lights at once!
|
||||
*
|
||||
* Ideally, we would just write to a bitmask...
|
||||
*
|
||||
* */
|
||||
|
||||
in uint v_pos_norm;
|
||||
// in uint v_col_light;
|
||||
// in vec4 v_pos;
|
||||
|
||||
// Light projection matrices.
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
// out vec4 shadowMapCoord;
|
||||
|
||||
const int EXTRA_NEG_Z = 32768;
|
||||
|
||||
void main() {
|
||||
vec3 f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
vec3 f_pos = f_chunk_pos + model_offs - focus_off.xyz;
|
||||
// f_pos = v_pos;
|
||||
// vec3 f_pos = f_chunk_pos + model_offs;
|
||||
|
||||
// gl_Position = v_pos + vec4(model_offs, 0.0);
|
||||
gl_Position = /*all_mat * */vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*//*uintBitsToFloat(v_pos_norm)*/1.0);
|
||||
// shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex;
|
||||
// vec4(v_pos, 0.0, 1.0);
|
||||
}
|
632
assets/voxygen/shaders/lod-terrain-frag.glsl
Normal file
632
assets/voxygen/shaders/lod-terrain-frag.glsl
Normal file
@ -0,0 +1,632 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
// #define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_VOXEL
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_LOD_FULL_INFO
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <sky.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_norm;
|
||||
// in vec2 v_pos_orig;
|
||||
// in vec4 f_shadow;
|
||||
// in vec4 f_square;
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
/// const vec4 sun_pos = vec4(0);
|
||||
// const vec4 light_pos[2] = vec4[](vec4(0), vec4(0)/*, vec3(00), vec3(0), vec3(0), vec3(0)*/);
|
||||
|
||||
#include <sky.glsl>
|
||||
|
||||
void main() {
|
||||
// tgt_color = vec4(vec3(1.0), 1.0);
|
||||
// return;
|
||||
// vec3 f_pos = lod_pos(f_pos.xy);
|
||||
// vec3 f_col = lod_col(f_pos.xy);
|
||||
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
|
||||
float my_alt = /*f_pos.z;*/alt_at_real(f_pos.xy);
|
||||
// vec3 f_pos = vec3(f_pos.xy, max(my_alt, f_pos.z));
|
||||
/* gl_Position =
|
||||
proj_mat *
|
||||
view_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0); */
|
||||
vec3 my_pos = vec3(f_pos.xy, my_alt);
|
||||
vec3 my_norm = lod_norm(f_pos.xy/*, f_square*/);
|
||||
|
||||
float which_norm = dot(my_norm, normalize(cam_pos.xyz - my_pos));
|
||||
// which_norm = 0.5 + which_norm * 0.5;
|
||||
|
||||
// which_norm = pow(max(0.0, which_norm), /*0.03125*/1 / 8.0);// * 0.5;
|
||||
// smoothstep
|
||||
which_norm = which_norm * which_norm * (3 - 2 * abs(which_norm));
|
||||
|
||||
// which_norm = mix(0.0, 1.0, which_norm > 0.0);
|
||||
// vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
vec3 f_norm = mix(faceforward(f_norm, cam_pos.xyz - f_pos, -f_norm), my_norm, which_norm);
|
||||
vec3 f_pos = mix(f_pos, my_pos, which_norm);
|
||||
// vec3 fract_pos = fract(f_pos);
|
||||
/* if (length(f_pos - cam_pos.xyz) <= view_distance.x + 32.0) {
|
||||
vec4 new_f_pos;
|
||||
float depth = 10000000.0;
|
||||
vec4 old_coord = all_mat * vec4(f_pos.xyz, 1.0);
|
||||
for (int i = 0; i < 6; i ++) {
|
||||
// vec4 square = focus_pos.xy + vec4(splay(pos - vec2(1.0, 1.0), splay(pos + vec2(1.0, 1.0))));
|
||||
vec3 my_f_norm = normals[i];
|
||||
vec3 my_f_tan = normals[(i + 2) % 6];
|
||||
vec3 my_f_bitan = normals[(i + 4) % 6];
|
||||
mat4 foo = mat4(vec4(my_f_tan, 0), vec4(my_f_bitan, 0), vec4(my_f_norm, 0), vec4(0, 0, 0, 1));
|
||||
mat4 invfoo = foo * inverse(foo * all_mat);
|
||||
vec4 my_f_pos = invfoo * (old_coord);//vec4(f_pos, 1.0);
|
||||
vec4 my_f_proj = all_mat * my_f_pos;
|
||||
if (my_f_proj.z <= depth) {
|
||||
new_f_pos = my_f_pos;
|
||||
f_norm = my_f_norm;
|
||||
depth = my_f_proj.z;
|
||||
}
|
||||
}
|
||||
// f_pos = new_f_pos.xyz;
|
||||
} */
|
||||
|
||||
// Test for distance to all 6 sides of the enclosing cube.
|
||||
// if (/*any(lessThan(fract(f_pos.xy), 0.01))*/fract_pos.x <= 0.1) {
|
||||
// f_norm = faceforward(vec3(-1, 0, 0), f_norm, vec3(1, 0, 0));
|
||||
// f_tan = vec3(0, 1, 0);
|
||||
// } else if (fract_pos.y <= 0.1) {
|
||||
// f_norm = faceforward(vec3(0, -1, 0), f_norm, vec3(0, 1, 0));
|
||||
// f_tan = vec3(0, 0, 1);
|
||||
// } else {
|
||||
// f_norm = faceforward(vec3(0, 0, -1), f_norm, vec3(0, 0, 1));
|
||||
// f_tan = vec3(1, 0, 0);
|
||||
// }
|
||||
// vec3 f_bitan = cross(f_norm, f_tan);
|
||||
|
||||
// mat4 foo = mat4(vec4(f_tan, 0), vec4(f_bitan, 0), vec4(f_norm, 0), vec4(0, 0, 0, 1));
|
||||
// mat4 invfoo = foo * inverse(foo * all_mat);
|
||||
// vec3 old_coord = all_mat * vec4(f_pos.xyz, 1.0);
|
||||
// vec4 new_f_pos = invfoo * (old_coord);//vec4(f_pos, 1.0);
|
||||
vec3 f_col = lod_col(f_pos.xy);
|
||||
// tgt_color = vec4(f_col, 1.0);
|
||||
// return;
|
||||
// vec3 f_col = srgb_to_linear(vec3(1.0));
|
||||
// vec3 f_norm = faceforward(f_norm, cam_pos.xyz - f_pos, -f_norm);
|
||||
// vec3 f_up = faceforward(cam_pos.xyz - f_pos, vec3(0.0, 0.0, -1.0), cam_pos.xyz - f_pos);
|
||||
// vec3 f_norm = faceforward(f_norm, /*vec3(cam_pos.xyz - f_pos.xyz)*/vec3(0.0, 0.0, -1.0), f_norm);
|
||||
|
||||
// const vec3 normals[3] = vec3[](vec3(1,0,0), vec3(0,1,0), vec3(0,0,1));//, vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1));
|
||||
// const mat3 side_norms = vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1);
|
||||
// mat3 sides = mat3(
|
||||
// /*vec3(1, 0, 0),
|
||||
// vec3(0, 1, 0),
|
||||
// vec3(0, 0, 1)*/
|
||||
// vec3(1, 0, 0),
|
||||
// // faceforward(vec3(1, 0, 0), -f_norm, vec3(1, 0, 0)),
|
||||
// vec3(0, 1, 0),
|
||||
// // faceforward(vec3(0, 1, 0), -f_norm, vec3(0, 1, 0)),
|
||||
// vec3(0, 0, 1)
|
||||
// // faceforward(vec3(0, 0, 1), -f_norm, vec3(0, 0, 1))
|
||||
// );
|
||||
|
||||
// This vector is shorthand for a diagonal matrix, which works because:
|
||||
// (1) our voxel normal vectors are exactly the basis vectors in worldspace;
|
||||
// (2) only 3 of them can be in the direction of the actual normal anyway.
|
||||
// (NOTE: This normal should always be pointing up, so implicitly sides.z = 1.0).
|
||||
// vec3 sides = sign(f_norm);
|
||||
// // NOTE: Should really be sides * f_norm, i.e. abs(f_norm), but voxel_norm would then re-multiply by sides so it cancels out.
|
||||
// vec3 cos_sides_i = sides * f_norm;
|
||||
// vec3 cos_sides_o = sides * view_dir;
|
||||
// // vec3 side_factor_i = cos_sides_i;
|
||||
// // vec3 side_factor_i = f_norm;
|
||||
// // vec3 side_factor_i = cos_sides_o;
|
||||
// vec3 side_factor_i = 1.0 - pow(1.0 - 0.5 * cos_sides_i, vec3(5));
|
||||
// // vec3 side_factor_i = /*abs*/sign(f_norm) * cos_sides_i;//max(cos_sides_i, 0.0);// 1.0 - pow(1.0 - 0.5 * cos_sides_i, vec3(5.0)); // max(sides * f_norm, vec3(0.0));//
|
||||
// // vec3 side_factor_i = /*abs*/sign(f_norm) * cos_sides_i;//max(cos_sides_i, 0.0);// 1.0 - pow(1.0 - 0.5 * cos_sides_i, vec3(5.0)); // max(sides * f_norm, vec3(0.0));//
|
||||
// // vec3 side_factor_o = max(cos_sides_o, 0.0);// 1.0 - pow(1.0 - 0.5 * max(cos_sides_o, 0.0), vec3(5));
|
||||
// vec3 side_factor_o = 1.0 - pow(1.0 - 0.5 * max(cos_sides_o, 0.0), vec3(5));
|
||||
// // vec3 side_factor_o = max(cos_sides_o, 0.0);// 1.0 - pow(1.0 - 0.5 * max(cos_sides_o, vec3(0.0)), vec3(5.0));//max(sides * view_dir/* * sign(cos_sides_i) */, vec3(0.0));
|
||||
// // vec3 side_factor_o = max(sides * view_dir/* * cos_sides_o*/, 0.0);// 1.0 - pow(1.0 - 0.5 * max(cos_sides_o, vec3(0.0)), vec3(5.0));//max(sides * view_dir/* * sign(cos_sides_i) */, vec3(0.0));
|
||||
// // NOTE: side = transpose(sides), so we avoid the extra operatin.
|
||||
// // We multply the vector by the matrix from the *left*, so each normal gets multiplied by the corresponding factor.
|
||||
// // vec3 voxel_norm = normalize(/*sides * *//*sqrt(1.0 - cos_sides_i * cos_sides_i)*/(side_factor_i * side_factor_o));
|
||||
// vec3 voxel_norm = normalize(/*sides * *//*sqrt(1.0 - cos_sides_i * cos_sides_i)*/((28.0 / (23.0 * PI)) * side_factor_i * side_factor_o * sides));
|
||||
// vec3 voxel_norm = normalize(sign(f_norm) * sqrt(abs(f_norm)) * max(sign(f_norm) * view_dir, 0.0));
|
||||
float f_ao = 1.0;//1.0;//sqrt(dot(cos_sides_i, cos_sides_i) / 3.0);
|
||||
// float f_ao = 0.2;
|
||||
// sqrt(dot(sqrt(1.0 - cos_sides_i * cos_sides_i)), 1.0 - cos_sides_o/* * cos_sides_o*/);// length(sqrt(1.0 - cos_sides_o * cos_sides_o) / cos_sides_i * cos_sides_o);
|
||||
// f_ao = f_ao * f_ao;
|
||||
|
||||
// /* vec3 voxel_norm = vec3(0.0);
|
||||
// for (int i = 0; i < 3; i ++) {
|
||||
// // Light reflecting off the half-angle can shine on up to three sides.
|
||||
// // So, the idea here is to figure out the ratio of visibility of each of these
|
||||
// // three sides such that their sum adds to 1, then computing a Beckmann Distribution for each side times
|
||||
// // the this ratio.
|
||||
// //
|
||||
// // The ratio of these normals in each direction should be the sum of their cosines with the light over π,
|
||||
// // I think.
|
||||
// //
|
||||
// // cos (wh, theta)
|
||||
// //
|
||||
// // - one normal
|
||||
// //
|
||||
// // The ratio of each of the three exposed sides should just be the slope.
|
||||
// vec3 side = normals[i];
|
||||
// side = faceforward(side, -f_norm, side);
|
||||
// float cos_wi = max(dot(f_norm, side), 0.0);
|
||||
// float cos_wo = max(dot(view_dir, side), 0.0);
|
||||
// float share = cos_wi * cos_wo;
|
||||
// // float share = (1.0 - pow5(1.0 - 0.5 * cos_wi)) * (1.0 - pow5(1.0 - 0.5 * cos_wo));
|
||||
// voxel_norm += share * side;
|
||||
// // voxel_norm += normals[i] * side_visible * max(dot(-cam_dir, normals[i]), 0.0);
|
||||
// // voxel_norm += normals[i] * side_visible * max(dot(-cam_dir, normals[i]), 0.0);
|
||||
// }
|
||||
// voxel_norm = normalize(voxel_norm); */
|
||||
|
||||
float dist_lerp = 0.0;//clamp(pow(max(distance(focus_pos.xy, f_pos.xy) - view_distance.x, 0.0) / 4096.0, 2.0), 0, 1);
|
||||
// dist_lerp = 0.0;
|
||||
// voxel_norm = normalize(mix(voxel_norm, f_norm, /*pow(dist_lerp, 1.0)*/dist_lerp));
|
||||
|
||||
// IDEA:
|
||||
// We can represent three faces as sign(voxel_norm).
|
||||
vec3 sides = sign(f_norm);
|
||||
// There are three relevant vectors: normal, tangent, and bitangent.
|
||||
// We say normal is the z component, tangent the x component, bitangent the y.
|
||||
// A blocking side is in the reverse direction of each.
|
||||
// So -sides is the *direction* of the next block.
|
||||
// Now, we want to multiply this by the *distance* to the nearest integer in that direction.
|
||||
// If sides.x is -1, the direction is 1, so the distance is 1.0 - fract(f_pos.x) and the delta is 1.0 - fract(f_pos.x).
|
||||
// If sides.x is 1, the direction is -1, so the distance is fract(f_pos.x) and the delta is -fract(f_pos.x) = 1.0 + fract(-f_pos.x).
|
||||
// If sides.x is 0, the direction is 0, so the distance is 0.0 and the delta is 0.0 = 0.0 + fract(0.0 * f_pos.x).
|
||||
// (we ignore f_pos < 0 for the time being).
|
||||
// Then this is 1.0 + sides.x * fract(-sides.x * f_pos.x);
|
||||
// We repeat this for y.
|
||||
//
|
||||
// We treat z as the dependent variable.
|
||||
// IF voxel_norm.x > 0.0, z should increase by voxel_norm.z / voxel_norm.x * delta_sides.x in the x direction;
|
||||
// IF voxel_norm.y > 0.0, z should increase by voxel_norm.z / voxel_norm.y * delta_sides.y in the y direction;
|
||||
// IF voxel_norm.x = 0.0, z should not increase in the x direction;
|
||||
// IF voxel_norm.y = 0.0, z should not increase in the y direction;
|
||||
// we assume that ¬(voxel_norm.z = 0).
|
||||
//
|
||||
// Now observe that we can rephrase this as saying, given a desired change in z (to get to the next integer), how far must
|
||||
// we travel along x and y?
|
||||
//
|
||||
// TODO: Handle negative numbers.
|
||||
// vec3 delta_sides = mix(-fract(f_pos), 1.0 - fract(f_pos), lessThan(sides, vec3(0.0)));
|
||||
vec3 delta_sides = mix(fract(f_pos) - 1.0, fract(f_pos), lessThan(sides, vec3(0.0)));
|
||||
/* vec3 delta_sides =
|
||||
mix(
|
||||
mix(-fract(f_pos), 1.0 - fract(f_pos), lessThan(sides, vec3(0.0))),
|
||||
mix(-(f_pos - ceil(f_pos)), 1.0 - (f_pos - ceil(f_pos)), lessThan(sides, vec3(0.0))),
|
||||
lessThan(f_pos, vec3(0.0))
|
||||
); */
|
||||
/* vec3 delta_sides =
|
||||
mix(
|
||||
mix(1.0 - fract(f_pos), -fract(f_pos), lessThan(sides, vec3(0.0))),
|
||||
mix(1.0 - (f_pos - ceil(f_pos)), -(f_pos - ceil(f_pos)), lessThan(sides, vec3(0.0))),
|
||||
lessThan(f_pos, vec3(0.0))
|
||||
); */
|
||||
// vec3 delta_sides = mix(1.0 - fract(f_pos), -fract(f_pos), lessThan(sides, vec3(0.0)));
|
||||
// vec3 delta_sides = 1.0 + sides * fract(-sides * f_pos);
|
||||
// delta_sides = -sign(delta_sides) * (1.0 - abs(delta_sides));
|
||||
// Three faces: xy, xz, and yz.
|
||||
// TODO: Handle zero slopes (for xz and yz).
|
||||
vec2 corner_xy = min(abs(f_norm.xy / f_norm.z * delta_sides.z), 1.0);
|
||||
vec2 corner_yz = min(abs(f_norm.yz / f_norm.x * delta_sides.x), 1.0);
|
||||
vec2 corner_xz = min(abs(f_norm.xz / f_norm.y * delta_sides.y), 1.0);
|
||||
// vec3 corner_delta = vec3(voxel_norm.xy / voxel_norm.z * delta_sides.z, delta_sides.z);
|
||||
// Now we just compute an (upper bounded) distance to the corner in each direction.
|
||||
// vec3 corner_distance = min(abs(corner_delta), 1.0);
|
||||
// Now, if both sides hit something, lerp to 0.25. If one side hits something, lerp to 0.75. And if no sides hit something,
|
||||
// lerp to 1.0 (TODO: incorporate the corner properly).
|
||||
// Bilinear interpolation on each plane:
|
||||
float ao_xy = dot(vec2(corner_xy.x, 1.0 - corner_xy.x), mat2(vec2(corner_xy.x < 1.00 ? corner_xy.y < 1.00 ? 0.25 : 0.5 : corner_xy.y < 1.00 ? 0.5 : 0.75, corner_xy.x < 1.00 ? 0.75 : 1.00), vec2(corner_xy.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(corner_xy.y, 1.0 - corner_xy.y));
|
||||
float ao_yz = dot(vec2(corner_yz.x, 1.0 - corner_yz.x), mat2(vec2(corner_yz.x < 1.00 ? corner_yz.y < 1.00 ? 0.25 : 0.5 : corner_yz.y < 1.00 ? 0.5 : 0.75, corner_yz.x < 1.00 ? 0.75 : 1.00), vec2(corner_yz.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(corner_yz.y, 1.0 - corner_yz.y));
|
||||
float ao_xz = dot(vec2(corner_xz.x, 1.0 - corner_xz.x), mat2(vec2(corner_xz.x < 1.00 ? corner_xz.y < 1.00 ? 0.25 : 0.5 : corner_xz.y < 1.00 ? 0.5 : 0.75, corner_xz.x < 1.00 ? 0.75 : 1.00), vec2(corner_xz.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(corner_xz.y, 1.0 - corner_xz.y));
|
||||
/* float ao_xy = dot(vec2(1.0 - corner_xy.x, corner_xy.x), mat2(vec2(corner_xy.x < 1.00 ? corner_xy.y < 1.00 ? 0.25 : 0.5 : corner_xy.y < 1.00 ? 0.5 : 0.75, corner_xy.x < 1.00 ? 0.75 : 1.00), vec2(corner_xy.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(1.0 - corner_xy.y, corner_xy.y));
|
||||
float ao_yz = dot(vec2(1.0 - corner_yz.x, corner_yz.x), mat2(vec2(corner_yz.x < 1.00 ? corner_yz.y < 1.00 ? 0.25 : 0.5 : corner_yz.y < 1.00 ? 0.5 : 0.75, corner_yz.x < 1.00 ? 0.75 : 1.00), vec2(corner_yz.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(1.0 - corner_yz.y, corner_yz.y));
|
||||
float ao_xz = dot(vec2(1.0 - corner_xz.x, corner_xz.x), mat2(vec2(corner_xz.x < 1.00 ? corner_xz.y < 1.00 ? 0.25 : 0.5 : corner_xz.y < 1.00 ? 0.5 : 0.75, corner_xz.x < 1.00 ? 0.75 : 1.00), vec2(corner_xz.y < 1.00 ? 0.75 : 1.0, 1.0)) * vec2(1.0 - corner_xz.y, corner_xz.y)); */
|
||||
// Now, if both sides hit something, lerp to 0.0. If one side hits something, lerp to 0.4. And if no sides hit something,
|
||||
// lerp to 1.0.
|
||||
// Bilinear interpolation on each plane:
|
||||
// float ao_xy = dot(vec2(1.0 - corner_xy.x, corner_xy.x), mat2(vec2(corner_xy.x < 1.00 ? corner_xy.y < 1.00 ? 0.0 : 0.25 : corner_xy.y < 1.00 ? 0.25 : 1.0, corner_xy.x < 1.00 ? 0.25 : 1.0), vec2(corner_xy.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_xy.y, corner_xy.y));
|
||||
// float ao_yz = dot(vec2(1.0 - corner_yz.x, corner_yz.x), mat2(vec2(corner_yz.x < 1.00 ? corner_yz.y < 1.00 ? 0.0 : 0.25 : corner_yz.y < 1.00 ? 0.25 : 1.0, corner_yz.x < 1.00 ? 0.25 : 1.0), vec2(corner_yz.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_yz.y, corner_yz.y));
|
||||
// float ao_xz = dot(vec2(1.0 - corner_xz.x, corner_xz.x), mat2(vec2(corner_xz.x < 1.00 ? corner_xz.y < 1.00 ? 0.0 : 0.25 : corner_xz.y < 1.00 ? 0.25 : 1.0, corner_xz.x < 1.00 ? 0.25 : 1.0), vec2(corner_xz.y < 1.00 ? 0.25 : 1.0, 1.0)) * vec2(1.0 - corner_xz.y, corner_xz.y));
|
||||
// Now, multiply each component by the face "share" which is just the absolute value of its normal for that plane...
|
||||
// vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(f_norm.yz == vec2(0.0), f_norm.xz == vec2(0.0), f_norm.xy == vec2(0.0)));
|
||||
// vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(length(f_norm.yz) <= 0.0, length(f_norm.xz) <= 0.0, length(f_norm.xy) <= 0.0));
|
||||
// vec3 f_ao_vec = mix(abs(vec3(ao_yz, ao_xz, ao_xy)), vec3(1.0), bvec3(abs(f_norm.x) <= 0.0, abs(f_norm.y) <= 0.0, abs(f_norm.z) <= 0.0));
|
||||
vec3 f_ao_vec = mix(/*abs(voxel_norm)*/vec3(1.0, 1.0, 1.0), /*abs(voxel_norm) * */vec3(ao_yz, ao_xz, ao_xy), /*abs(voxel_norm)*/vec3(length(f_norm.yz), length(f_norm.xz), length(f_norm.xy))/*vec3(1.0)*//*sign(max(view_dir * sides, 0.0))*/);
|
||||
float f_orig_len = length(cam_pos.xyz - f_pos);
|
||||
vec3 f_orig_view_dir = normalize(cam_pos.xyz - f_pos);
|
||||
// f_ao_vec *= sign(max(f_orig_view_dir * sides, 0.0));
|
||||
// Projecting view onto face:
|
||||
// bool IntersectRayPlane(vec3 rayOrigin, vec3 rayDirection, vec3 posOnPlane, vec3 planeNormal, inout vec3 intersectionPoint)
|
||||
// {
|
||||
// float rDotn = dot(rayDirection, planeNormal);
|
||||
//
|
||||
// //parallel to plane or pointing away from plane?
|
||||
// if (rDotn < 0.0000001 )
|
||||
// return false;
|
||||
//
|
||||
// float s = dot(planeNormal, (posOnPlane - rayOrigin)) / rDotn;
|
||||
//
|
||||
// intersectionPoint = rayOrigin + s * rayDirection;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
bvec3 hit_yz_xz_xy;
|
||||
vec3 dist_yz_xz_xy;
|
||||
/* {
|
||||
// vec3 rDotn = -f_orig_view_dir * -sides;
|
||||
// vec3 rDotn = f_orig_view_dir * sides;
|
||||
// hit_yz_xz_xy = greaterThanEqual(rDotn, vec3(0.000001));
|
||||
// vec3 s = -sides * (f_pos + delta_sides - cam_pos.xyz) / rDotn;
|
||||
// dist_yz_xz_xy = abs(s * -f_orig_view_dir);
|
||||
// vec3 s = -sides * (f_pos + delta_sides - cam_pos.xyz) / (-f_orig_view_dir * -sides);
|
||||
// vec3 s = (f_pos + delta_sides - cam_pos.xyz) / -f_orig_view_dir;
|
||||
// dist_yz_xz_xy = abs(s);
|
||||
hit_yz_xz_xy = greaterThanEqual(f_orig_view_dir * sides, vec3(0.000001));
|
||||
dist_yz_xz_xy = abs((f_pos + delta_sides - cam_pos.xyz) / -f_orig_view_dir);
|
||||
} */
|
||||
{
|
||||
// vec3 rDotn = -f_orig_view_dir * -sides;
|
||||
// vec3 rDotn = f_orig_view_dir * sides;
|
||||
// hit_yz_xz_xy = greaterThanEqual(rDotn, vec3(0.000001));
|
||||
// vec3 s = -sides * (f_pos + delta_sides - cam_pos.xyz) / rDotn;
|
||||
// dist_yz_xz_xy = abs(s * -f_orig_view_dir);
|
||||
// vec3 s = -sides * (f_pos + delta_sides - cam_pos.xyz) / (-f_orig_view_dir * -sides);
|
||||
// vec3 s = (f_pos + delta_sides - cam_pos.xyz) / -f_orig_view_dir;
|
||||
// dist_yz_xz_xy = abs(s);
|
||||
hit_yz_xz_xy = greaterThanEqual(f_orig_view_dir * sides, vec3(0.000001));
|
||||
dist_yz_xz_xy = abs((f_pos + delta_sides - cam_pos.xyz) / f_orig_view_dir);
|
||||
}
|
||||
|
||||
// vec3 xy_point = f_pos, xz_point = f_pos, yz_point = f_pos;
|
||||
// bool hit_xy = (/*ao_yz < 1.0 || ao_xz < 1.0*//*min(f_ao_vec.x, f_ao_vec.y)*//*f_ao_vec.z < 1.0*/true/*min(corner_xz.y, corner_yz.y) < 1.0*//*min(corner_xy.x, corner_xy.y) < 1.0*/) && IntersectRayPlane(cam_pos.xyz, -f_orig_view_dir, vec3(f_pos.x, f_pos.y, f_pos.z + delta_sides.z/* - sides.z*/), vec3(0.0, 0.0, -sides.z), xy_point);
|
||||
// bool hit_xz = (/*ao_xy < 1.0 || ao_yz < 1.0*//*min(f_ao_vec.x, f_ao_vec.z)*//*f_ao_vec.y < 1.0*/true/*min(corner_xy.y, corner_yz.x) < 1.0*//*min(corner_xz.x, corner_xz.y) < 1.0*/) && IntersectRayPlane(cam_pos.xyz, -f_orig_view_dir, vec3(f_pos.x, f_pos.y + delta_sides.y/* - sides.y*/, f_pos.z), vec3(0.0, -sides.y, 0.0), xz_point);
|
||||
// bool hit_yz = (/*ao_xy < 1.0 || ao_xz < 1.0*//*min(f_ao_vec.y, f_ao_vec.z) < 1.0*//*f_ao_vec.x < 1.0*/true/*true*//*min(corner_xy.x, corner_xz.x) < 1.0*//*min(corner_yz.x, corner_yz.y) < 1.0*/) && IntersectRayPlane(cam_pos.xyz, -f_orig_view_dir, vec3(f_pos.x + delta_sides.x/* - sides.x*/, f_pos.y, f_pos.z), vec3(-sides.x, 0.0, 0.0), yz_point);
|
||||
// float xy_dist = distance(cam_pos.xyz, xy_point), xz_dist = distance(cam_pos.xyz, xz_point), yz_dist = distance(cam_pos.xyz, yz_point);
|
||||
bool hit_xy = hit_yz_xz_xy.z, hit_xz = hit_yz_xz_xy.y, hit_yz = hit_yz_xz_xy.x;
|
||||
float xy_dist = dist_yz_xz_xy.z, xz_dist = dist_yz_xz_xy.y, yz_dist = dist_yz_xz_xy.x;
|
||||
// hit_xy = hit_xy && distance(f_pos.xy + delta_sides.xy, xy_point.xy) <= 1.0;
|
||||
// hit_xz = hit_xz && distance(f_pos.xz + delta_sides.xz, xz_point.xz) <= 1.0;
|
||||
// hit_yz = hit_yz && distance(f_pos.yz + delta_sides.yz, yz_point.yz) <= 1.0;
|
||||
vec3 voxel_norm =
|
||||
hit_yz ?
|
||||
hit_xz ?
|
||||
yz_dist < xz_dist ?
|
||||
hit_xy ? yz_dist < xy_dist ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
hit_xy ? xz_dist < xy_dist ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
hit_xy ? yz_dist < xy_dist ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
hit_xz ?
|
||||
hit_xy ? xz_dist < xy_dist ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
hit_xy ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0);
|
||||
// vec3 f_ao_view = max(vec3(dot(f_orig_view_dir.yz, sides.yz), dot(f_orig_view_dir.xz, sides.xz), dot(f_orig_view_dir.xy, sides.xy)), 0.0);
|
||||
// delta_sides *= sqrt(1.0 - f_ao_view * f_ao_view);
|
||||
// delta_sides *= 1.0 - mix(view_dir / f_ao_view, vec3(0.0), equal(f_ao_view, vec3(0.0)));// sqrt(1.0 - f_ao_view * f_ao_view);
|
||||
// delta_sides *= 1.0 - /*sign*/(max(vec3(dot(f_orig_view_dir.yz, sides.yz), dot(f_orig_view_dir.xz, sides.xz), dot(f_orig_view_dir.xy, sides.xy)), 0.0));
|
||||
// f_ao = length(f_ao_vec);
|
||||
// f_ao = dot(f_ao_vec, vec3(1.0)) / 3.0;
|
||||
// f_ao = 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0)));
|
||||
// f_ao = pow(f_ao_vec.x * f_ao_vec.y * f_ao_vec.z * 3.0, 1.0 / 2.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0)));
|
||||
// f_ao = pow(f_ao_vec.x * f_ao_vec.y * f_ao_vec.z, 1.0 / 3.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0)));
|
||||
// f_ao = f_ao_vec.x * f_ao_vec.y * f_ao_vec.z + (1.0 - f_ao_vec.x) * (1.0 - f_ao_vec.y) * (1.0 - f_ao_vec.z);
|
||||
// f_ao = sqrt((f_ao_vec.x + f_ao_vec.y + f_ao_vec.z) / 3.0); // 1.0 / sqrt(3.0) * sqrt(dot(f_ao_vec, vec3(1.0)));
|
||||
// f_ao = sqrt(dot(f_ao_vec, abs(voxel_norm)));
|
||||
// f_ao = 3.0 / (1.0 / f_ao_vec.x + 1.0 / f_ao_vec.y + 1.0 / f_ao_vec.z);
|
||||
// f_ao = min(ao_yz, min(ao_xz, ao_xy));
|
||||
// f_ao = max(f_ao_vec.x, max(f_ao_vec.y, f_ao_vec.z));
|
||||
// f_ao = min(f_ao_vec.x, min(f_ao_vec.y, f_ao_vec.z));
|
||||
// f_ao = sqrt(dot(f_ao_vec * abs(voxel_norm), sqrt(1.0 - delta_sides * delta_sides)) / 3.0);
|
||||
// f_ao = dot(f_ao_vec, sqrt(1.0 - delta_sides * delta_sides));
|
||||
// f_ao = dot(f_ao_vec, 1.0 - abs(delta_sides));
|
||||
// f_ao =
|
||||
// f_ao_vec.x < 1.0 ?
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// abs(delta_sides.x) < abs(delta_sides.y) ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z : f_ao_vec.x :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z : f_ao_vec.y :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z : f_ao_vec.x :
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z : f_ao_vec.y :
|
||||
// f_ao_vec.z;
|
||||
// f_ao = abs(delta_sides.x) < abs(delta_sides.y) ? abs(delta_sides.x) < abs(delta_sides.z) ? f_ao_vec.x : f_ao_vec.z :
|
||||
// abs(delta_sides.y) < abs(delta_sides.z) ? f_ao_vec.y : f_ao_vec.z;
|
||||
// f_ao = abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.y) * f_ao_vec.y ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? f_ao_vec.x : f_ao_vec.z :
|
||||
// abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? f_ao_vec.y : f_ao_vec.z;
|
||||
// f_ao = dot(abs(voxel_norm), abs(voxel_norm) * f_ao_vec)/* / 3.0*/;
|
||||
// f_ao = sqrt(dot(abs(voxel_norm), f_ao_vec) / 3.0);
|
||||
// f_ao = /*abs(sides)*/max(sign(1.0 + f_orig_view_dir * sides), 0.0) * f_ao);
|
||||
// f_ao = mix(f_ao, 1.0, dist_lerp);
|
||||
|
||||
// vec3 voxel_norm = f_norm;
|
||||
// vec3 voxel_norm =
|
||||
// f_ao_vec.x < 1.0 ?
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// abs(delta_sides.x) < abs(delta_sides.y) ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// vec3 voxel_norm =
|
||||
// /*f_ao_vec.x < 1.0*/true ?
|
||||
// /*f_ao_vec.y < 1.0*/true ?
|
||||
// abs(delta_sides.x) < abs(delta_sides.y) ?
|
||||
// /*f_ao_vec.z < 1.0 */true ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// /*f_ao_vec.y < 1.0*/true ?
|
||||
// /*f_ao_vec.z < 1.0*/true ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// vec3(0.0, 0.0, sides.z);
|
||||
/* vec3 voxel_norm =
|
||||
f_ao_vec.x < 1.0 ?
|
||||
f_ao_vec.y < 1.0 ?
|
||||
abs(delta_sides.x) < abs(delta_sides.y) ?
|
||||
f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
f_ao_vec.z < 1.0 ? abs(delta_sides.x) < abs(delta_sides.z) ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
f_ao_vec.y < 1.0 ?
|
||||
f_ao_vec.z < 1.0 ? abs(delta_sides.y) < abs(delta_sides.z) ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
f_ao_vec.z < 1.0 ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0); */
|
||||
// vec3 voxel_norm =
|
||||
// f_ao_vec.x < 1.0 ?
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.y) * f_ao_vec.y ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.x) * f_ao_vec.x < abs(delta_sides.z) * f_ao_vec.z ? vec3(sides.x, 0.0, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(sides.x, 0.0, 0.0) :
|
||||
// f_ao_vec.y < 1.0 ?
|
||||
// f_ao_vec.z < 1.0 ? abs(delta_sides.y) * f_ao_vec.y < abs(delta_sides.z) * f_ao_vec.z ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
|
||||
// f_ao_vec.z < 1.0 ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0);
|
||||
// vec3 voxel_norm = vec3(0.0);
|
||||
// voxel_norm = mix(voxel_norm, f_norm, dist_lerp);
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
// voxel_norm = vec3(0.0);
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float shadow_alt = /*f_pos.z;*/alt_at(f_pos.xy);//max(alt_at(f_pos.xy), f_pos.z);
|
||||
// float shadow_alt = f_pos.z;
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float shadow_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, shadow_alt, f_pos, sun_dir);
|
||||
// float sun_shade_frac = 1.0;
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, shadow_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;//horizon_at2(f_shadow, shadow_alt, f_pos, moon_dir);
|
||||
|
||||
// Magic stop-gap code without any physical justification.
|
||||
vec3 lerpy_norm;
|
||||
if (my_norm.z/*f_norm.z*/ > 0.99999) {
|
||||
lerpy_norm = vec3(0, 0, 1);
|
||||
} else {
|
||||
vec3 side_norm = normalize(vec3(my_norm.xy, 0));
|
||||
// lerpy_norm = f_norm;
|
||||
float mix_factor = clamp(abs(dot(f_orig_view_dir, side_norm)), 0, 1);
|
||||
lerpy_norm = mix(
|
||||
mix(my_norm, side_norm, clamp(dot(side_norm, my_norm) + 0.5, 0, 1)),
|
||||
my_norm,
|
||||
mix_factor
|
||||
);
|
||||
}
|
||||
const float DIST = 0.07;
|
||||
voxel_norm = normalize(mix(voxel_norm, lerpy_norm, clamp(my_norm.z * my_norm.z - (1.0 - DIST), 0, 1) / DIST));
|
||||
|
||||
f_pos.xyz += abs(voxel_norm) * delta_sides;
|
||||
voxel_norm = voxel_norm == vec3(0.0) ? f_norm : voxel_norm;
|
||||
|
||||
vec3 hash_pos = f_pos + focus_off.xyz;
|
||||
const float A = 0.055;
|
||||
const float W_INV = 1 / (1 + A);
|
||||
const float W_2 = W_INV * W_INV;//pow(W_INV, 2.4);
|
||||
const float NOISE_FACTOR = 0.02;//pow(0.02, 1.2);
|
||||
float noise = hash(vec4(floor(hash_pos * 3.0 - voxel_norm * 0.5), 0));//0.005/* - 0.01*/;
|
||||
vec3 noise_delta = (sqrt(f_col) * W_INV + noise * NOISE_FACTOR);
|
||||
// noise_delta = noise_delta * noise_delta * W_2 - f_col;
|
||||
// lum = W ⋅ col
|
||||
// lum + noise = W ⋅ (col + delta)
|
||||
// W ⋅ col + noise = W ⋅ col + W ⋅ delta
|
||||
// noise = W ⋅ delta
|
||||
// delta = noise / W
|
||||
// vec3 col = (f_col + noise_delta);
|
||||
// vec3 col = noise_delta * noise_delta * W_2;
|
||||
|
||||
f_col = noise_delta * noise_delta * W_2;
|
||||
// f_col = /*srgb_to_linear*/(f_col + hash(vec4(floor(hash_pos * 3.0 - voxel_norm * 0.5), 0)) * 0.01/* - 0.01*/); // Small-scale noise
|
||||
|
||||
// f_ao = 1.0;
|
||||
// f_ao = dot(f_ao_vec, sqrt(1.0 - delta_sides * delta_sides));
|
||||
|
||||
f_ao = dot(f_ao_vec, abs(voxel_norm));
|
||||
// f_ao = sqrt(dot(f_ao_vec * abs(voxel_norm), sqrt(1.0 - delta_sides * delta_sides)) / 3.0);
|
||||
|
||||
// vec3 ao_pos2 = min(fract(f_pos), 1.0 - fract(f_pos));
|
||||
// f_ao = sqrt(dot(ao_pos2, ao_pos2));
|
||||
// // f_ao = dot(abs(voxel_norm), f_ao_vec);
|
||||
// // voxel_norm = f_norm;
|
||||
|
||||
// Note: because voxels, we reduce the normal for reflections to just its z component, dpendng on distance to camera.
|
||||
// Idea: the closer we are to facing top-down, the more the norm should tend towards up-z.
|
||||
// vec3 l_norm; // = vec3(0.0, 0.0, 1.0);
|
||||
// vec3 l_norm = normalize(vec3(f_norm.x / max(abs(f_norm.x), 0.001), f_norm.y / max(abs(f_norm.y), 0.001), f_norm.z / max(abs(f_norm.z), 0.001)));
|
||||
// vec3 l_factor = 1.0 / (1.0 + max(abs(/*f_pos - cam_pos.xyz*//*-vec3(vert_pos4) / vert_pos4.w*/vec3(f_pos.xy, 0.0) - vec3(/*cam_pos*/focus_pos.xy, cam_to_frag)) - vec3(view_distance.x, view_distance.x, 0.0), 0.0) / vec3(32.0 * 2.0, 32.0 * 2.0, 1.0));
|
||||
// l_factor.z =
|
||||
// vec4 focus_pos4 = view_mat * vec4(focus_pos.xyz, 1.0);
|
||||
// vec3 focus_dir = normalize(-vec3(focus_pos4) / focus_pos4.w);
|
||||
|
||||
// float l_factor = 1.0 - pow(clamp(0.5 + 0.5 * dot(/*-view_dir*/-cam_to_frag, l_norm), 0.0, 1.0), 2.0);//1.0 / (1.0 + 0.5 * pow(max(distance(/*focus_pos.xy*/vec3(focus_pos.xy, /*vert_pos4.z / vert_pos4.w*/f_pos.z), vec3(f_pos.xy, f_pos.z))/* - view_distance.x*/ - 32.0, 0.0) / (32.0 * 1.0), /*0.5*/1.0));
|
||||
// l_factor = 1.0;
|
||||
// l_norm = normalize(mix(l_norm, f_norm, l_factor));
|
||||
// l_norm = f_norm;
|
||||
|
||||
/* l_norm = normalize(vec3(
|
||||
mix(l_norm.x, f_norm.x, clamp(pow(f_norm.x * 0.5, 64), 0, 1)),
|
||||
mix(-1.0, 1.0, clamp(pow(f_norm.y * 0.5, 64), 0, 1)),
|
||||
mix(-1.0, 1.0, clamp(pow(f_norm.z * 0.5, 64), 0, 1))
|
||||
)); */
|
||||
// f_norm = mix(l_norm, f_norm, min(1.0 / max(cam_to_frag, 0.001), 1.0));
|
||||
/* vec3 l_norm = normalize(vec3(
|
||||
mix(-1.0, 1.0, clamp(pow(f_norm.x * 0.5, 64), 0, 1)),
|
||||
mix(-1.0, 1.0, clamp(pow(f_norm.y * 0.5, 64), 0, 1)),
|
||||
mix(-1.0, 1.0, clamp(pow(f_norm.z * 0.5, 64), 0, 1))
|
||||
)); */
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
// vec3 view_dir = normalize(f_pos - cam_pos.xyz);
|
||||
|
||||
|
||||
// vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
// vec3 moon_dir = get_moon_dir(time_of_day.x);
|
||||
// // float sun_light = get_sun_brightness(sun_dir);
|
||||
// // float moon_light = get_moon_brightness(moon_dir);
|
||||
// // float my_alt = f_pos.z;//alt_at_real(f_pos.xy);
|
||||
// // vec3 f_norm = my_norm;
|
||||
// // vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
// // float shadow_alt = /*f_pos.z;*/alt_at(f_pos.xy);//max(alt_at(f_pos.xy), f_pos.z);
|
||||
// // float my_alt = alt_at(f_pos.xy);
|
||||
// float sun_shade_frac = horizon_at2(f_shadow, shadow_alt, f_pos, sun_dir);
|
||||
// float moon_shade_frac = horizon_at2(f_shadow, shadow_alt, f_pos, moon_dir);
|
||||
// // float sun_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, sun_dir);
|
||||
// // float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir);
|
||||
// // Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// // Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// // float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-f_norm, sun_dir)) * 10000.0), 0.0, 0.5);
|
||||
// // NOTE: current assumption is that moon and sun shouldn't be out at the sae time.
|
||||
// // This assumption is (or can at least easily be) wrong, but if we pretend it's true we avoids having to explicitly pass in a separate shadow
|
||||
// // for the sun and moon (since they have different brightnesses / colors so the shadows shouldn't attenuate equally).
|
||||
// // float shade_frac = sun_shade_frac + moon_shade_frac;
|
||||
// // float brightness_denominator = (ambient_sides + vec3(SUN_AMBIANCE * sun_light + moon_light);
|
||||
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, moon_shade_frac/*, light_pos*/);
|
||||
|
||||
float alpha = 1.0;//0.1;//0.2;///1.0;//sqrt(2.0);
|
||||
const float n2 = 1.5;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float cam_alt = alt_at(cam_pos.xy);
|
||||
float fluid_alt = medium.x == 1u ? max(cam_alt + 1, floor(shadow_alt)) : view_distance.w;
|
||||
float R_s = (f_pos.z < my_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
vec3 mu = medium.x == 1u/* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0);
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation = compute_attenuation_point(cam_pos.xyz, view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos);
|
||||
// Use f_norm here for better shadows.
|
||||
// vec3 light_frac = light_reflection_factor(f_norm/*l_norm*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(/*1.0*/R_s), alpha);
|
||||
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, cam_to_frag, (0.25 * shade_frac + 0.25 * light_frac) * f_col, 0.5 * shade_frac * f_col, 0.5 * shade_frac * /*vec3(1.0)*/f_col, 2.0, emitted_light, reflected_light);
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, voxel_norm/*l_norm*/, view_dir, f_pos, vec3(0.0), cam_attenuation, fluid_alt, vec3(1.0)/* * (0.5 * light_frac + vec3(0.5 * shade_frac))*/, vec3(1.0), /*0.5 * shade_frac * *//*vec3(1.0)*//*f_col*/vec3(R_s), alpha, voxel_norm, dist_lerp/*max(distance(focus_pos.xy, f_pos.xyz) - view_distance.x, 0.0) / 1000 < 1.0*/, emitted_light, reflected_light);
|
||||
// emitted_light = vec3(1.0);
|
||||
// emitted_light *= max(shade_frac, MIN_SHADOW);
|
||||
// reflected_light *= shade_frac;
|
||||
// max_light *= shade_frac;
|
||||
// reflected_light = vec3(0.0);
|
||||
|
||||
// dot(diffuse_factor, /*R_r * */vec4(abs(norm) * (1.0 - dist), dist))
|
||||
|
||||
// corner_xy = mix(all(lessThan(corner_xy, 1.0)) ? vec2(0.0) : 0.4 * (), 1.0
|
||||
//
|
||||
// TODO: Handle similar logic for z.
|
||||
|
||||
// So we repeat this for all three sides to find the "next" position on each side.
|
||||
// vec3 delta_sides = 1.0 + sides * fract(-sides * f_pos);
|
||||
// Now, we
|
||||
// Now, all we have to do is find out whether (again, assuming f_pos is positive) next_sides represents a new integer.
|
||||
// We currently just treat this as "new floor != old floor".
|
||||
|
||||
// So to find the position at the nearest voxel, we just subtract voxel_norm * fract(sides * ) from f_pos.z.
|
||||
// Then to find out whether we meet a new "block" in 1 voxel, we just
|
||||
// on the "other" side can be found (according to my temporary theory) as the cross product
|
||||
// vec3 norm = normalize(cross(
|
||||
// vec3(/*2.0 * SAMPLE_W*/square.z - square.x, 0.0, altx1 - altx0),
|
||||
// vec3(0.0, /*2.0 * SAMPLE_W*/square.w - square.y, alty1 - alty0)
|
||||
// ));
|
||||
// vec3 norm = normalize(vec3(
|
||||
// (altx0 - altx1) / (square.z - square.x),
|
||||
// (alty0 - alty1) / (square.w - square.y),
|
||||
// 1.0
|
||||
// //(abs(square.w - square.y) + abs(square.z - square.x)) / (slope + 0.00001) // Avoid NaN
|
||||
// ));
|
||||
//
|
||||
// If a side coordinate is 0, then it counts as no AO;
|
||||
// otherwise, it counts as fractional AO. So what we need is to know whether the fractional AO to the next block in that direction pushes us to a new integer.
|
||||
//
|
||||
// vec3 ao_pos_z = floor(f_pos + f_norm);
|
||||
// vec3 ao_pos_z = corner_distance;
|
||||
// vec3 ao_pos = 0.5 - clamp(min(fract(abs(f_pos)), 1.0 - fract(abs(f_pos))), 0.0, 0.5);
|
||||
//
|
||||
// f_ao = /*sqrt*/1.0 - 2.0 * sqrt(dot(ao_pos, ao_pos) / 2.0);
|
||||
// f_ao = /*sqrt*/1.0 - (dot(ao_pos, ao_pos)/* / 2.0*/);
|
||||
// f_ao = /*sqrt*/1.0 - 2.0 * (dot(ao_pos, ao_pos)/* / 2.0*/);
|
||||
// f_ao = /*sqrt*/1.0 - 2.0 * sqrt(dot(ao_pos, ao_pos) / 2.0);
|
||||
float ao = f_ao;// /*pow(f_ao, 0.5)*/f_ao * 0.9 + 0.1;
|
||||
emitted_light *= ao;
|
||||
reflected_light *= ao;
|
||||
|
||||
// emitted_light += 0.5 * vec3(SUN_AMBIANCE * sun_shade_frac * sun_light + moon_shade_frac * moon_light) * f_col * (ambient_sides + 1.0);
|
||||
|
||||
// Ambient lighting attempt: vertical light.
|
||||
// reflected_light += /*0.0125*/0.15 * 0.25 * _col * light_reflection_factor(f_norm, cam_to_frag, vec3(0, 0, -1.0), 0.5 * f_col, 0.5 * f_col, 2.0);
|
||||
// emitted_light += /*0.0125*/0.25 * f_col * ;
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
// vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light);
|
||||
// f_col = f_col + (hash(vec4(floor(vec3(focus_pos.xy + splay(v_pos_orig), f_pos.z)) * 3.0 - round(f_norm) * 0.5, 0)) - 0.5) * 0.05; // Small-scale noise
|
||||
vec3 surf_color = /*illuminate(emitted_light, reflected_light)*/illuminate(max_light, view_dir, f_col * emitted_light, f_col * reflected_light);
|
||||
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(cam_to_frag/*view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 1.0, /*true*/false, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec3 color = surf_color;
|
||||
#endif
|
||||
|
||||
// float mist_factor = max(1 - (f_pos.z + (texture(t_noise, f_pos.xy * 0.0005 + time_of_day.x * 0.0003).x - 0.5) * 128.0) / 400.0, 0.0);
|
||||
// //float mist_factor = f_norm.z * 2.0;
|
||||
// color = mix(color, vec3(1.0) * /*diffuse_light*/reflected_light, clamp(mist_factor * 0.00005 * distance(f_pos.xy, focus_pos.xy), 0, 0.3));
|
||||
// color = surf_color;
|
||||
|
||||
tgt_color = vec4(color, 1.0);
|
||||
}
|
104
assets/voxygen/shaders/lod-terrain-vert.glsl
Normal file
104
assets/voxygen/shaders/lod-terrain-vert.glsl
Normal file
@ -0,0 +1,104 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_VOXEL
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
in vec2 v_pos;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec4 nul;
|
||||
};
|
||||
|
||||
out vec3 f_pos;
|
||||
out vec3 f_norm;
|
||||
// out vec2 v_pos_orig;
|
||||
// out vec4 f_square;
|
||||
// out vec4 f_shadow;
|
||||
// out float f_light;
|
||||
|
||||
void main() {
|
||||
// Find distances between vertices.
|
||||
f_pos = lod_pos(v_pos, focus_pos.xy);
|
||||
vec2 dims = vec2(1.0 / view_distance.y);
|
||||
vec4 f_square = focus_pos.xyxy + vec4(splay(v_pos - dims), splay(v_pos + dims));
|
||||
f_norm = lod_norm(f_pos.xy, f_square);
|
||||
// v_pos_orig = v_pos;
|
||||
|
||||
// f_pos = lod_pos(focus_pos.xy + splay(v_pos) * /*1000000.0*/(1 << 20), square);
|
||||
|
||||
// f_norm = lod_norm(f_pos.xy);
|
||||
|
||||
// f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
|
||||
f_pos.z -= 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0);
|
||||
|
||||
// f_pos.z -= 100.0 * pow(1.0 + 0.01 / view_distance.x, -pow(distance(focus_pos.xy, f_pos.xy), 2.0));
|
||||
// f_pos.z = mix(-f_pos.z, f_pos.z, view_distance.x <= distance(focus_pos.xy, f_pos.xy) + 32.0);
|
||||
|
||||
// bool faces_fluid = false;// bool((f_pos_norm >> 28) & 0x1u);
|
||||
// // TODO: Measure real water surface altitude here.
|
||||
// float surfaceAlt = mix(view_distance.z, /*floor*/(min(f_pos.z, floor(alt_at_real(cam_pos.xy)))), medium.x);
|
||||
// // float surfaceAlt = mix(view_distance.z, floor(max(cam_pos.z, alt_at_real(cam_pos.xy))), medium.x);
|
||||
// // float surfaceAlt = min(floor(f_pos.z), floor(alt_at_real(cam_pos.xy))); // faces_fluid ? max(ceil(f_pos.z), floor(f_alt)) : floor(f_alt);
|
||||
|
||||
// f_pos.z -= max(sign(view_distance.x - distance(focus_pos.xy, f_pos.xy)), 0.0) * (32.0 * view_distance.z / 255 + 32.0 * max(0.0, f_pos.z - cam_pos.z));
|
||||
// f_pos.z -= 0.1 + max(view_distance.x - distance(focus_pos.xy, f_pos.xy), 0.0) * (1.0 + max(1.0, ceil(f_pos.z - focus_pos.z)));
|
||||
|
||||
// vec3 wRayinitial = f_pos; // cam_pos.z < f_pos.z ? f_pos : cam_pos.xyz;
|
||||
// vec3 wRayfinal = cam_pos.xyz; // cam_pos.z < f_pos.z ? cam_pos.xyz : f_pos;
|
||||
// wRayfinal = dot(wRayfinal - wRayinitial, focus_pos.xyz - cam_pos.xyz) < 0.0 ? wRayfinal : wRayinitial;
|
||||
// vec3 wRayNormal = /*surfaceAlt < wRayinitial.z ? vec3(0.0, 0.0, -1.0) : */vec3(0.0, 0.0, 1.0);
|
||||
// float n_camera = mix(1.0, 1.3325, medium.x);
|
||||
// float n_vertex = faces_fluid ? 1.3325 : 1.0;
|
||||
// float n1 = n_vertex; // cam_pos.z < f_pos.z ? n_vertex : n_camera;
|
||||
// float n2 = n_camera; // cam_pos.z < f_pos.z ? n_camera : n_vertex;
|
||||
|
||||
// float wRayLength0 = length(wRayfinal - wRayinitial);
|
||||
// vec3 wRayDir = (wRayfinal - wRayinitial) / wRayLength0;
|
||||
// vec3 wPoint = wRayfinal;
|
||||
// bool wIntersectsSurface = IntersectRayPlane(wRayinitial, wRayDir, vec3(0.0, 0.0, surfaceAlt), -wRayNormal, wPoint);
|
||||
// float wRayLength = length(wPoint - wRayinitial);
|
||||
// wPoint = wRayLength < wRayLength0 ? wPoint : wRayfinal;
|
||||
// wRayLength = min(wRayLength, wRayLength0); // min(max_length, dot(wRayfinal - wpos, defaultpos - wpos));
|
||||
|
||||
// // vec3 wRayDir2 = (wRayfinal - wRayinitial) / wRayLength;
|
||||
|
||||
// vec3 wRayDir3 = (dot(wRayDir, wRayNormal) < 0.0 && surfaceAlt < wRayinitial.z && wIntersectsSurface/* && medium.x == 1u*/) ? refract(wRayDir, wRayNormal, n2 / n1) : wRayDir;
|
||||
// // wPoint -= wRayDir3 * wRayLength * n2 / n1;
|
||||
|
||||
// vec3 newRay = (dot(wRayDir3, focus_pos.xyz - cam_pos.xyz) < 0.0 && /*dot(wRayDir, wRayNormal) > 0.0 && *//*surfaceAlt < wRayinitial.z && */wIntersectsSurface && medium.x == 1u) ? wPoint - wRayDir3 * wRayLength * n2 / n1/*wPoint - wRayDir3 * wRayLength * n2 / n1*/ : f_pos;// - (wRayfinal - wPoint) * n2 / n1; // wPoint + n2 * (wRayfinal - wPoint) - n2 / n1 * wRayLength * wRayDir3;
|
||||
|
||||
// newRay.z -= max(view_distance.x - distance(focus_pos.xy, f_pos.xy), 0.0) * (1.0 + max(0.0, f_pos.z - focus_pos.z));
|
||||
|
||||
|
||||
// f_light = 1.0;
|
||||
|
||||
gl_Position =
|
||||
/* proj_mat *
|
||||
view_mat * */
|
||||
all_mat *
|
||||
vec4(f_pos/*newRay*/, 1);
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z * gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
@ -1,38 +1,86 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in vec3 f_norm;
|
||||
in vec3 f_col;
|
||||
in float f_ao;
|
||||
in float f_light;
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
const float FADE_DIST = 32.0;
|
||||
|
||||
void main() {
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
diffuse_light *= f_light * point_shadow;
|
||||
ambient_light *= f_light, point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
float ao = pow(f_ao, 0.5) * 0.85 + 0.15;
|
||||
ambient_light *= ao;
|
||||
diffuse_light *= ao;
|
||||
vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light);
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;
|
||||
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac);
|
||||
|
||||
vec3 surf_color = f_col;
|
||||
float alpha = 1.0;
|
||||
const float n2 = 1.5;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
vec3 k_a = vec3(1.0);
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
// To account for prior saturation.
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
|
||||
max_light += lights_at(f_pos, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
|
||||
surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds);
|
||||
vec3 fog_color = get_sky_color(cam_to_frag, time_of_day.x, cam_pos.xyz, f_pos, 0.5, false, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec3 color = surf_color;
|
||||
#endif
|
||||
|
||||
tgt_color = vec4(color, 0.3);
|
||||
}
|
||||
|
@ -1,11 +1,23 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
in vec3 v_pos;
|
||||
in uint v_col;
|
||||
// in uint v_col;
|
||||
in uint v_norm_ao;
|
||||
in vec3 inst_pos;
|
||||
in float inst_time;
|
||||
@ -163,7 +175,7 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
f_pos = inst_pos + (v_pos * attr.scale * SCALE + attr.offs);
|
||||
f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE + attr.offs);
|
||||
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
@ -175,12 +187,8 @@ void main() {
|
||||
f_col =
|
||||
//srgb_to_linear(col) *
|
||||
srgb_to_linear(attr.col);
|
||||
f_ao = float((v_norm_ao >> 3) & 0x3u) / 4.0;
|
||||
|
||||
f_light = 1.0;
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
|
@ -1,20 +1,38 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_col;
|
||||
flat in vec3 f_norm;
|
||||
in float f_ao;
|
||||
// in float f_alt;
|
||||
// in vec4 f_shadow;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
mat4 model_mat;
|
||||
vec4 model_col;
|
||||
ivec4 atlas_offs;
|
||||
vec3 model_pos;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
mat4 normals_mat;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
@ -29,17 +47,17 @@ uniform u_bones {
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
|
||||
// float distance = distance(vec3(cam_pos), focus_pos.xyz) - 2;
|
||||
|
||||
float opacity = clamp(distance / distance_divider, 0, 1);
|
||||
// float opacity = clamp(distance / distance_divider, 0, 1);
|
||||
|
||||
if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > opacity) {
|
||||
discard;
|
||||
}
|
||||
// if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > opacity) {
|
||||
// discard;
|
||||
// }
|
||||
|
||||
if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > shadow_dithering) {
|
||||
discard;
|
||||
}
|
||||
// if(threshold_matrix[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4] > shadow_dithering) {
|
||||
// discard;
|
||||
// }
|
||||
|
||||
tgt_color = vec4(0.0,0.0,0.0, 1.0);
|
||||
}
|
||||
|
@ -1,8 +1,25 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION)
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
// Note: The sampler uniform is declared here because it differs for MSAA
|
||||
#include <anti-aliasing.glsl>
|
||||
#include <srgb.glsl>
|
||||
|
||||
in vec2 f_pos;
|
||||
|
||||
@ -29,15 +46,138 @@ vec3 hsv2rgb(vec3 c) {
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
vec3 illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitted, vec3 reflected) {
|
||||
const float NIGHT_EXPOSURE = 10.0;
|
||||
const float DUSK_EXPOSURE = 2.0;//0.8;
|
||||
const float DAY_EXPOSURE = 1.0;//0.7;
|
||||
|
||||
const float DAY_SATURATION = 1.0;
|
||||
const float DUSK_SATURATION = 0.6;
|
||||
const float NIGHT_SATURATION = 0.1;
|
||||
|
||||
const float gamma = /*0.5*//*1.*0*/1.0;//1.0;
|
||||
/* float light = length(emitted + reflected);
|
||||
float color = srgb_to_linear(emitted + reflected);
|
||||
float avg_col = (color.r + color.g + color.b) / 3.0;
|
||||
return ((color - avg_col) * light + reflected * avg_col) * (emitted + reflected); */
|
||||
// float max_intensity = vec3(1.0);
|
||||
vec3 color = emitted + reflected;
|
||||
float lum = rel_luminance(color);
|
||||
// float lum_sky = lum - max_light;
|
||||
|
||||
// vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
// vec3 moon_dir = get_moon_dir(time_of_day.x);
|
||||
// float sky_light = rel_luminance(
|
||||
// get_sun_color(sun_dir) * get_sun_brightness(sun_dir) * SUN_COLOR_FACTOR +
|
||||
// get_moon_color(moon_dir) * get_moon_brightness(moon_dir));
|
||||
float sky_light = lum;
|
||||
|
||||
// Tone mapped value.
|
||||
// vec3 T = /*color*//*lum*/color;//normalize(color) * lum / (1.0 + lum);
|
||||
// float alpha = 0.5;//2.0;
|
||||
// float alpha = mix(
|
||||
// mix(
|
||||
// DUSK_EXPOSURE,
|
||||
// NIGHT_EXPOSURE,
|
||||
// max(sun_dir.z, 0)
|
||||
// ),
|
||||
// DAY_EXPOSURE,
|
||||
// max(-sun_dir.z, 0)
|
||||
// );
|
||||
float alpha = 1.0;//log(1.0 - lum) / lum;
|
||||
// vec3 now_light = moon_dir.z < 0 ? moon_dir : sun_dir;
|
||||
// float cos_view_light = dot(-now_light, view_dir);
|
||||
// alpha *= exp(1.0 - cos_view_light);
|
||||
// sky_light *= 1.0 - log(1.0 + view_dir.z);
|
||||
float alph = sky_light > 0.0 && max_light > 0.0 ? mix(1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light / (0.0 + sky_light)), 1.0, clamp(max_light - sky_light, 0.0, 1.0)) : 1.0;
|
||||
alpha = alpha * alph;// min(alph, 1.0);//((max_light > 0.0 && max_light > sky_light /* && sky_light > 0.0*/) ? /*1.0*/1.0 / log(/*1.0*//*1.0 + *//*lum_sky + */1.0 + max_light - (0.0 + sky_light)) : 1.0);
|
||||
// alpha = alpha * min(1.0, (max_light == 0.0 ? 1.0 : (1.0 + abs(lum_sky)) / /*(1.0 + max_light)*/max_light));
|
||||
|
||||
vec3 col_adjusted = lum == 0.0 ? vec3(0.0) : color / lum;
|
||||
|
||||
// float L = lum == 0.0 ? 0.0 : log(lum);
|
||||
|
||||
|
||||
// // float B = T;
|
||||
// // float B = L + log(alpha);
|
||||
// float B = lum;
|
||||
|
||||
// float D = L - B;
|
||||
|
||||
// float o = 0.0;//log(PERSISTENT_AMBIANCE);
|
||||
// float scale = /*-alpha*/-alpha;//1.0;
|
||||
|
||||
// float B_ = (B - o) * scale;
|
||||
|
||||
// // float T = lum;
|
||||
// float O = exp(B_ + D);
|
||||
|
||||
float T = 1.0 - exp(-alpha * lum);//lum / (1.0 + lum);
|
||||
// float T = lum;
|
||||
|
||||
// Heuristic desaturation
|
||||
// const float s = 0.8;
|
||||
float s = 1.0;
|
||||
// float s = mix(
|
||||
// mix(
|
||||
// DUSK_SATURATION,
|
||||
// NIGHT_SATURATION,
|
||||
// max(sun_dir.z, 0)
|
||||
// ),
|
||||
// DAY_SATURATION,
|
||||
// max(-sun_dir.z, 0)
|
||||
// );
|
||||
// s = max(s, (max_light) / (1.0 + s));
|
||||
// s = max(s, max_light / (1.0 + max_light));
|
||||
// s = max_light / (1.0 + max_light);
|
||||
|
||||
vec3 c = pow(col_adjusted, vec3(s)) * T;
|
||||
// vec3 c = col_adjusted * T;
|
||||
// vec3 c = sqrt(col_adjusted) * T;
|
||||
// vec3 c = /*col_adjusted * */col_adjusted * T;
|
||||
|
||||
return c;
|
||||
// float sum_col = color.r + color.g + color.b;
|
||||
// return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma)));
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = (f_pos + 1.0) * 0.5;
|
||||
|
||||
if (medium.x == 1u) {
|
||||
/* if (medium.x == 1u) {
|
||||
uv = clamp(uv + vec2(sin(uv.y * 16.0 + tick.x), sin(uv.x * 24.0 + tick.x)) * 0.005, 0, 1);
|
||||
}
|
||||
} */
|
||||
|
||||
vec2 c_uv = vec2(0.5);//uv;//vec2(0.5);//uv;
|
||||
vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*//*0.5 - */min(uv, 1.0 - uv);//min(uv * (1.0 - uv), 0.25) * 2.0;
|
||||
// delta = /*sqrt(2.0) / 2.0 - */sqrt(vec2(dot(delta, delta)));
|
||||
// delta = 0.5 - vec2(min(delta.x, delta.y));
|
||||
delta = vec2(0.25);//vec2(dot(/*0.5 - */delta, /*0.5 - */delta));//vec2(min(delta.x, delta.y));//sqrt(2.0) * (0.5 - vec2(min(delta.x, delta.y)));
|
||||
// delta = vec2(sqrt(dot(delta, delta)));
|
||||
// vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/1.0 - vec2(sqrt(dot(uv, 1.0 - uv)));//min(uv * (1.0 - uv), 0.25) * 2.0;
|
||||
// float delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/1.0 - (dot(uv - 0.5, uv - 0.5));//0.01;//25;
|
||||
// vec2 delta = /*sqrt*//*sqrt(2.0) / 2.0*//*sqrt(2.0) / 2.0*/sqrt(uv * (1.0 - uv));//min(uv * (1.0 - uv), 0.25) * 2.0;
|
||||
|
||||
// float bright_color0 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(0.0, 0.0), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color1 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(delta.x, delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color2 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(delta.x, -delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color3 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(-delta.x, delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color4 = rel_luminance(texelFetch/*texture*/(src_color, ivec2(clamp(c_uv + vec2(-delta.x, -delta.y), 0.0, 1.0) * screen_res.xy/* / 50*/)/* * 50*/, 0).rgb);
|
||||
|
||||
// float bright_color0 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(0.0, 0.0), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color1 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(delta, delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color2 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(delta, -delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color3 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(-delta, delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb);
|
||||
// float bright_color4 = rel_luminance(texture(src_color, /*ivec2*/(clamp(c_uv + vec2(-delta, -delta), 0.0, 1.0)/* * screen_res.xy*//* / 50*/)/* * 50*/, 0).rgb);
|
||||
|
||||
// float bright_color = max(bright_color0, max(bright_color1, max(bright_color2, max(bright_color3, bright_color4))));// / 2.0;// / 5.0;
|
||||
|
||||
// float bright_color = (bright_color0 + bright_color1 + bright_color2 + bright_color3 + bright_color4) / 5.0;
|
||||
|
||||
vec4 aa_color = aa_apply(src_color, uv * screen_res.xy, screen_res.xy);
|
||||
|
||||
// aa_color.rgb = illuminate(1.0 - 1.0 / (1.0 + bright_color), normalize(cam_pos.xyz - focus_pos.xyz), /*vec3 max_light, */vec3(0.0), aa_color.rgb);
|
||||
|
||||
//vec4 hsva_color = vec4(rgb2hsv(fxaa_color.rgb), fxaa_color.a);
|
||||
//hsva_color.y *= 1.45;
|
||||
//hsva_color.z *= 0.85;
|
||||
@ -46,9 +186,11 @@ void main() {
|
||||
|
||||
vec4 final_color = pow(aa_color, gamma);
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
if (medium.x == 1u) {
|
||||
final_color *= vec4(0.2, 0.2, 0.8, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
tgt_color = vec4(final_color.rgb, 1);
|
||||
}
|
||||
|
@ -1,5 +1,21 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION)
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec2 v_pos;
|
||||
@ -14,5 +30,5 @@ out vec2 f_pos;
|
||||
void main() {
|
||||
f_pos = v_pos;
|
||||
|
||||
gl_Position = vec4(v_pos, 0.0, 1.0);
|
||||
gl_Position = vec4(v_pos, -1.0, 1.0);
|
||||
}
|
||||
|
@ -1,7 +1,24 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_TRANSMISSION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <sky.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
|
||||
@ -13,14 +30,34 @@ uniform u_locals {
|
||||
out vec4 tgt_color;
|
||||
|
||||
void main() {
|
||||
// tgt_color = vec4(MU_SCATTER, 1.0);
|
||||
// return;
|
||||
vec4 _clouds;
|
||||
|
||||
vec3 cam_dir = normalize(f_pos - cam_pos.xyz);
|
||||
|
||||
float cam_alt = alt_at(cam_pos.xy);
|
||||
// float f_alt = alt_at(f_pos.xy);
|
||||
float fluid_alt = medium.x == 1u ? floor(cam_alt + 1) : view_distance.w;
|
||||
// float fluid_alt = max(f_pos.z + 1, floor(f_alt));
|
||||
vec3 mu = medium.x == 1u /* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0);
|
||||
// vec3 sun_attenuation = compute_attenuation(wpos, -sun_dir, mu, surface_alt, wpos);
|
||||
vec3 cam_attenuation = compute_attenuation(cam_pos.xyz, -cam_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*//*f_pos*//*vec3(f_pos.xy, fluid_alt)*/cam_pos.xyz);
|
||||
// vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
|
||||
// vec3 cam_attenuation = vec3(1.0);
|
||||
|
||||
|
||||
/* vec3 world_pos = cam_pos.xyz + cam_dir * 500000.0;
|
||||
tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, world_pos, 1.0, true, _clouds), 1.0); */
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
|
||||
float dist = 100000.0;
|
||||
if (medium.x == 1u) {
|
||||
dist = UNDERWATER_MIST_DIST;
|
||||
}
|
||||
vec3 wpos = cam_pos.xyz + normalize(f_pos) * dist;
|
||||
|
||||
tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, wpos, 1.0, true, _clouds), 1.0);
|
||||
float refractionIndex = medium.x == 1u ? 1.0 / 1.3325 : 1.0;
|
||||
/* if (medium.x == 1u) {
|
||||
dist = UNDERWATER_MIST_DIST;
|
||||
} */
|
||||
vec3 wpos = cam_pos.xyz + /*normalize(f_pos)*/cam_dir * dist;
|
||||
|
||||
tgt_color = vec4(cam_attenuation * get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, wpos, 1.0, true, refractionIndex, _clouds), 1.0);
|
||||
}
|
||||
|
@ -1,5 +1,21 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_TRANSMISSION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 v_pos;
|
||||
@ -12,12 +28,22 @@ uniform u_locals {
|
||||
out vec3 f_pos;
|
||||
|
||||
void main() {
|
||||
/* vec3 v_pos = v_pos;
|
||||
v_pos.y = -v_pos.y; */
|
||||
f_pos = v_pos;
|
||||
|
||||
// TODO: Make this position-independent to avoid rounding error jittering
|
||||
gl_Position =
|
||||
proj_mat *
|
||||
view_mat *
|
||||
vec4(v_pos * 100000.0 + cam_pos.xyz, 1);
|
||||
gl_Position.z = 0.0;
|
||||
/* proj_mat *
|
||||
view_mat * */
|
||||
all_mat *
|
||||
/* proj_mat *
|
||||
view_mat * */
|
||||
vec4(/*100000 * */v_pos + cam_pos.xyz, 1);
|
||||
// vec4(v_pos * (100000.0/* + 0.5*/) + cam_pos.xyz, 1);
|
||||
// gl_Position = vec4(gl_Position.xy, sign(gl_Position.z) * gl_Position.w, gl_Position.w);
|
||||
gl_Position.z = gl_Position.w;
|
||||
// gl_Position.z = gl_Position.w - 0.000001;//0.0;
|
||||
// gl_Position.z = 1.0;
|
||||
// gl_Position.z = -1.0;
|
||||
}
|
||||
|
@ -1,38 +1,199 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in vec3 f_norm;
|
||||
in vec3 f_col;
|
||||
in float f_ao;
|
||||
in float f_light;
|
||||
flat in float f_light;
|
||||
// flat in vec3 f_pos_norm;
|
||||
in vec2 f_uv_pos;
|
||||
// flat in uint f_atlas_pos;
|
||||
// in vec3 f_col;
|
||||
// in float f_ao;
|
||||
// in float f_light;
|
||||
// in vec4 light_pos[2];
|
||||
|
||||
uniform sampler2D t_col_light;
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
const float FADE_DIST = 32.0;
|
||||
|
||||
void main() {
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
diffuse_light *= f_light * point_shadow;
|
||||
ambient_light *= f_light, point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
float ao = pow(f_ao, 0.5) * 0.85 + 0.15;
|
||||
ambient_light *= ao;
|
||||
diffuse_light *= ao;
|
||||
vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light);
|
||||
/* if (f_uv_pos.x < 757) {
|
||||
discard;
|
||||
} */
|
||||
// vec2 f_uv_pos = vec2(768,1) + 0.5;
|
||||
// vec2 f_uv_pos = vec2(760, 380);// + 0.5;
|
||||
// vec2 f_uv_pos = vec2((uvec2(f_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu)) + 0.5;
|
||||
/* if (f_uv_pos.x < 757) {
|
||||
discard;
|
||||
} */
|
||||
// vec3 du = dFdx(f_pos);
|
||||
// vec3 dv = dFdy(f_pos);
|
||||
// vec3 f_norm = normalize(cross(du, dv));
|
||||
|
||||
// vec4 f_col_light = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)/* + uv_delta*//* - f_norm * 0.00001*/);
|
||||
// vec4 f_col_light = textureGrad(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0), vec2(0.5), vec2(0.5));
|
||||
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0);
|
||||
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
|
||||
// vec3 f_col = vec3(1.0);
|
||||
// vec2 texSize = textureSize(t_col_light, 0);
|
||||
// float f_ao = f_col_light.a;
|
||||
// float f_ao = f_col_light.a + length(vec2(dFdx(f_col_light.a), dFdy(f_col_light.a)));
|
||||
float f_ao = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// float f_ao = 1.0;
|
||||
// float /*f_light*/f_ao = textureProj(t_col_light, vec3(f_uv_pos, texSize)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
|
||||
// vec3 my_chunk_pos = f_pos_norm;
|
||||
// tgt_color = vec4(hash(floor(vec4(my_chunk_pos.x, 0, 0, 0))), hash(floor(vec4(0, my_chunk_pos.y, 0, 1))), hash(floor(vec4(0, 0, my_chunk_pos.z, 2))), 1.0);
|
||||
// tgt_color = vec4(f_uv_pos / texSize, 0.0, 1.0);
|
||||
// tgt_color = vec4(f_col.rgb, 1.0);
|
||||
// return;
|
||||
// vec4 light_pos[2];
|
||||
//#if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// vec4 sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
//#elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// vec4 sun_pos = vec4(0.0);
|
||||
//#endif
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
// float sun_light = get_sun_brightness(sun_dir);
|
||||
// float moon_light = get_moon_brightness(moon_dir);
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
// float f_alt = f_pos.z;
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
// float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
|
||||
// float sun_shade_frac = horizon_at(f_pos, sun_dir);
|
||||
// float moon_shade_frac = horizon_at(f_pos, moon_dir);
|
||||
// Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-f_norm, sun_dir)) * 10000.0), 0.0, 0.5);
|
||||
// NOTE: current assumption is that moon and sun shouldn't be out at the sae time.
|
||||
// This assumption is (or can at least easily be) wrong, but if we pretend it's true we avoids having to explicitly pass in a separate shadow
|
||||
// for the sun and moon (since they have different brightnesses / colors so the shadows shouldn't attenuate equally).
|
||||
// float shade_frac = sun_shade_frac + moon_shade_frac;
|
||||
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac/*, light_pos*/);
|
||||
|
||||
vec3 surf_color = /*srgb_to_linear*//*linear_to_srgb*/(f_col);
|
||||
float alpha = 1.0;
|
||||
const float n2 = 1.5;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
vec3 k_a = vec3(1.0);
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
vec3 emitted_light, reflected_light;
|
||||
|
||||
// To account for prior saturation.
|
||||
// float vert_light = pow(f_light, 1.5);
|
||||
// vec3 light_frac = light_reflection_factor(f_norm/*vec3(0, 0, 1.0)*/, view_dir, vec3(0, 0, -1.0), vec3(1.0), vec3(R_s), alpha);
|
||||
/* light_frac += light_reflection_factor(f_norm, view_dir, vec3(1.0, 0, 0.0), vec3(1.0), vec3(1.0), 2.0);
|
||||
light_frac += light_reflection_factor(f_norm, view_dir, vec3(-1.0, 0, 0.0), vec3(1.0), vec3(1.0), 2.0);
|
||||
light_frac += light_reflection_factor(f_norm, view_dir, vec3(0.0, -1.0, 0.0), vec3(1.0), vec3(1.0), 2.0);
|
||||
light_frac += light_reflection_factor(f_norm, view_dir, vec3(0.0, 1.0, 0.0), vec3(1.0), vec3(1.0), 2.0); */
|
||||
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
// vec3 emitted_light, reflected_light;
|
||||
// float point_shadow = shadow_at(f_pos,f_norm);
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
||||
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
float max_light = 0.0;
|
||||
max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, /*time_of_day.x, *//*cam_to_frag*/view_dir, k_a * f_light/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
// reflected_light *= /*vert_light * */point_shadow * shade_frac;
|
||||
// emitted_light *= /*vert_light * */point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// max_light *= /*vert_light * */point_shadow * shade_frac;
|
||||
// emitted_light *= point_shadow;
|
||||
// reflected_light *= point_shadow;
|
||||
// max_light *= point_shadow;
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
// float point_shadow = shadow_at(f_pos, f_norm);
|
||||
// diffuse_light *= f_light * point_shadow;
|
||||
// ambient_light *= f_light * point_shadow;
|
||||
// light += point_light;
|
||||
// diffuse_light += point_light;
|
||||
// reflected_light += point_light;
|
||||
|
||||
max_light += lights_at(f_pos, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
|
||||
/* vec3 point_light = light_at(f_pos, f_norm);
|
||||
emitted_light += point_light;
|
||||
reflected_light += point_light; */
|
||||
|
||||
// float ao = /*pow(f_ao, 0.5)*/f_ao * 0.85 + 0.15;
|
||||
float ao = f_ao;
|
||||
emitted_light *= ao;
|
||||
reflected_light *= ao;
|
||||
|
||||
surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light);
|
||||
// vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds);
|
||||
vec3 fog_color = get_sky_color(cam_to_frag/*view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 0.5, false, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec3 color = surf_color;
|
||||
#endif
|
||||
|
||||
// tgt_color = vec4(color, 1.0);
|
||||
tgt_color = vec4(color, 1.0 - clamp((distance(focus_pos.xy, f_pos.xy) - (sprite_render_distance - FADE_DIST)) / FADE_DIST, 0, 1));
|
||||
}
|
||||
|
@ -1,62 +1,236 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <sky.glsl>
|
||||
|
||||
in vec3 v_pos;
|
||||
in uint v_col;
|
||||
in uint v_atlas_pos;
|
||||
// in uint v_col;
|
||||
in uint v_norm_ao;
|
||||
in uint inst_pos_ori;
|
||||
in vec4 inst_mat0;
|
||||
in vec4 inst_mat1;
|
||||
in vec4 inst_mat2;
|
||||
in vec4 inst_mat3;
|
||||
in vec3 inst_col;
|
||||
// in vec3 inst_col;
|
||||
in float inst_wind_sway;
|
||||
|
||||
struct SpriteLocals {
|
||||
mat4 mat;
|
||||
vec4 wind_sway;
|
||||
vec4 offs;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
mat4 mat;
|
||||
vec4 wind_sway;
|
||||
vec4 offs;
|
||||
// SpriteLocals sprites[8];
|
||||
};
|
||||
|
||||
// struct Instance {
|
||||
// mat4 inst_mat;
|
||||
// vec3 inst_col;
|
||||
// float inst_wind_sway;
|
||||
// };
|
||||
//
|
||||
// layout (std140)
|
||||
// uniform u_ibuf {
|
||||
// Instance sprite_instances[/*MAX_LAYER_FACES*/512];
|
||||
// };
|
||||
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
layout (std140)
|
||||
uniform u_terrain_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
out vec3 f_pos;
|
||||
flat out vec3 f_norm;
|
||||
out vec3 f_col;
|
||||
out float f_ao;
|
||||
out float f_light;
|
||||
flat out float f_light;
|
||||
// flat out vec3 f_pos_norm;
|
||||
// out vec3 f_col;
|
||||
// out float f_ao;
|
||||
out vec2 f_uv_pos;
|
||||
// flat out uint f_atlas_pos;
|
||||
// out vec3 light_pos[2];
|
||||
// out float f_light;
|
||||
|
||||
const float SCALE = 1.0 / 11.0;
|
||||
const float SCALE_FACTOR = pow(SCALE, 1.3) * 0.2;
|
||||
|
||||
const int EXTRA_NEG_Z = 32768;
|
||||
|
||||
void main() {
|
||||
mat4 inst_mat;
|
||||
inst_mat[0] = inst_mat0;
|
||||
inst_mat[1] = inst_mat1;
|
||||
inst_mat[2] = inst_mat2;
|
||||
inst_mat[3] = inst_mat3;
|
||||
// vec3 inst_chunk_pos = vec3(ivec3((uvec3(inst_pos_ori) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
// uint inst_ori = (inst_pos_ori >> 29) & 0x7u;
|
||||
// SpriteLocals locals = sprites[inst_ori];
|
||||
// SpriteLocals locals = sprites;
|
||||
// mat4 inst_mat = locals.mat;
|
||||
// float inst_wind_sway = locals.wind_sway.w;
|
||||
|
||||
vec3 sprite_pos = (inst_mat * vec4(0, 0, 0, 1)).xyz;
|
||||
// mat4 inst_mat = mat4(vec4(1, 0, 0, 0), vec4(0, 1, 0, 0), vec4(0, 0, 1, 0), vec4(5.5, 5.5, 0, 1));
|
||||
// float inst_wind_sway = 0.0;
|
||||
mat4 inst_mat;
|
||||
inst_mat[0] = inst_mat0;
|
||||
inst_mat[1] = inst_mat1;
|
||||
inst_mat[2] = inst_mat2;
|
||||
inst_mat[3] = inst_mat3;
|
||||
/* Instance instances = sprite_instances[gl_InstanceID & 1023];
|
||||
mat4 inst_mat = instances.inst_mat;
|
||||
vec3 inst_col = instances.inst_col;
|
||||
float inst_wind_sway = instances.inst_wind_sway; */
|
||||
vec3 inst_offs = model_offs - focus_off.xyz;
|
||||
// mat3 inst_mat;
|
||||
// inst_mat[0] = inst_mat0.xyz;
|
||||
// inst_mat[1] = inst_mat1.xyz;
|
||||
// inst_mat[2] = inst_mat2.xyz;
|
||||
// /* Instance instances = sprite_instances[gl_InstanceID & 1023];
|
||||
// mat4 inst_mat = instances.inst_mat;
|
||||
// vec3 inst_col = instances.inst_col;
|
||||
// float inst_wind_sway = instances.inst_wind_sway; */
|
||||
// float inst_wind_sway = wind_sway.w;
|
||||
// vec3 inst_offs = model_offs - focus_off.xyz;
|
||||
|
||||
f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz;
|
||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||
// vec3 sprite_pos = floor(inst_mat3.xyz * SCALE) + inst_offs;
|
||||
|
||||
// Wind waving
|
||||
f_pos += inst_wind_sway * vec3(
|
||||
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
||||
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
||||
0.0
|
||||
) * pow(abs(v_pos.z) * SCALE, 1.3) * 0.2;
|
||||
// f_pos_norm = v_pos;
|
||||
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
f_norm = (inst_mat * vec4(normals[(v_norm_ao >> 0) & 0x7u], 0)).xyz;
|
||||
// vec3 sprite_pos = (inst_mat * vec4(0, 0, 0, 1)).xyz;
|
||||
// vec3 sprite_pos = floor((inst_mat * vec4(0, 0, 0, 1)).xyz * SCALE/* - vec3(0.5, 0.5, 0.0)*/) + inst_offs;
|
||||
// vec3 sprite_pos = /*round*/floor(((inst_mat * vec4(0, 0, 0, 1)).xyz - /* wind_sway.xyz * */offs.xyz) * SCALE/* - vec3(0.5, 0.5, 0.0)*/) - inst_offs;
|
||||
// vec3 sprite_pos = /*round*/floor(((inst_mat * vec4(-offs.xyz, 1)).xyz) * SCALE/* - vec3(0.5, 0.5, 0.0)*/) + inst_offs;
|
||||
|
||||
vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0;
|
||||
f_col = srgb_to_linear(col) * srgb_to_linear(inst_col);
|
||||
f_ao = float((v_norm_ao >> 3) & 0x3u) / 4.0;
|
||||
// vec3 v_pos = vec3(gl_VertexID * 32, gl_VertexID % 32, 1.0);
|
||||
// f_pos = v_pos + (model_offs - focus_off.xyz);
|
||||
|
||||
// Select glowing
|
||||
if (select_pos.w > 0 && select_pos.xyz == floor(sprite_pos)) {
|
||||
f_col *= 8.0;
|
||||
}
|
||||
// vec3 v_pos = /*inst_mat*//*locals.*/wind_sway.xyz * v_pos;
|
||||
vec3 v_pos_ = /*inst_mat*//*locals.*//*sprites[0].*/wind_sway.xyz * v_pos;
|
||||
// vec3 v_pos = (/*inst_mat*/locals.mat * vec4(v_pos, 1)).xyz + vec3(0.5, 0.5, 0.0);
|
||||
// f_pos = v_pos * SCALE + (inst_chunk_pos + model_offs - focus_off.xyz);
|
||||
|
||||
f_light = 1.0;
|
||||
// vec3 v_pos_ = (inst_mat * vec4(v_pos/* * SCALE*/, 1)).xyz;
|
||||
// vec3 v_pos = (inst_mat * vec4(v_pos, 1)).xyz;
|
||||
// f_pos = v_pos + (model_offs - focus_off.xyz);
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
f_pos = (inst_mat * vec4(v_pos_, 1.0)).xyz * SCALE + inst_offs;
|
||||
// f_pos = (inst_mat * v_pos_) * SCALE + sprite_pos;
|
||||
|
||||
// f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz + (model_offs - focus_off.xyz);
|
||||
// f_pos = v_pos_ + (inst_chunk_pos + model_offs - focus_off.xyz + vec3(0.5, 0.5, 0.0));
|
||||
// f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0));
|
||||
|
||||
// Wind waving
|
||||
/* const float x_scale = sin(tick.x * 1.5 + f_pos.x * 0.1);
|
||||
const float y_scale = sin(tick.x * 1.5 + f_pos.y * 0.1);
|
||||
const float z_scale = pow(abs(v_pos_.z), 1.3) * SCALE_FACTOR;
|
||||
const float xy_bias = sin(tick.x * 0.25);
|
||||
const float z_bias = xy_bias * t_scale;
|
||||
mat3 shear = mat4(
|
||||
vec3(x_scale , 0.0, 0.0, 0.0),
|
||||
vec3(0.0, y_scale, 0.0, 0.0),
|
||||
vec3(0.0, 0.0, z_bias, 0.0),
|
||||
vec3(0.0, 0.0, (1.0 / z_bias), 0.0)
|
||||
); */
|
||||
// const float x_scale = sin(tick.x * 1.5 + f_pos.x * 0.1);
|
||||
// const float y_scale = sin(tick.x * 1.5 + f_pos.y * 0.1);
|
||||
// const float z_scale = pow(abs(v_pos_.z), 1.3) * SCALE_FACTOR;
|
||||
// const float xy_bias = sin(tick.x * 0.25);
|
||||
// const float z_bias = xy_bias * t_scale;
|
||||
// vec3 rotate = inst_wind_sway * vec3(
|
||||
// sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
||||
// sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
||||
// 0.0
|
||||
// ) * pow(abs(v_pos_.z/* + sprites[0].offs.z*/)/* * SCALE*/, 1.3) * /*0.2;*/SCALE_FACTOR;
|
||||
//
|
||||
// mat3 shear = mat4(
|
||||
// vec3(x_scale * , 0.0, 0.0, 0.0),
|
||||
// vec3(0.0, y_scale, 0.0, 0.0),
|
||||
// vec3(0.0, 0.0, z_bias, 0.0),
|
||||
// vec3(0.0, 0.0, (1.0 / z_bias), 0.0)
|
||||
// );
|
||||
/*if (wind_sway.w >= 0.4) */{
|
||||
f_pos += /*inst_wind_sway*/wind_sway.w * vec3(
|
||||
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
||||
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
||||
0.0
|
||||
) * pow(abs(v_pos_.z/* + sprites[0].offs.z*/)/* * SCALE*/, 1.3) * /*0.2;*/SCALE_FACTOR;
|
||||
}
|
||||
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
// vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
// uint norm_idx = (v_norm_ao >> 0) & 0x7u;
|
||||
// f_norm = (inst_mat * vec4(normals[], 0)).xyz;
|
||||
|
||||
// TODO: Consider adding a second, already-normalized (i.e. unscaled) matrix.
|
||||
// vec3 norm = /*normalize*/(inst_mat/*locals.mat*/[(v_norm_ao >> 1u) & 3u].xyz);
|
||||
// vec3 norm = /*normalize*/(inst_mat/*locals.mat*/[(v_norm_ao >> 1u) & 3u]);
|
||||
|
||||
// vec3 norm = bone_data.normals_mat[axis_idx].xyz;
|
||||
// norm = normalize(norm);
|
||||
// norm = norm / SCALE_FACTOR / locals.wind_sway.xyz;
|
||||
// norm = norm / (norm.x + norm.y + norm.z);
|
||||
// vec3 norm = norm_mat * vec4(uvec3(1 << axis_idx) & uvec3(0x1u, 0x3u, 0x7u), 1);
|
||||
|
||||
// // Calculate normal here rather than for each pixel in the fragment shader
|
||||
// f_norm = normalize((
|
||||
// combined_mat *
|
||||
// vec4(norm, 0)
|
||||
// ).xyz);
|
||||
|
||||
vec3 norm = /*normalize*/(inst_mat/*locals.mat*/[(v_norm_ao >> 1u) & 3u].xyz);
|
||||
f_norm = mix(-norm, norm, v_norm_ao & 1u);
|
||||
|
||||
/* vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0;
|
||||
f_col = srgb_to_linear(col) * srgb_to_linear(inst_col);
|
||||
f_ao = float((v_norm_ao >> 3) & 0x3u) / 4.0; */
|
||||
f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));/* + 0.5*/;
|
||||
// f_atlas_pos = v_atlas_pos;
|
||||
/* for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
light_pos[i] = vec3(shadowMats[i].texture_mat * vec4(f_pos, 1.0));
|
||||
} */
|
||||
|
||||
// // Select glowing
|
||||
// if (select_pos.w > 0 && select_pos.xyz == floor(sprite_pos)) {
|
||||
// f_col *= 4.0;
|
||||
// }
|
||||
// f_light = 1.0;
|
||||
// if (select_pos.w > 0) */{
|
||||
vec3 sprite_pos = /*round*/floor(((inst_mat * vec4(-offs.xyz, 1)).xyz) * SCALE/* - vec3(0.5, 0.5, 0.0)*/) + inst_offs;
|
||||
f_light = (select_pos.w > 0 && select_pos.xyz == sprite_pos/* - vec3(0.5, 0.5, 0.0) * SCALE*/) ? 1.0 / PERSISTENT_AMBIANCE : 1.0;
|
||||
// }
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
// gl_Position.z = -gl_Position.z;
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
|
@ -1,69 +1,373 @@
|
||||
#version 330 core
|
||||
// #extension GL_ARB_texture_storage : require
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <random.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
in vec3 f_chunk_pos;
|
||||
// in float f_ao;
|
||||
// in vec3 f_chunk_pos;
|
||||
// #ifdef FLUID_MODE_SHINY
|
||||
flat in uint f_pos_norm;
|
||||
in vec3 f_col;
|
||||
in float f_light;
|
||||
in float f_ao;
|
||||
// #else
|
||||
// const uint f_pos_norm = 0u;
|
||||
// #endif
|
||||
// in float f_alt;
|
||||
// in vec4 f_shadow;
|
||||
// in vec3 f_col;
|
||||
// in float f_light;
|
||||
/*centroid */in vec2 f_uv_pos;
|
||||
// in vec3 light_pos[2];
|
||||
// const vec3 light_pos[6] = vec3[](vec3(0), vec3(0), vec3(00), vec3(0), vec3(0), vec3(0));
|
||||
|
||||
/* #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
in vec4 sun_pos;
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
const vec4 sun_pos = vec4(0.0);
|
||||
#endif */
|
||||
|
||||
uniform sampler2D t_col_light;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
|
||||
float vmax(vec3 v) {
|
||||
return max(v.x, max(v.y, v.z));
|
||||
}
|
||||
#include <lod.glsl>
|
||||
|
||||
void main() {
|
||||
// discard;
|
||||
// vec4 f_col_light = textureGrad(t_col_light, f_uv_pos / texSize, 0.25, 0.25);
|
||||
// vec4 f_col_light = texture(t_col_light, (f_uv_pos) / texSize);
|
||||
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
const vec3 normals[8] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1), vec3(0,0,0), vec3(0,0,0));
|
||||
|
||||
// uint norm_index = (f_pos_norm >> 29) & 0x7u;
|
||||
// vec2 uv_delta = (norm_index & 0u) == 0u ? vec2(-1.0) : vec2(0);
|
||||
|
||||
vec2 f_uv_pos = f_uv_pos + atlas_offs.xy;
|
||||
// vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize);
|
||||
// float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
vec4 f_col_light = texelFetch(t_col_light, ivec2(f_uv_pos)/* + uv_delta*//* - f_norm * 0.00001*/, 0);
|
||||
// float f_light = f_col_light.a;
|
||||
// vec4 f_col_light = texelFetch(t_col_light, ivec2(int(f_uv_pos.x), int(f_uv_pos.y)/* + uv_delta*//* - f_norm * 0.00001*/), 0);
|
||||
vec3 f_col = /*linear_to_srgb*//*srgb_to_linear*/(f_col_light.rgb);
|
||||
// vec3 f_col = vec3(1.0);
|
||||
float f_light = texture(t_col_light, (f_uv_pos + 0.5) / textureSize(t_col_light, 0)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// vec2 texSize = textureSize(t_col_light, 0);
|
||||
// float f_light = texture(t_col_light, f_uv_pos/* + vec2(atlas_offs.xy)*/).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// float f_light = textureProj(t_col_light, vec3(f_uv_pos/* + vec2(atlas_offs.xy)*/, texSize.x)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// float f_light = textureProjLod(t_col_light, vec3(f_uv_pos/* + vec2(atlas_offs.xy)*/, texSize.x), 0).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// float f_light = textureGrad(t_col_light, (f_uv_pos + 0.5) / texSize, vec2(0.1, 0.0), vec2(0.0, 0.1)).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// f_light = sqrt(f_light);
|
||||
// f_light = sqrt(f_light);
|
||||
// f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0;
|
||||
// vec3 f_col = light_col.rgb;//vec4(1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
// float f_ao = 1.0;
|
||||
|
||||
// vec3 my_chunk_pos = vec3(ivec3((uvec3(f_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)));
|
||||
// tgt_color = vec4(hash(floor(vec4(my_chunk_pos.x, 0, 0, 0))), hash(floor(vec4(0, my_chunk_pos.y, 0, 1))), hash(floor(vec4(0, 0, my_chunk_pos.z, 2))), 1.0);
|
||||
// tgt_color.rgb *= f_light;
|
||||
// tgt_color = vec4(vec3(f_light), 1.0);
|
||||
// tgt_color = vec4(f_col, 1.0);
|
||||
// return;
|
||||
// vec4 light_pos[2];
|
||||
// vec4 light_col = vec4(
|
||||
// hash(floor(vec4(f_pos.x, 0, 0, 0))),
|
||||
// hash(floor(vec4(0, f_pos.y, 0, 1))),
|
||||
// hash(floor(vec4(0, 0, f_pos.z, 2))),
|
||||
// 1.0
|
||||
// );
|
||||
// vec3 f_col = light_col.rgb;//vec4(1.0, 0.0, 0.0, 1.0);
|
||||
// tgt_color = vec4(f_col, 1.0);
|
||||
// tgt_color = vec4(light_shadow_count.x <= 31u ? f_col : vec3(0.0), 1.0);
|
||||
// tgt_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
// float sum = 0.0;
|
||||
// for (uint i = 0u; i < /* 6 * */light_shadow_count.x; i ++) {
|
||||
// // uint i = 1u;
|
||||
// Light L = lights[i/* / 6*/];
|
||||
|
||||
// /* vec4 light_col = vec4(
|
||||
// hash(vec4(1.0, 0.0, 0.0, i)),
|
||||
// hash(vec4(1.0, 1.0, 0.0, i)),
|
||||
// hash(vec4(1.0, 0.0, 1.0, i)),
|
||||
// 1.0
|
||||
// ); */
|
||||
// vec3 light_col = vec3(1.0);//L.light_col.rgb;
|
||||
// float light_strength = L.light_col.a / 255.0;
|
||||
// // float light_strength = 1.0 / light_shadow_count.x;
|
||||
|
||||
// vec3 light_pos = L.light_pos.xyz;
|
||||
|
||||
// // Pre-calculate difference between light and fragment
|
||||
// vec3 fragToLight = f_pos - light_pos;
|
||||
|
||||
// // vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u];
|
||||
|
||||
// // use the light to fragment vector to sample from the depth map
|
||||
// float bias = 0.0;//0.05;//0.05;
|
||||
// // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, i)/*, 0.0*//*, bias*/).r;
|
||||
// // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, i + 1)/*, bias*/).r;
|
||||
// float currentDepth = VectorToDepth(fragToLight) + bias;
|
||||
// float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).r;
|
||||
//
|
||||
// // float visibility = texture(t_shadow_maps, vec4(fragToLight, i + 1), -(length(fragToLight) - bias)/* / screen_res.w*/);
|
||||
// // it is currently in linear range between [0,1]. Re-transform back to original value
|
||||
// // closestDepth *= screen_res.w; // far plane
|
||||
// // now test for shadows
|
||||
// // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0;
|
||||
// // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
|
||||
|
||||
// // tgt_color += light_col * vec4(vec3(/*closestDepth*/visibility/* + bias*//* / screen_res.w */) * 1.0 / light_shadow_count.x, 0.0);
|
||||
// // tgt_color.rgb += light_col * vec3(closestDepth + 0.05 / screen_res.w) * 1.0 /*/ light_shadow_count.x*/ * light_strength;
|
||||
// tgt_color.rgb += light_col * vec3(closestDepth) * 1.0 / screen_res.w /*/ light_shadow_count.x*/ * light_strength;
|
||||
// sum += light_strength;
|
||||
// }
|
||||
|
||||
// TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction.
|
||||
uint norm_axis = (f_pos_norm >> 30) & 0x3u;
|
||||
// Increase array access by 3 to access positive values
|
||||
uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
|
||||
// uint norm_axis = (f_pos_norm >> 30) & 0x3u;
|
||||
// // Increase array access by 3 to access positive values
|
||||
// uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
|
||||
// Use an array to avoid conditional branching
|
||||
// uint norm_index = (f_pos_norm >> 29) & 0x7u;
|
||||
// vec3 f_norm = normals[norm_index];
|
||||
vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u];
|
||||
// vec3 du = dFdx(f_pos);
|
||||
// vec3 dv = dFdy(f_pos);
|
||||
// vec3 f_norm = normalize(cross(du, dv));
|
||||
|
||||
float ao = pow(f_ao, 0.5) * 0.9 + 0.1;
|
||||
// /* if (light_shadow_count.x == 1) {
|
||||
// tgt_color.rgb = vec3(0.0);
|
||||
// } */
|
||||
// if (sum > 0.0) {
|
||||
// tgt_color.rgb /= sum;
|
||||
// }
|
||||
// return;
|
||||
// Whether this face is facing fluid or not.
|
||||
bool faces_fluid = bool((f_pos_norm >> 28) & 0x1u);
|
||||
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
diffuse_light *= point_shadow;
|
||||
ambient_light *= point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
ambient_light *= f_light * ao;
|
||||
diffuse_light *= f_light * ao;
|
||||
diffuse_light += point_light * ao;
|
||||
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
|
||||
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
// vec3 view_dir = normalize(f_pos - cam_pos.xyz);
|
||||
|
||||
vec3 col = f_col + hash(vec4(floor(f_chunk_pos * 3.0 - f_norm * 0.5), 0)) * 0.02; // Small-scale noise
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
vec3 moon_dir = get_moon_dir(time_of_day.x); */
|
||||
|
||||
// Select glowing
|
||||
if (select_pos.w > 0 && select_pos.xyz == floor(f_pos - f_norm * 0.01)) {
|
||||
if (vmax(abs(mod(f_pos - f_norm * 0.5, 1.0) - 0.5)) > 0.45) {
|
||||
col *= 0.5;
|
||||
}
|
||||
}
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
float f_alt = f_pos.z;
|
||||
#endif
|
||||
|
||||
vec3 surf_color = illuminate(srgb_to_linear(col), light, diffuse_light, ambient_light);
|
||||
float alpha = 1.0;//0.0001;//1.0;
|
||||
// TODO: Possibly angle with water surface into account? Since we can basically assume it's horizontal.
|
||||
const float n2 = 1.5;//1.01;
|
||||
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
|
||||
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
|
||||
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
|
||||
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
|
||||
// float faces_fluid = faces_fluid && f_pos.z <= floor(f_alt);
|
||||
float fluid_alt = max(f_pos.z + 1, floor(f_alt));
|
||||
float R_s = /*(f_pos.z < f_alt)*/faces_fluid /*&& f_pos.z <= fluid_alt*/ ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
|
||||
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
// vec3 surf_color = /*srgb_to_linear*/(f_col);
|
||||
vec3 k_a = vec3(1.0);
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
// float sun_light = get_sun_brightness(sun_dir);
|
||||
// float moon_light = get_moon_brightness(moon_dir);
|
||||
/* float sun_shade_frac = horizon_at(f_pos, sun_dir);
|
||||
float moon_shade_frac = horizon_at(f_pos, moon_dir); */
|
||||
// float f_alt = alt_at(f_pos.xy);
|
||||
// vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
float sun_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
|
||||
#endif
|
||||
float moon_shade_frac = 1.0;//horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
|
||||
// Globbal illumination "estimate" used to light the faces of voxels which are parallel to the sun or moon (which is a very common occurrence).
|
||||
// Will be attenuated by k_d, which is assumed to carry any additional ambient occlusion information (e.g. about shadowing).
|
||||
// float ambient_sides = clamp(mix(0.5, 0.0, abs(dot(-f_norm, sun_dir)) * 10000.0), 0.0, 0.5);
|
||||
// NOTE: current assumption is that moon and sun shouldn't be out at the sae time.
|
||||
// This assumption is (or can at least easily be) wrong, but if we pretend it's true we avoids having to explicitly pass in a separate shadow
|
||||
// for the sun and moon (since they have different brightnesses / colors so the shadows shouldn't attenuate equally).
|
||||
// float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
|
||||
|
||||
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
|
||||
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac/*, light_pos*/);
|
||||
|
||||
float max_light = 0.0;
|
||||
|
||||
// After shadows are computed, we use a refracted sun and moon direction.
|
||||
// sun_dir = faces_fluid && sun_shade_frac > 0.0 ? refract(sun_dir/*-view_dir*/, vec3(0.0, 0.0, 1.0), 1.0 / 1.3325) : sun_dir;
|
||||
// moon_dir = faces_fluid && moon_shade_frac > 0.0 ? refract(moon_dir/*-view_dir*/, vec3(0.0, 0.0, 1.0), 1.0 / 1.3325) : moon_dir;
|
||||
|
||||
// Compute attenuation due to water from the camera.
|
||||
vec3 mu = faces_fluid/* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0);
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation =
|
||||
medium.x == 1u ? compute_attenuation_point(cam_pos.xyz, view_dir, MU_WATER, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos)
|
||||
: compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz);
|
||||
|
||||
// Computing light attenuation from water.
|
||||
vec3 emitted_light, reflected_light;
|
||||
// To account for prior saturation
|
||||
/*float */f_light = faces_fluid ? 1.0 : f_light * sqrt(f_light);
|
||||
|
||||
emitted_light = vec3(1.0);
|
||||
reflected_light = vec3(1.0);
|
||||
float f_select = (select_pos.w > 0 && select_pos.xyz == floor(f_pos - f_norm * 0.5)) ? 1.0 / PERSISTENT_AMBIANCE : 1.0;
|
||||
max_light += get_sun_diffuse2(/*time_of_day.x, */sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a * f_select/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
|
||||
// emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
|
||||
// reflected_light *= f_light * point_shadow * shade_frac;
|
||||
// max_light *= f_light * point_shadow * shade_frac;
|
||||
emitted_light *= f_light;
|
||||
reflected_light *= f_light;
|
||||
max_light *= f_light;
|
||||
|
||||
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light);
|
||||
|
||||
// float f_ao = 1.0;
|
||||
|
||||
// float ao = /*pow(f_ao, 0.5)*/f_ao * 0.9 + 0.1;
|
||||
// emitted_light *= ao;
|
||||
// reflected_light *= ao;
|
||||
/* vec3 point_light = light_at(f_pos, f_norm);
|
||||
emitted_light += point_light;
|
||||
reflected_light += point_light; */
|
||||
|
||||
// float point_shadow = shadow_at(f_pos, f_norm);
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// vec3 light, diffuse_light, ambient_light;
|
||||
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, cam_to_frag, k_a * f_light, k_d * f_light, k_s * f_light, alpha, emitted_light, reflected_light);
|
||||
// get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
// float point_shadow = shadow_at(f_pos, f_norm);
|
||||
// diffuse_light *= f_light * point_shadow;
|
||||
// ambient_light *= f_light * point_shadow;
|
||||
// vec3 point_light = light_at(f_pos, f_norm);
|
||||
// light += point_light;
|
||||
// diffuse_light += point_light;
|
||||
// reflected_light += point_light;
|
||||
// reflected_light += light_reflection_factor(norm, cam_to_frag, , vec3 k_d, vec3 k_s, float alpha) {
|
||||
|
||||
// light_reflection_factorplight_reflection_factor
|
||||
|
||||
// vec3 surf_color = illuminate(srgb_to_linear(f_col), light, diffuse_light, ambient_light);
|
||||
vec3 f_chunk_pos = f_pos - (model_offs - focus_off.xyz);
|
||||
float noise = hash(vec4(floor(f_chunk_pos * 3.0 - f_norm * 0.5), 0));//0.005/* - 0.01*/;
|
||||
|
||||
//vec3 srgb_to_linear(vec3 srgb) {
|
||||
// bvec3 cutoff = lessThan(srgb, vec3(0.04045));
|
||||
// vec3 higher = pow((srgb + vec3(0.055))/vec3(1.055), vec3(2.4));
|
||||
// vec3 lower = srgb/vec3(12.92);
|
||||
//
|
||||
// return mix(higher, lower, cutoff);
|
||||
//}
|
||||
//
|
||||
//vec3 linear_to_srgb(vec3 col) {
|
||||
// // bvec3 cutoff = lessThan(col, vec3(0.0060));
|
||||
// // return mix(11.500726 * col, , cutoff);
|
||||
// vec3 s1 = vec3(sqrt(col.r), sqrt(col.g), sqrt(col.b));
|
||||
// vec3 s2 = vec3(sqrt(s1.r), sqrt(s1.g), sqrt(s1.b));
|
||||
// vec3 s3 = vec3(sqrt(s2.r), sqrt(s2.g), sqrt(s2.b));
|
||||
// return vec3(
|
||||
// mix(11.500726 * col.r, (0.585122381 * s1.r + 0.783140355 * s2.r - 0.368262736 * s3.r), clamp((col.r - 0.0060) * 10000.0, 0.0, 1.0)),
|
||||
// mix(11.500726 * col.g, (0.585122381 * s1.g + 0.783140355 * s2.g - 0.368262736 * s3.g), clamp((col.g - 0.0060) * 10000.0, 0.0, 1.0)),
|
||||
// mix(11.500726 * col.b, (0.585122381 * s1.b + 0.783140355 * s2.b - 0.368262736 * s3.b), clamp((col.b - 0.0060) * 10000.0, 0.0, 1.0))
|
||||
// );
|
||||
//
|
||||
// 11.500726
|
||||
//}
|
||||
// vec3 noise_delta = vec3(noise * 0.005);
|
||||
// vec3 noise_delta = noise * 0.02 * (1.0 - vec3(0.2126, 0.7152, 0.0722));
|
||||
// vec3 noise_delta = noise * 0.002 / vec3(0.2126, 0.7152, 0.0722);
|
||||
// vec3 noise_delta = sqrt(f_col) + noise;
|
||||
/* vec3 noise_delta = f_col + noise * 0.02;
|
||||
noise_delta *= noise_delta;
|
||||
noise_delta -= f_col; */
|
||||
// vec3 noise_delta = (1.0 - f_col) * 0.02 * noise * noise;
|
||||
//
|
||||
// a = 0.055
|
||||
//
|
||||
// 1 / (1 + a) = 1 / (1 + 0.055) ~ 0.947867299
|
||||
//
|
||||
// l2s = x^(1/2.4) * (1 / (1 + a)) - a + c
|
||||
// s2l = (l + a)^2.4 * (1 / (1 + a))^2.4
|
||||
// = ((x^(1/2.4) * (1 / (1 + a)) - a + c) + a)^2.4 * (1 / (1 + a))^2.4
|
||||
// = (x^(1/2.4) * (1 / (1 + a)) + c)^2.4 * (1 / (1 + a))^2.4
|
||||
//
|
||||
// ~ (x^(1/2) * 1 / (1 + a) + c)^2 * (1 / (1 + a))^2
|
||||
//
|
||||
// = ((x + a)^2.4 * (1 / (1 + a))^2.4 + c)^(1/2.4) * (1 / (1 + a))^(1/2.4)
|
||||
// = (((x + a)^2.4 + c * (1 + a)^2.4) * (1 / (1 + a))^2.4)^(1/2.4) * (1 / (1 + a))^(1/2.4)
|
||||
// = ((x + a)^2.4 + c * (1 + a)^2.4)^(1/2.4) * ((1 / (1 + a))^2.4)^(1/2.4) * (1 / (1 + a))^(1/2.4)
|
||||
// = ((x + a)^2.4 + c * (1 + a)^2.4)^(1/2.4) * (1 / (1 + a))^(1/2.4)
|
||||
//
|
||||
// = ((x + a)^2 + c * (1 + a)^2)^(1/2) * (1 / (1 + a))^(1/2)
|
||||
// = (x^2 + a^2 + 2xa + c + ca^2 + 2ac)^(1/2) * (1 / (1 + a))^(1/2)
|
||||
//
|
||||
const float A = 0.055;
|
||||
const float W_INV = 1 / (1 + A);
|
||||
const float W_2 = W_INV * W_INV;//pow(W_INV, 2.4);
|
||||
const float NOISE_FACTOR = 0.02;//pow(0.02, 1.2);
|
||||
vec3 noise_delta = (sqrt(f_col) * W_INV + noise * NOISE_FACTOR);
|
||||
// noise_delta = noise_delta * noise_delta * W_2 - f_col;
|
||||
// lum = W ⋅ col
|
||||
// lum + noise = W ⋅ (col + delta)
|
||||
// W ⋅ col + noise = W ⋅ col + W ⋅ delta
|
||||
// noise = W ⋅ delta
|
||||
// delta = noise / W
|
||||
// vec3 col = (f_col + noise_delta);
|
||||
vec3 col = noise_delta * noise_delta * W_2;
|
||||
// vec3 col = srgb_to_linear(linear_to_srgb(f_col) + noise * 0.02);
|
||||
// vec3 col = /*srgb_to_linear*/(f_col + noise); // Small-scale noise
|
||||
// vec3 col = /*srgb_to_linear*/(f_col + hash(vec4(floor(f_pos * 3.0 - f_norm * 0.5), 0)) * 0.01); // Small-scale noise
|
||||
vec3 surf_color = illuminate(max_light, view_dir, col * emitted_light, col * reflected_light);
|
||||
|
||||
#if (CLOUD_MODE == CLOUD_MODE_REGULAR)
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 1.0, true, clouds);
|
||||
vec3 fog_color = get_sky_color(cam_to_frag/*view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 1.0, false, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
#elif (CLOUD_MODE == CLOUD_MODE_NONE)
|
||||
vec3 color = surf_color;
|
||||
#endif
|
||||
|
||||
tgt_color = vec4(color, 1.0);
|
||||
}
|
||||
|
@ -1,42 +1,171 @@
|
||||
#version 330 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
// #define HAS_SHADOW_MAPS
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <lod.glsl>
|
||||
#include <shadows.glsl>
|
||||
|
||||
|
||||
in uint v_pos_norm;
|
||||
in uint v_col_light;
|
||||
// in uint v_col_light;
|
||||
in uint v_atlas_pos;
|
||||
|
||||
layout (std140)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
out vec3 f_pos;
|
||||
out vec3 f_chunk_pos;
|
||||
flat out uint f_pos_norm;
|
||||
out vec3 f_col;
|
||||
out float f_light;
|
||||
out float f_ao;
|
||||
//struct ShadowLocals {
|
||||
// mat4 shadowMatrices;
|
||||
// mat4 texture_mat;
|
||||
//};
|
||||
//
|
||||
//layout (std140)
|
||||
//uniform u_light_shadows {
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
//};
|
||||
|
||||
const int EXTRA_NEG_Z = 65536;
|
||||
out vec3 f_pos;
|
||||
// #ifdef FLUID_MODE_SHINY
|
||||
flat out uint f_pos_norm;
|
||||
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// out vec4 sun_pos;
|
||||
// #endif
|
||||
|
||||
// #endif
|
||||
// out float f_alt;
|
||||
// out vec4 f_shadow;
|
||||
// out vec3 f_col;
|
||||
// out vec3 f_chunk_pos;
|
||||
// out float f_ao;
|
||||
/*centroid */out vec2 f_uv_pos;
|
||||
// out vec3 light_pos[2];
|
||||
// out float f_light;
|
||||
|
||||
// uniform sampler2DRect t_col_light;
|
||||
|
||||
const int EXTRA_NEG_Z = 32768;
|
||||
|
||||
void main() {
|
||||
f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0x1FFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
f_pos = f_chunk_pos + model_offs;
|
||||
// over it (if this vertex to see if it intersects.
|
||||
// f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
vec3 f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
|
||||
f_pos = f_chunk_pos + model_offs - focus_off.xyz;
|
||||
|
||||
f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
|
||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||
// f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
|
||||
// f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0));
|
||||
|
||||
f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0;
|
||||
// vec3 light_col = vec3(
|
||||
// hash(floor(vec4(f_chunk_pos.x, 0, 0, 0))),
|
||||
// hash(floor(vec4(0, f_chunk_pos.y, 0, 1))),
|
||||
// hash(floor(vec4(0, 0, f_chunk_pos.z, 2)))
|
||||
// );
|
||||
|
||||
f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
f_ao = float((v_col_light >> 6u) & 3u) / 4.0;
|
||||
// f_col = light_col;// f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0;
|
||||
// f_light = 1.0;//float(v_col_light & 0x3Fu) / 64.0;
|
||||
// f_ao = 1.0;//float((v_col_light >> 6u) & 3u) / 4.0;
|
||||
// f_col = f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0;
|
||||
// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||
// f_ao = float((v_col_light >> 6u) & 3u) / 4.0;
|
||||
|
||||
// for (uint i = 0u; i < 1u/*light_shadow_count.z*/; ++i) {
|
||||
// light_pos[i] = vec3(shadowMats[i].texture_mat * vec4(f_pos, 1.0));
|
||||
// }
|
||||
// vec2 texSize = textureSize(t_col_light, 0);
|
||||
f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));
|
||||
|
||||
// #if (SHADOW_MODE == SHADOW_MODE_MAP)
|
||||
// // for (uint i = 0u; i < light_shadow_count.z; ++i) {
|
||||
// // light_pos[i] = /*vec3(*/shadowMats[i].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // }
|
||||
// sun_pos = /*vec3(*/shadowMats[0].texture_mat * vec4(f_pos, 1.0)/*)*/;
|
||||
// // #elif (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_NONE)
|
||||
// // vec4 sun_pos = vec4(0.0);
|
||||
// #endif
|
||||
|
||||
// #ifdef FLUID_MODE_SHINY
|
||||
f_pos_norm = v_pos_norm;
|
||||
// #endif
|
||||
|
||||
// Also precalculate shadow texture and estimated terrain altitude.
|
||||
// f_alt = alt_at(f_pos.xy);
|
||||
// f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
|
||||
|
||||
// IDEA: Cast a ray from the vertex to the camera (if this vertex is above the camera) or from the camera to the vertex (if this
|
||||
// vertex is below the camera) to see where it intersects the plane of water. All of this only applies if either the terrain
|
||||
// vertex is in water, or the camera is in water.
|
||||
//
|
||||
// If an intersection is found, refract the ray across the barrier using the correct ratio of indices of refraction (1 / N_WATER
|
||||
// if the vertex is above the camera [ray is going from air to water], N_WATER if the camera is above the vertex
|
||||
// [ray is going from water to air]).
|
||||
//
|
||||
// In order to make sure that terrain and other objects below such an interface are properly renered, we then "un-refract" by
|
||||
// reversing the refracted vector, and multiplying that by the distance from the object from which we cast the ray to the
|
||||
// intersectng point, in order to make the object appear to the viewer where it should after refraction.
|
||||
// bool faces_fluid = bool((f_pos_norm >> 28) & 0x1u);
|
||||
// // TODO: Measure real water surface altitude here.
|
||||
// float surfaceAlt = faces_fluid ? max(ceil(f_pos.z), floor(f_alt)) : /*floor(f_alt);*/mix(view_distance.z, min(f_alt, floor(alt_at_real(cam_pos.xy))), medium.x);
|
||||
|
||||
// vec3 wRayinitial = f_pos; // cam_pos.z < f_pos.z ? f_pos : cam_pos.xyz;
|
||||
// vec3 wRayfinal = cam_pos.xyz; // cam_pos.z < f_pos.z ? cam_pos.xyz : f_pos;
|
||||
// vec3 wRayNormal = surfaceAlt < wRayinitial.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
|
||||
// float n_camera = mix(1.0, 1.3325, medium.x);
|
||||
// float n_vertex = faces_fluid ? 1.3325 : 1.0;
|
||||
// float n1 = n_vertex; // cam_pos.z < f_pos.z ? n_vertex : n_camera;
|
||||
// float n2 = n_camera; // cam_pos.z < f_pos.z ? n_camera : n_vertex;
|
||||
|
||||
// float wRayLength0 = length(wRayfinal - wRayinitial);
|
||||
// vec3 wRayDir = (wRayfinal - wRayinitial) / wRayLength0;
|
||||
// vec3 wPoint = wRayfinal;
|
||||
// bool wIntersectsSurface = IntersectRayPlane(wRayinitial, wRayDir, vec3(0.0, 0.0, surfaceAlt), -wRayNormal, wPoint);
|
||||
// float wRayLength = length(wPoint - wRayinitial);
|
||||
// wPoint = wRayLength < wRayLength0 ? wPoint : wRayfinal;
|
||||
// wRayLength = min(wRayLength, wRayLength0); // min(max_length, dot(wRayfinal - wpos, defaultpos - wpos));
|
||||
|
||||
// // vec3 wRayDir2 = (wRayfinal - wRayinitial) / wRayLength;
|
||||
|
||||
// vec3 wRayDir3 = (dot(wRayDir, wRayNormal) < 0.0 && wIntersectsSurface) ? refract(wRayDir, wRayNormal, n2 / n1) : wRayDir;
|
||||
// // wPoint -= wRayDir3 * wRayLength * n2 / n1;
|
||||
// vec3 newRay = dot(wRayDir, wRayNormal) < 0.0 && wIntersectsSurface ? wPoint - wRayDir3 * wRayLength * n2 / n1 : f_pos;// - (wRayfinal - wPoint) * n2 / n1; // wPoint + n2 * (wRayfinal - wPoint) - n2 / n1 * wRayLength * wRayDir3;
|
||||
|
||||
#ifdef HAS_SHADOW_MAPS
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
/*all_mat*/shadowMats[0].shadowMatrices/*texture_mat*/ *
|
||||
vec4(f_pos/*newRay*/, 1);
|
||||
gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w));
|
||||
#else
|
||||
gl_Position = all_mat * vec4(f_pos/*newRay*/, 1);
|
||||
#endif
|
||||
// gl_Position.y /= gl_Position.w;
|
||||
// gl_Position.w = 1.0;
|
||||
// gl_Position.z = -gl_Position.z;
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z / gl_Position.w;
|
||||
// gl_Position.z = -gl_Position.z *gl_Position.w;
|
||||
// gl_Position.z = gl_Position.z / 100.0;
|
||||
// gl_Position.z = gl_Position.z / 10000.0;
|
||||
// gl_Position.z = -gl_Position.z / 100.0;
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
// gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
||||
|
@ -22,30 +22,39 @@ out vec4 f_color;
|
||||
void main() {
|
||||
f_color = v_color;
|
||||
|
||||
// vec2 v_pos = vec2(-1.0,1.0) * v_pos;
|
||||
/* f_uv = vec2(1.0,1.0) * v_uv; */
|
||||
// vec2 v_uv = vec2(1.0,-1.0) * v_uv;
|
||||
|
||||
if (w_pos.w == 1.0) {
|
||||
f_uv = v_uv;
|
||||
// Fixed scale In-game element
|
||||
vec4 projected_pos = proj_mat * view_mat * vec4(w_pos.xyz, 1.0);
|
||||
gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos, 0.0, 1.0);
|
||||
// Fixed scale In-game element
|
||||
vec4 projected_pos = /*proj_mat * view_mat*/all_mat * vec4(w_pos.xyz - focus_off.xyz, 1.0);
|
||||
gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos/* * projected_pos.w*/, -1.0, /*projected_pos.w*/1.0);
|
||||
} else if (v_mode == uint(3)) {
|
||||
// HACK: North facing source rectangle.
|
||||
gl_Position = vec4(v_pos, -1.0, 1.0);
|
||||
vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2]));
|
||||
// TODO: Consider cleaning up matrix to something more efficient (e.g. a mat3).
|
||||
vec2 aspect_ratio = textureSize(u_tex, 0).yx;
|
||||
mat2 look_at = mat2(look_at_dir.y, look_at_dir.x, -look_at_dir.x, look_at_dir.y);
|
||||
f_uv = v_center + look_at * (v_uv - v_center);
|
||||
gl_Position = vec4(v_pos, 0.0, 1.0);
|
||||
vec2 v_centered = (v_uv - v_center) / aspect_ratio;
|
||||
vec2 v_rotated = look_at * v_centered;
|
||||
f_uv = aspect_ratio * v_rotated + v_center;
|
||||
} else if (v_mode == uint(5)) {
|
||||
// HACK: North facing target rectangle.
|
||||
f_uv = v_uv;
|
||||
float aspect_ratio = screen_res.x / screen_res.y;
|
||||
vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2]));
|
||||
// TODO: Consider cleaning up matrix to something more efficient (e.g. a mat3).
|
||||
vec2 aspect_ratio = screen_res.yx;
|
||||
mat2 look_at = mat2(look_at_dir.y, -look_at_dir.x, look_at_dir.x, look_at_dir.y);
|
||||
vec2 v_len = v_pos - v_center;
|
||||
vec2 v_proj = look_at * vec2(v_len.x, v_len.y / aspect_ratio);
|
||||
gl_Position = vec4(v_center + vec2(v_proj.x, v_proj.y * aspect_ratio), 0.0, 1.0);
|
||||
vec2 v_centered = (v_pos - v_center) / aspect_ratio;
|
||||
vec2 v_rotated = look_at * v_centered;
|
||||
gl_Position = vec4(aspect_ratio * v_rotated + v_center, -1.0, 1.0);
|
||||
} else {
|
||||
// Interface element
|
||||
f_uv = v_uv;
|
||||
gl_Position = vec4(v_pos, 0.0, 1.0);
|
||||
gl_Position = vec4(v_pos, -1.0, 1.0);
|
||||
}
|
||||
f_mode = v_mode;
|
||||
}
|
||||
|
BIN
assets/voxygen/voxel/figure/eyes/general/female_blind-0.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/figure/eyes/general/female_blind-0.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/figure/eyes/general/male_blind-0.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/figure/eyes/general/male_blind-0.vox
(Stored with Git LFS)
Binary file not shown.
285
assets/voxygen/voxel/humanoid_color_manifest.ron
Normal file
285
assets/voxygen/voxel/humanoid_color_manifest.ron
Normal file
@ -0,0 +1,285 @@
|
||||
#![enable(unwrap_newtypes)]
|
||||
|
||||
(
|
||||
// NOTE: You can't change the legnths of these arrays without updating num_hair_colors() in
|
||||
// common/src/comp/body/humanoid.rs. That's because this is a hack; we should really use enum
|
||||
// variants for hair colors like we do all the other stuff. Once we fix that, this will no
|
||||
// longer be something you need to worry about.
|
||||
hair_colors: (
|
||||
Danari: [
|
||||
(198, 169, 113), // Philosopher's Grey
|
||||
//(245, 232, 175), // Cream Blonde
|
||||
//(228, 208, 147), // Gold Blonde
|
||||
//(228, 223, 141), // Platinum Blonde
|
||||
(176, 106, 41), // Summer Blonde
|
||||
(107, 76, 51), // Oak
|
||||
//(203, 154, 98), // Light
|
||||
(64, 32, 18), // Skin7
|
||||
(86, 72, 71), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(107, 32, 60), // Grape Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
//(146, 32, 32), // Autumn Red
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
Dwarf: [
|
||||
(210, 204, 130), // Platinum Blonde
|
||||
(220, 199, 119), // Cream Blonde
|
||||
(212, 156, 73), // Gold Blonde
|
||||
(176, 106, 41), // Summer Blonde
|
||||
(216, 146, 114), // Matte Pink
|
||||
(107, 76, 51), // Oak
|
||||
(203, 154, 98), // Light
|
||||
(64, 32, 18), // Skin7
|
||||
(86, 72, 71), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(191, 228, 254), // Ice NobleBlue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(146, 166, 172), // Matte Green
|
||||
(0, 139, 58), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
Elf: [
|
||||
(66, 83, 113), // Mysterious Blue
|
||||
(13, 76, 41), // Rainforest Green
|
||||
(245, 232, 175), // Cream Blonde
|
||||
(212, 156, 73), // Gold Blonde
|
||||
(228, 223, 141), // Platinum Blonde
|
||||
(176, 106, 41), // Summer Blonde
|
||||
(107, 76, 51), // Oak
|
||||
(203, 154, 98), // Light
|
||||
(64, 32, 18), // Skin7
|
||||
(86, 72, 71), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(103, 191, 254), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(80, 156, 211), // Candy Pink
|
||||
(216, 146, 114), // Matte Pink
|
||||
(146, 166, 172), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
Human: [
|
||||
(210, 204, 130), // Platinum Blonde
|
||||
(220, 199, 119), // Cream Blonde
|
||||
(212, 156, 73), // Gold Blonde
|
||||
(176, 106, 41), // Summer Blonde
|
||||
(216, 146, 114), // Matte Pink
|
||||
(203, 200, 98), // Light
|
||||
(107, 76, 51), // Oak
|
||||
(64, 32, 18), // Skin7
|
||||
(86, 72, 81), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(114, 137, 211), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(80, 156, 211), // Candy Pink
|
||||
(146, 166, 172), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
Orc: [
|
||||
(66, 66, 59), // Wise Grey
|
||||
//(107, 76, 51), // Oak
|
||||
//(203, 154, 98), // Light
|
||||
(64, 32, 18), // Skin7
|
||||
(54, 30, 26), // Dark Skin7
|
||||
(86, 72, 71), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(66, 83, 113), // Mysterious Blue
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
Undead: [
|
||||
//(245, 232, 175), // Cream Blonde
|
||||
(228, 208, 147), // Gold Blonde
|
||||
//(228, 223, 141), // Platinum Blonde
|
||||
(176, 106, 41), // Summer Blonde
|
||||
(107, 76, 51), // Oak
|
||||
(203, 154, 98), // Light
|
||||
(64, 32, 18), // Skin7
|
||||
(86, 72, 71), // Ash
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(111, 54, 117), // Punky Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(103, 191, 254), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(66, 66, 59), // Decayed Grey
|
||||
//(80, 156, 211), // Candy Pink
|
||||
(216, 146, 114), // Matte Pink
|
||||
(0, 131, 122), // Rotten Green
|
||||
(146, 166, 172), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
],
|
||||
),
|
||||
eye_colors_light: (
|
||||
VigorousBlack: (71, 59, 49),
|
||||
NobleBlue: (75, 158, 191),
|
||||
CuriousGreen: (110, 167, 113),
|
||||
LoyalBrown: (73, 42, 36),
|
||||
ViciousRed: (169,0 ,47),
|
||||
PumpkinOrange: (220, 156, 19),
|
||||
GhastlyYellow: (221, 225, 31),
|
||||
MagicPurple: (137, 4, 177),
|
||||
ToxicGreen: (1, 223, 1),
|
||||
ExoticPurple: (95, 32, 111),
|
||||
SulfurYellow: (235, 198, 94),
|
||||
AmberOrange: (137, 46, 1),
|
||||
PineGreen: (0, 78, 56),
|
||||
CornflowerBlue: (18, 66, 90),
|
||||
),
|
||||
eye_colors_dark: (
|
||||
VigorousBlack: (32, 32, 32),
|
||||
NobleBlue: (62, 130, 159),
|
||||
CuriousGreen: (81, 124, 84),
|
||||
LoyalBrown: (54, 30, 26),
|
||||
ViciousRed: (119, 0, 33),
|
||||
PumpkinOrange: (209, 145, 18),
|
||||
GhastlyYellow: (205, 212, 29),
|
||||
MagicPurple: (110, 3, 143),
|
||||
ToxicGreen: (1, 185, 1),
|
||||
ExoticPurple: (69, 23, 80),
|
||||
SulfurYellow: (209, 176, 84),
|
||||
AmberOrange: (112, 40, 1),
|
||||
PineGreen: (0, 54, 38),
|
||||
CornflowerBlue: (13, 47, 64),
|
||||
),
|
||||
eye_white: (255, 255, 255),
|
||||
skin_colors_plain: (
|
||||
Skin1: (228, 183, 160),
|
||||
Skin2: (226, 181, 158),
|
||||
Skin3: (223, 179, 157),
|
||||
Skin4: (221, 177, 155),
|
||||
Skin5: (218, 176, 154),
|
||||
Skin6: (216, 174, 152),
|
||||
Skin7: (213, 172, 151),
|
||||
Skin8: (211, 170, 149),
|
||||
Skin9: (198, 159, 140),
|
||||
Skin10: (180, 144, 127),
|
||||
Skin11: (163, 130, 114),
|
||||
Skin12: (135, 103, 90),
|
||||
Skin13: (120, 92, 80),
|
||||
Skin14: (105, 80, 70),
|
||||
Skin15: (90, 69, 60),
|
||||
Skin16: (75, 57, 50),
|
||||
Skin17: (60, 46, 40),
|
||||
Skin18: (45, 34, 30),
|
||||
Iron: (135, 113, 95),
|
||||
Steel: (108, 94, 86),
|
||||
DanariOne: (43, 166, 224),
|
||||
DanariTwo: (40, 155, 210),
|
||||
DanariThree: (37, 143, 195),
|
||||
DanariFour: (34, 132, 181),
|
||||
ElfOne: (118, 84, 157),
|
||||
ElfTwo: (99, 114, 161),
|
||||
// ElfThree: (230, 188, 198),
|
||||
OrcOne: (61, 130, 42),
|
||||
OrcTwo: (82, 117, 36),
|
||||
OrcThree: (71, 94, 42),
|
||||
OrcFour: (97, 54, 29),
|
||||
UndeadOne: (178, 178, 178),
|
||||
UndeadTwo: (162, 157, 150),
|
||||
UndeadThree: (145, 135, 121),
|
||||
),
|
||||
skin_colors_light: (
|
||||
Skin1: (233, 190, 166),
|
||||
Skin2: (232, 188, 164),
|
||||
Skin3: (229, 186, 163),
|
||||
Skin4: (227, 184, 161),
|
||||
Skin5: (224, 183, 159),
|
||||
Skin6: (222, 181, 157),
|
||||
Skin7: (220, 178, 156),
|
||||
Skin8: (218, 176, 154),
|
||||
Skin9: (205, 165, 145),
|
||||
Skin10: (187, 149, 131),
|
||||
Skin11: (169, 134, 118),
|
||||
Skin12: (135, 103, 90),
|
||||
Skin13: (120, 92, 80),
|
||||
Skin14: (105, 80, 70),
|
||||
Skin15: (90, 69, 60),
|
||||
Skin16: (75, 57, 50),
|
||||
Skin17: (60, 46, 40),
|
||||
Skin18: (45, 34, 30),
|
||||
Iron: (144, 125, 106),
|
||||
Steel: (120, 107, 99),
|
||||
DanariOne: (44, 172, 230),
|
||||
DanariTwo: (41, 161, 217),
|
||||
DanariThree: (38, 148, 202),
|
||||
DanariFour: (35, 136, 188),
|
||||
ElfOne: (122, 87, 163),
|
||||
ElfTwo: (102, 118, 167),
|
||||
//ElfThree: (242, 199, 209),
|
||||
OrcOne: (83, 165, 56),
|
||||
OrcTwo: (92, 132, 46),
|
||||
OrcThree: (84, 110, 54),
|
||||
OrcFour: (97, 54, 29),
|
||||
UndeadOne: (185, 185, 185),
|
||||
UndeadTwo: (168, 163, 155),
|
||||
UndeadThree: (150, 139, 125),
|
||||
),
|
||||
skin_colors_dark: (
|
||||
Skin1: (222, 176, 154),
|
||||
Skin2: (220, 174, 153),
|
||||
Skin3: (217, 172, 152),
|
||||
Skin4: (214, 171, 150),
|
||||
Skin5: (211, 170, 149),
|
||||
Skin6: (209, 168, 147),
|
||||
Skin7: (206, 166, 146),
|
||||
Skin8: (204, 164, 144),
|
||||
Skin9: (191, 154, 136),
|
||||
Skin10: (173, 139, 123),
|
||||
Skin11: (157, 126, 110),
|
||||
Skin12: (132, 103, 82),
|
||||
Skin13: (107, 82, 72),
|
||||
Skin14: (92, 70, 62),
|
||||
Skin15: (77, 59, 51),
|
||||
Skin16: (61, 47, 41),
|
||||
Skin17: (48, 37, 32),
|
||||
Skin18: (33, 25, 22),
|
||||
Iron: (124, 99, 82),
|
||||
Steel: (96, 81, 72),
|
||||
DanariOne: (43, 166, 224),
|
||||
DanariTwo: (40, 155, 210),
|
||||
DanariThree: (37, 143, 195),
|
||||
DanariFour: (34, 132, 181),
|
||||
ElfOne: (114, 81, 152),
|
||||
ElfTwo: (96, 110, 155),
|
||||
//ElfThree: (217, 178, 187),
|
||||
OrcOne: (55, 114, 36),
|
||||
OrcTwo: (70, 104, 29),
|
||||
OrcThree: (60, 83, 32),
|
||||
OrcFour: (84, 47, 25),
|
||||
UndeadOne: (172, 172, 172),
|
||||
UndeadTwo: (156, 152, 145),
|
||||
UndeadThree: (128, 119, 107),
|
||||
),
|
||||
)
|
BIN
assets/voxygen/voxel/sprite/pumpkin/1.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/2.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/3.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/4.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/5.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/6.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/6.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/pumpkin/7.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/pumpkin/7.vox
(Stored with Git LFS)
Binary file not shown.
152
assets/world/style/colors.ron
Normal file
152
assets/world/style/colors.ron
Normal file
@ -0,0 +1,152 @@
|
||||
#![enable(unwrap_newtypes)]
|
||||
#![enable(implicit_some)]
|
||||
|
||||
// NOTE: Many of these colors are not used directly, but are modified in various ways (e.g. via
|
||||
// lerping). So don't be too frustrated if a color change seems to have a different effect in
|
||||
// different places; just follow the trends.
|
||||
(
|
||||
block: (
|
||||
pyramid: (203, 170, 146),
|
||||
|
||||
// These are all ranges from low to high.
|
||||
structure_blocks: (
|
||||
None: None,
|
||||
// Samples the surface color.
|
||||
Grass: None,
|
||||
// Water blocks ignore color information, and even if they didn't would not be lerped.
|
||||
Water: None,
|
||||
GreenSludge: None,
|
||||
// Leaves all actually get interpolated.
|
||||
TemperateLeaves: (start: (0, 132, 94), end: (142, 181, 0)),
|
||||
PineLeaves: (start: (0, 60, 50), end: (30, 100, 10)),
|
||||
PalmLeavesInner: (start: (61, 166, 43), end: (29, 130, 32)),
|
||||
PalmLeavesOuter: (start: (62, 171, 38), end: (45, 171, 65)),
|
||||
Acacia: (start: (15, 126, 50), end: (30, 180, 10)),
|
||||
Liana: (start: (0, 125, 107), end: (0, 155, 129)),
|
||||
Mangrove: (start: (32, 56, 22), end: (57, 69, 27)),
|
||||
)
|
||||
|
||||
// Water blocks ignore color now so this isn't used, but just in case this color was worth
|
||||
// remembering here it is.
|
||||
// green_sludge: (30.0, 126.0, 23.0)
|
||||
),
|
||||
column: (
|
||||
cold_grass: (0.0, 0.5, 0.25),
|
||||
warm_grass: (0.4, 0.8, 0.0),
|
||||
dark_grass: (0.15, 0.4, 0.1),
|
||||
wet_grass: (0.1, 0.8, 0.2),
|
||||
cold_stone: (0.57, 0.67, 0.8),
|
||||
hot_stone: (0.07, 0.07, 0.06),
|
||||
warm_stone: (0.77, 0.77, 0.64),
|
||||
beach_sand: (0.8, 0.75, 0.5),
|
||||
desert_sand: (0.7, 0.4, 0.25),
|
||||
snow: (0.8, 0.85, 1.0),
|
||||
|
||||
stone_col: (195, 187, 201),
|
||||
|
||||
dirt_low: (0.075, 0.07, 0.3),
|
||||
dirt_high: (0.75, 0.55, 0.1),
|
||||
|
||||
snow_high: (0.01, 0.3, 0.0),
|
||||
warm_stone_high: (0.3, 0.12, 0.2),
|
||||
|
||||
grass_high: (0.15, 0.2, 0.15),
|
||||
tropical_high: (0.87, 0.62, 0.56),
|
||||
),
|
||||
// NOTE: I think (but am not sure) that this is the color of stuff below the bottom-most
|
||||
// ground. I'm not sure how easy it is to see.
|
||||
deep_stone_color: (125, 120, 130),
|
||||
layer: (
|
||||
bridge: (80, 80, 100),
|
||||
stalagtite: (200, 200, 200),
|
||||
),
|
||||
site: (
|
||||
castle: (),
|
||||
dungeon: (
|
||||
stone: (150, 150, 175),
|
||||
),
|
||||
settlement: (
|
||||
building: (
|
||||
archetype: (
|
||||
keep: (
|
||||
brick_base: (80, 80, 80),
|
||||
floor_base: (80, 60, 10),
|
||||
pole: (90, 70, 50),
|
||||
flag: (
|
||||
Evil: (80, 10, 130),
|
||||
Good: (200, 80, 40),
|
||||
),
|
||||
stone: (
|
||||
Evil: (65, 60, 55),
|
||||
Good: (100, 100, 110),
|
||||
),
|
||||
),
|
||||
house: (
|
||||
foundation: (100, 100, 100),
|
||||
floor: (100, 75, 50),
|
||||
roof: (
|
||||
Roof1: (0x99, 0x5E, 0x54),
|
||||
Roof2: (0x43, 0x63, 0x64),
|
||||
Roof3: (0x76, 0x6D, 0x68),
|
||||
Roof4: (0x7B, 0x41, 0x61),
|
||||
Roof5: (0x52, 0x20, 0x20),
|
||||
Roof6: (0x1A, 0x4A, 0x59),
|
||||
Roof7: (0xCC, 0x76, 0x4E),
|
||||
// (0x1D, 0x4D, 0x45),
|
||||
// (0xB3, 0x7D, 0x60),
|
||||
// (0xAC, 0x5D, 0x26),
|
||||
// (0x32, 0x46, 0x6B),
|
||||
// (0x2B, 0x19, 0x0F),
|
||||
// (0x93, 0x78, 0x51),
|
||||
// (0x92, 0x57, 0x24),
|
||||
// (0x4A, 0x4E, 0x4E),
|
||||
// (0x2F, 0x32, 0x47),
|
||||
// (0x8F, 0x35, 0x43),
|
||||
// (0x6D, 0x1E, 0x3A),
|
||||
// (0x6D, 0xA7, 0x80),
|
||||
// (0x4F, 0xA0, 0x95),
|
||||
// (0xE2, 0xB9, 0x99),
|
||||
// (0x7A, 0x30, 0x22),
|
||||
// (0x4A, 0x06, 0x08),
|
||||
// (0x8E, 0xB4, 0x57),
|
||||
),
|
||||
wall: (
|
||||
Wall1: (200, 180, 150),
|
||||
Wall2: (0xB8, 0xB4, 0xA4),
|
||||
Wall3: (0x76, 0x6D, 0x68),
|
||||
Wall4: (0xF3, 0xC9, 0x8F),
|
||||
Wall5: (0xD3, 0xB7, 0x99),
|
||||
Wall6: (0xE1, 0xAB, 0x91),
|
||||
Wall7: (0x82, 0x57, 0x4C),
|
||||
Wall8: (0xB9, 0x96, 0x77),
|
||||
Wall9: (0xAE, 0x8D, 0x9C),
|
||||
),
|
||||
support: (
|
||||
Support1: (60, 45, 30),
|
||||
Support2: (0x65, 0x55, 0x56),
|
||||
Support3: (0x53, 0x33, 0x13),
|
||||
Support4: (0x58, 0x42, 0x33),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
plot_town_path: (100, 95, 65),
|
||||
|
||||
plot_field_dirt: (80, 55, 35),
|
||||
plot_field_mound: (70, 80, 30),
|
||||
|
||||
wall_low: (130, 100, 0),
|
||||
wall_high :(90, 70, 50),
|
||||
|
||||
tower_color: (50, 50, 50),
|
||||
|
||||
// NOTE: Ideally these would be part of a make_case_elim, but we can't use it beacuse
|
||||
// it doesn't support struct variants yet.
|
||||
plot_dirt: (90, 70, 50),
|
||||
plot_grass: (100, 200, 0),
|
||||
plot_water: (100, 150, 250),
|
||||
plot_town: (150, 110, 60),
|
||||
// TODO: Add field furrow stuff.
|
||||
),
|
||||
),
|
||||
)
|
BIN
assets/world/tree/acacia/1.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia/2.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia/3.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia/4.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia/4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia/5.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia_3/1.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/tree/acacia_3/1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/acacia_3/2.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/tree/acacia_3/2.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/acacia_3/3.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/tree/acacia_3/3.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/acacia_3/4.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/tree/acacia_3/4.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/acacia_3/5.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/tree/acacia_3/5.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/tree/acacia_savannah/1.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia_savannah/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia_savannah/2.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia_savannah/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia_savannah/3.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia_savannah/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia_savannah/4.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia_savannah/4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/acacia_savannah/5.vox
(Stored with Git LFS)
BIN
assets/world/tree/acacia_savannah/5.vox
(Stored with Git LFS)
Binary file not shown.
@ -13,10 +13,12 @@ uvth = "3.1.1"
|
||||
futures-util = "0.3"
|
||||
futures-executor = "0.3"
|
||||
futures-timer = "2.0"
|
||||
image = { version = "0.22.5", default-features = false, features = ["png"] }
|
||||
image = { version = "0.23.8", default-features = false, features = ["png"] }
|
||||
num = "0.2.0"
|
||||
num_cpus = "1.10.1"
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
rayon = "^1.3.0"
|
||||
specs = { git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818bad487695c66c43db88050a5" }
|
||||
vek = { version = "0.11.0", features = ["serde"] }
|
||||
vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] }
|
||||
hashbrown = { version = "0.7.2", features = ["rayon", "serde", "nightly"] }
|
||||
authc = { git = "https://gitlab.com/veloren/auth.git", rev = "b943c85e4a38f5ec60cd18c34c73097640162bfe" }
|
||||
|
@ -29,7 +29,7 @@ use common::{
|
||||
recipe::RecipeBook,
|
||||
state::State,
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize},
|
||||
terrain::{block::Block, neighbors, TerrainChunk, TerrainChunkSize},
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use futures_executor::block_on;
|
||||
@ -40,6 +40,8 @@ use image::DynamicImage;
|
||||
use network::{
|
||||
Network, Participant, Pid, ProtocolAddr, Stream, PROMISES_CONSISTENCY, PROMISES_ORDERED,
|
||||
};
|
||||
use num::traits::FloatConst;
|
||||
use rayon::prelude::*;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
net::SocketAddr,
|
||||
@ -74,7 +76,28 @@ pub struct Client {
|
||||
client_state: ClientState,
|
||||
thread_pool: ThreadPool,
|
||||
pub server_info: ServerInfo,
|
||||
pub world_map: (Arc<DynamicImage>, Vec2<u32>),
|
||||
/// Just the "base" layer for LOD; currently includes colors and nothing
|
||||
/// else. In the future we'll add more layers, like shadows, rivers, and
|
||||
/// probably foliage, cities, roads, and other structures.
|
||||
pub lod_base: Vec<u32>,
|
||||
/// The "height" layer for LOD; currently includes only land altitudes, but
|
||||
/// in the future should also water depth, and probably other
|
||||
/// information as well.
|
||||
pub lod_alt: Vec<u32>,
|
||||
/// The "shadow" layer for LOD. Includes east and west horizon angles and
|
||||
/// an approximate max occluder height, which we use to try to
|
||||
/// approximate soft and volumetric shadows.
|
||||
pub lod_horizon: Vec<u32>,
|
||||
/// A fully rendered map image for use with the map and minimap; note that
|
||||
/// this can be constructed dynamically by combining the layers of world
|
||||
/// map data (e.g. with shadow map data or river data), but at present
|
||||
/// we opt not to do this.
|
||||
///
|
||||
/// The second element of the tuple is the world size (as a 2D grid,
|
||||
/// in chunks), and the third element holds the minimum height for any land
|
||||
/// chunk (i.e. the sea level) in its x coordinate, and the maximum land
|
||||
/// height above this height (i.e. the max height) in its y coordinate.
|
||||
pub world_map: (Arc<DynamicImage>, Vec2<u16>, Vec2<f32>),
|
||||
pub player_list: HashMap<Uid, PlayerInfo>,
|
||||
pub character_list: CharacterList,
|
||||
pub active_character_id: Option<i32>,
|
||||
@ -130,84 +153,217 @@ impl Client {
|
||||
// We reduce the thread count by 1 to keep rendering smooth
|
||||
thread_pool.set_num_threads((num_cpus::get() - 1).max(1));
|
||||
|
||||
let (network, f) = Network::new(Pid::new());
|
||||
thread_pool.execute(f);
|
||||
let (network, scheduler) = Network::new(Pid::new());
|
||||
thread_pool.execute(scheduler);
|
||||
|
||||
let participant = block_on(network.connect(ProtocolAddr::Tcp(addr.into())))?;
|
||||
let mut stream = block_on(participant.open(10, PROMISES_ORDERED | PROMISES_CONSISTENCY))?;
|
||||
|
||||
// Wait for initial sync
|
||||
let (state, entity, server_info, world_map, recipe_book, max_group_size) = block_on(
|
||||
async {
|
||||
loop {
|
||||
match stream.recv().await? {
|
||||
ServerMsg::InitialSync {
|
||||
entity_package,
|
||||
server_info,
|
||||
time_of_day,
|
||||
max_group_size,
|
||||
world_map: (map_size, world_map),
|
||||
recipe_book,
|
||||
} => {
|
||||
// TODO: Display that versions don't match in Voxygen
|
||||
if server_info.git_hash != *common::util::GIT_HASH {
|
||||
warn!(
|
||||
"Server is running {}[{}], you are running {}[{}], versions \
|
||||
might be incompatible!",
|
||||
server_info.git_hash,
|
||||
server_info.git_date,
|
||||
common::util::GIT_HASH.to_string(),
|
||||
common::util::GIT_DATE.to_string(),
|
||||
let (
|
||||
state,
|
||||
entity,
|
||||
server_info,
|
||||
lod_base,
|
||||
lod_alt,
|
||||
lod_horizon,
|
||||
world_map,
|
||||
recipe_book,
|
||||
max_group_size,
|
||||
) = block_on(async {
|
||||
loop {
|
||||
match stream.recv().await? {
|
||||
ServerMsg::InitialSync {
|
||||
entity_package,
|
||||
server_info,
|
||||
time_of_day,
|
||||
max_group_size,
|
||||
world_map,
|
||||
recipe_book,
|
||||
} => {
|
||||
// TODO: Display that versions don't match in Voxygen
|
||||
if server_info.git_hash != *common::util::GIT_HASH {
|
||||
warn!(
|
||||
"Server is running {}[{}], you are running {}[{}], versions might \
|
||||
be incompatible!",
|
||||
server_info.git_hash,
|
||||
server_info.git_date,
|
||||
common::util::GIT_HASH.to_string(),
|
||||
common::util::GIT_DATE.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
debug!("Auth Server: {:?}", server_info.auth_provider);
|
||||
|
||||
// Initialize `State`
|
||||
let mut state = State::default();
|
||||
// Client-only components
|
||||
state
|
||||
.ecs_mut()
|
||||
.register::<comp::Last<comp::CharacterState>>();
|
||||
|
||||
let entity = state.ecs_mut().apply_entity_package(entity_package);
|
||||
*state.ecs_mut().write_resource() = time_of_day;
|
||||
|
||||
let map_size_lg = common::terrain::MapSizeLg::new(world_map.dimensions_lg)
|
||||
.map_err(|_| {
|
||||
Error::Other(format!(
|
||||
"Server sent bad world map dimensions: {:?}",
|
||||
world_map.dimensions_lg,
|
||||
))
|
||||
})?;
|
||||
let map_size = map_size_lg.chunks();
|
||||
let max_height = world_map.max_height;
|
||||
let sea_level = world_map.sea_level;
|
||||
let rgba = world_map.rgba;
|
||||
let alt = world_map.alt;
|
||||
let expected_size =
|
||||
(u32::from(map_size.x) * u32::from(map_size.y)) as usize;
|
||||
if rgba.len() != expected_size {
|
||||
return Err(Error::Other("Server sent a bad world map image".into()));
|
||||
}
|
||||
if alt.len() != expected_size {
|
||||
return Err(Error::Other("Server sent a bad altitude map.".into()));
|
||||
}
|
||||
let [west, east] = world_map.horizons;
|
||||
let scale_angle =
|
||||
|a: u8| (a as f32 / 255.0 * <f32 as FloatConst>::FRAC_PI_2()).tan();
|
||||
let scale_height = |h: u8| h as f32 / 255.0 * max_height;
|
||||
let scale_height_big = |h: u32| (h >> 3) as f32 / 8191.0 * max_height;
|
||||
|
||||
debug!("Preparing image...");
|
||||
let unzip_horizons = |(angles, heights): &(Vec<_>, Vec<_>)| {
|
||||
(
|
||||
angles.iter().copied().map(scale_angle).collect::<Vec<_>>(),
|
||||
heights
|
||||
.iter()
|
||||
.copied()
|
||||
.map(scale_height)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
};
|
||||
let horizons = [unzip_horizons(&west), unzip_horizons(&east)];
|
||||
|
||||
// Redraw map (with shadows this time).
|
||||
let mut world_map = vec![0u32; rgba.len()];
|
||||
let mut map_config = common::terrain::map::MapConfig::orthographic(
|
||||
map_size_lg,
|
||||
core::ops::RangeInclusive::new(0.0, max_height),
|
||||
);
|
||||
map_config.horizons = Some(&horizons);
|
||||
let rescale_height = |h: f32| h / max_height;
|
||||
let bounds_check = |pos: Vec2<i32>| {
|
||||
pos.reduce_partial_min() >= 0
|
||||
&& pos.x < map_size.x as i32
|
||||
&& pos.y < map_size.y as i32
|
||||
};
|
||||
map_config.generate(
|
||||
|pos| {
|
||||
let (rgba, alt, downhill_wpos) = if bounds_check(pos) {
|
||||
let posi =
|
||||
pos.y as usize * map_size.x as usize + pos.x as usize;
|
||||
let [r, g, b, a] = rgba[posi].to_le_bytes();
|
||||
let alti = alt[posi];
|
||||
// Compute downhill.
|
||||
let downhill = {
|
||||
let mut best = -1;
|
||||
let mut besth = alti;
|
||||
for nposi in neighbors(map_size_lg, posi) {
|
||||
let nbh = alt[nposi];
|
||||
if nbh < besth {
|
||||
besth = nbh;
|
||||
best = nposi as isize;
|
||||
}
|
||||
}
|
||||
best
|
||||
};
|
||||
let downhill_wpos = if downhill < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
Vec2::new(
|
||||
(downhill as usize % map_size.x as usize) as i32,
|
||||
(downhill as usize / map_size.x as usize) as i32,
|
||||
) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||
)
|
||||
};
|
||||
(Rgba::new(r, g, b, a), alti, downhill_wpos)
|
||||
} else {
|
||||
(Rgba::zero(), 0, None)
|
||||
};
|
||||
let wpos = pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
|
||||
let downhill_wpos = downhill_wpos.unwrap_or(
|
||||
wpos + TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||
);
|
||||
}
|
||||
|
||||
debug!("Auth Server: {:?}", server_info.auth_provider);
|
||||
|
||||
// Initialize `State`
|
||||
let mut state = State::default();
|
||||
// Client-only components
|
||||
state
|
||||
.ecs_mut()
|
||||
.register::<comp::Last<comp::CharacterState>>();
|
||||
|
||||
let entity = state.ecs_mut().apply_entity_package(entity_package);
|
||||
*state.ecs_mut().write_resource() = time_of_day;
|
||||
|
||||
assert_eq!(world_map.len(), (map_size.x * map_size.y) as usize);
|
||||
let mut world_map_raw =
|
||||
vec![0u8; 4 * world_map.len()/*map_size.x * map_size.y*/];
|
||||
LittleEndian::write_u32_into(&world_map, &mut world_map_raw);
|
||||
debug!("Preparing image...");
|
||||
let world_map = Arc::new(
|
||||
let alt = rescale_height(scale_height_big(alt));
|
||||
common::terrain::map::MapSample {
|
||||
rgb: Rgb::from(rgba),
|
||||
alt: f64::from(alt),
|
||||
downhill_wpos,
|
||||
connections: None,
|
||||
}
|
||||
},
|
||||
|wpos| {
|
||||
let pos =
|
||||
wpos.map2(TerrainChunkSize::RECT_SIZE, |e, f| e / f as i32);
|
||||
rescale_height(if bounds_check(pos) {
|
||||
let posi =
|
||||
pos.y as usize * map_size.x as usize + pos.x as usize;
|
||||
scale_height_big(alt[posi])
|
||||
} else {
|
||||
0.0
|
||||
})
|
||||
},
|
||||
|pos, (r, g, b, a)| {
|
||||
world_map[pos.y * map_size.x as usize + pos.x] =
|
||||
u32::from_le_bytes([r, g, b, a]);
|
||||
},
|
||||
);
|
||||
let make_raw = |rgba| -> Result<_, Error> {
|
||||
let mut raw = vec![0u8; 4 * world_map.len()];
|
||||
LittleEndian::write_u32_into(rgba, &mut raw);
|
||||
Ok(Arc::new(
|
||||
image::DynamicImage::ImageRgba8({
|
||||
// Should not fail if the dimensions are correct.
|
||||
let world_map =
|
||||
image::ImageBuffer::from_raw(map_size.x, map_size.y, world_map_raw);
|
||||
world_map.ok_or_else(|| Error::Other("Server sent a bad world map image".into()))?
|
||||
let map =
|
||||
image::ImageBuffer::from_raw(u32::from(map_size.x), u32::from(map_size.y), raw);
|
||||
map.ok_or_else(|| Error::Other("Server sent a bad world map image".into()))?
|
||||
})
|
||||
// Flip the image, since Voxygen uses an orientation where rotation from
|
||||
// positive x axis to positive y axis is counterclockwise around the z axis.
|
||||
.flipv(),
|
||||
);
|
||||
debug!("Done preparing image...");
|
||||
// Flip the image, since Voxygen uses an orientation where rotation from
|
||||
// positive x axis to positive y axis is counterclockwise around the z axis.
|
||||
.flipv(),
|
||||
))
|
||||
};
|
||||
let lod_base = rgba;
|
||||
let lod_alt = alt;
|
||||
let world_map = make_raw(&world_map)?;
|
||||
let horizons = (west.0, west.1, east.0, east.1)
|
||||
.into_par_iter()
|
||||
.map(|(wa, wh, ea, eh)| u32::from_le_bytes([wa, wh, ea, eh]))
|
||||
.collect::<Vec<_>>();
|
||||
let lod_horizon = horizons;
|
||||
let map_bounds = Vec2::new(sea_level, max_height);
|
||||
debug!("Done preparing image...");
|
||||
|
||||
break Ok((
|
||||
state,
|
||||
entity,
|
||||
server_info,
|
||||
(world_map, map_size),
|
||||
recipe_book,
|
||||
max_group_size,
|
||||
));
|
||||
},
|
||||
ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers),
|
||||
err => {
|
||||
warn!("whoops, server mad {:?}, ignoring", err);
|
||||
},
|
||||
}
|
||||
break Ok((
|
||||
state,
|
||||
entity,
|
||||
server_info,
|
||||
lod_base,
|
||||
lod_alt,
|
||||
lod_horizon,
|
||||
(world_map, map_size, map_bounds),
|
||||
recipe_book,
|
||||
max_group_size,
|
||||
));
|
||||
},
|
||||
ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers),
|
||||
err => {
|
||||
warn!("whoops, server mad {:?}, ignoring", err);
|
||||
},
|
||||
}
|
||||
},
|
||||
)?;
|
||||
}
|
||||
})?;
|
||||
|
||||
stream.send(ClientMsg::Ping)?;
|
||||
|
||||
@ -222,6 +378,9 @@ impl Client {
|
||||
thread_pool,
|
||||
server_info,
|
||||
world_map,
|
||||
lod_base,
|
||||
lod_alt,
|
||||
lod_horizon,
|
||||
player_list: HashMap::new(),
|
||||
character_list: CharacterList::default(),
|
||||
active_character_id: None,
|
||||
|
@ -11,12 +11,14 @@ no-assets = []
|
||||
arraygen = "0.1.13"
|
||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git" }
|
||||
|
||||
roots = "0.0.6"
|
||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["serde", "storage-event-control"], rev = "7a2e348ab2223818bad487695c66c43db88050a5" }
|
||||
vek = { version = "0.11.0", features = ["serde"] }
|
||||
vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] }
|
||||
dot_vox = "4.0"
|
||||
image = { version = "0.22.5", default-features = false, features = ["png"] }
|
||||
image = { version = "0.23.8", default-features = false, features = ["png"] }
|
||||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
serde_json = "1.0.50"
|
||||
serde_repr = "0.1.6"
|
||||
ron = { version = "0.6", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
rand = "0.7"
|
||||
|
@ -170,5 +170,13 @@ impl ReloadIndicator {
|
||||
}
|
||||
|
||||
// Returns true if the watched file was changed
|
||||
pub fn reloaded(&self) -> bool { self.reloaded.swap(false, Ordering::Acquire) }
|
||||
pub fn reloaded(&self) -> bool {
|
||||
// Optimize for the common case by performing an initial relaxed read, avoiding
|
||||
// the atomic write.
|
||||
if self.reloaded.load(Ordering::Relaxed) {
|
||||
self.reloaded.swap(false, Ordering::Acquire)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub mod quadruped_small;
|
||||
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
make_case_elim,
|
||||
npc::NpcKind,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -21,23 +22,26 @@ use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::{fs::File, io::BufReader};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Body {
|
||||
Humanoid(humanoid::Body) = 0,
|
||||
QuadrupedSmall(quadruped_small::Body) = 1,
|
||||
QuadrupedMedium(quadruped_medium::Body) = 2,
|
||||
BirdMedium(bird_medium::Body) = 3,
|
||||
FishMedium(fish_medium::Body) = 4,
|
||||
Dragon(dragon::Body) = 5,
|
||||
BirdSmall(bird_small::Body) = 6,
|
||||
FishSmall(fish_small::Body) = 7,
|
||||
BipedLarge(biped_large::Body) = 8,
|
||||
Object(object::Body) = 9,
|
||||
Golem(golem::Body) = 10,
|
||||
Critter(critter::Body) = 11,
|
||||
QuadrupedLow(quadruped_low::Body) = 12,
|
||||
}
|
||||
make_case_elim!(
|
||||
body,
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Body {
|
||||
Humanoid(body: humanoid::Body) = 0,
|
||||
QuadrupedSmall(body: quadruped_small::Body) = 1,
|
||||
QuadrupedMedium(body: quadruped_medium::Body) = 2,
|
||||
BirdMedium(body: bird_medium::Body) = 3,
|
||||
FishMedium(body: fish_medium::Body) = 4,
|
||||
Dragon(body: dragon::Body) = 5,
|
||||
BirdSmall(body: bird_small::Body) = 6,
|
||||
FishSmall(body: fish_small::Body) = 7,
|
||||
BipedLarge(body: biped_large::Body)= 8,
|
||||
Object(body: object::Body) = 9,
|
||||
Golem(body: golem::Body) = 10,
|
||||
Critter(body: critter::Body) = 11,
|
||||
QuadrupedLow(body: quadruped_low::Body) = 12,
|
||||
}
|
||||
);
|
||||
|
||||
/// Data representing data generic to the body together with per-species data.
|
||||
///
|
||||
@ -60,10 +64,14 @@ pub struct AllBodies<BodyMeta, SpeciesMeta> {
|
||||
pub quadruped_small: BodyData<BodyMeta, quadruped_small::AllSpecies<SpeciesMeta>>,
|
||||
pub quadruped_medium: BodyData<BodyMeta, quadruped_medium::AllSpecies<SpeciesMeta>>,
|
||||
pub bird_medium: BodyData<BodyMeta, bird_medium::AllSpecies<SpeciesMeta>>,
|
||||
pub fish_medium: BodyData<BodyMeta, ()>,
|
||||
pub dragon: BodyData<BodyMeta, dragon::AllSpecies<SpeciesMeta>>,
|
||||
pub bird_small: BodyData<BodyMeta, ()>,
|
||||
pub fish_small: BodyData<BodyMeta, ()>,
|
||||
pub biped_large: BodyData<BodyMeta, biped_large::AllSpecies<SpeciesMeta>>,
|
||||
pub object: BodyData<BodyMeta, ()>,
|
||||
pub golem: BodyData<BodyMeta, golem::AllSpecies<SpeciesMeta>>,
|
||||
pub critter: BodyData<BodyMeta, critter::AllSpecies<SpeciesMeta>>,
|
||||
pub dragon: BodyData<BodyMeta, dragon::AllSpecies<SpeciesMeta>>,
|
||||
pub quadruped_low: BodyData<BodyMeta, quadruped_low::AllSpecies<SpeciesMeta>>,
|
||||
}
|
||||
|
||||
@ -87,6 +95,30 @@ impl<BodyMeta, SpeciesMeta> core::ops::Index<NpcKind> for AllBodies<BodyMeta, Sp
|
||||
}
|
||||
}
|
||||
|
||||
/// Can only retrieve body metadata by direct index.
|
||||
impl<'a, BodyMeta, SpeciesMeta> core::ops::Index<&'a Body> for AllBodies<BodyMeta, SpeciesMeta> {
|
||||
type Output = BodyMeta;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: &Body) -> &Self::Output {
|
||||
match index {
|
||||
Body::Humanoid(_) => &self.humanoid.body,
|
||||
Body::QuadrupedSmall(_) => &self.quadruped_small.body,
|
||||
Body::QuadrupedMedium(_) => &self.quadruped_medium.body,
|
||||
Body::BirdMedium(_) => &self.bird_medium.body,
|
||||
Body::FishMedium(_) => &self.fish_medium.body,
|
||||
Body::Dragon(_) => &self.dragon.body,
|
||||
Body::BirdSmall(_) => &self.bird_small.body,
|
||||
Body::FishSmall(_) => &self.fish_small.body,
|
||||
Body::BipedLarge(_) => &self.biped_large.body,
|
||||
Body::Object(_) => &self.object.body,
|
||||
Body::Golem(_) => &self.golem.body,
|
||||
Body::Critter(_) => &self.critter.body,
|
||||
Body::QuadrupedLow(_) => &self.quadruped_low.body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
BodyMeta: Send + Sync + for<'de> serde::Deserialize<'de>,
|
||||
SpeciesMeta: Send + Sync + for<'de> serde::Deserialize<'de>,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::make_case_elim;
|
||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::Rgb;
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Body {
|
||||
@ -58,16 +59,19 @@ impl From<Body> for super::Body {
|
||||
fn from(body: Body) -> Self { super::Body::Humanoid(body) }
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Species {
|
||||
Danari = 0,
|
||||
Dwarf = 1,
|
||||
Elf = 2,
|
||||
Human = 3,
|
||||
Orc = 4,
|
||||
Undead = 5,
|
||||
}
|
||||
make_case_elim!(
|
||||
species,
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Species {
|
||||
Danari = 0,
|
||||
Dwarf = 1,
|
||||
Elf = 2,
|
||||
Human = 3,
|
||||
Orc = 4,
|
||||
Undead = 5,
|
||||
}
|
||||
);
|
||||
|
||||
/// Data representing per-species generic data.
|
||||
///
|
||||
@ -114,142 +118,6 @@ impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
|
||||
fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
|
||||
}
|
||||
|
||||
// Hair Colors
|
||||
pub const DANARI_HAIR_COLORS: [(u8, u8, u8); 12] = [
|
||||
(198, 169, 113), // Philosopher's Grey
|
||||
//(245, 232, 175), // Cream Blonde
|
||||
//(228, 208, 147), // Gold Blonde
|
||||
//(228, 223, 141), // Platinum Blonde
|
||||
(199, 131, 58), // Summer Blonde
|
||||
(107, 76, 51), // Oak Skin4
|
||||
//(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(107, 32, 60), // Grape Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
//(146, 32, 32), // Autumn Red
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
pub const DWARF_HAIR_COLORS: [(u8, u8, u8); 21] = [
|
||||
(245, 232, 175), // Cream Blonde
|
||||
(228, 208, 147), // Gold Blonde
|
||||
(228, 223, 141), // Platinum Blonde
|
||||
(199, 131, 58), // Summer Blonde
|
||||
(107, 76, 51), // Oak Skin4
|
||||
(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(191, 228, 254), // Ice NobleBlue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(174, 148, 161), // Matte Pink
|
||||
(163, 186, 192), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
pub const ELF_HAIR_COLORS: [(u8, u8, u8); 24] = [
|
||||
(66, 83, 113), // Mysterious Blue
|
||||
(13, 76, 41), // Rainforest Green
|
||||
(245, 232, 175), // Cream Blonde
|
||||
(228, 208, 147), // Gold Blonde
|
||||
(228, 223, 141), // Platinum Blonde
|
||||
(199, 131, 58), // Summer Blonde
|
||||
(107, 76, 51), // Oak Skin4
|
||||
(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(191, 228, 254), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(224, 182, 184), // Candy Pink
|
||||
(174, 148, 161), // Matte Pink
|
||||
(163, 186, 192), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
pub const HUMAN_HAIR_COLORS: [(u8, u8, u8); 22] = [
|
||||
(245, 232, 175), // Cream Blonde
|
||||
(228, 208, 147), // Gold Blonde
|
||||
(228, 223, 141), // Platinum Blonde
|
||||
(199, 131, 58), // Summer Blonde
|
||||
(107, 76, 51), // Oak Skin4
|
||||
(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(191, 228, 254), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(224, 182, 184), // Candy Pink
|
||||
(174, 148, 161), // Matte Pink
|
||||
(163, 186, 192), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
pub const ORC_HAIR_COLORS: [(u8, u8, u8); 11] = [
|
||||
(66, 66, 59), // Wise Grey
|
||||
//(107, 76, 51), // Oak Skin4
|
||||
//(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(54, 30, 26), // Dark Skin7
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(66, 83, 113), // Mysterious Blue
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
pub const UNDEAD_HAIR_COLORS: [(u8, u8, u8); 22] = [
|
||||
//(245, 232, 175), // Cream Blonde
|
||||
(228, 208, 147), // Gold Blonde
|
||||
//(228, 223, 141), // Platinum Blonde
|
||||
(199, 131, 58), // Summer Blonde
|
||||
(107, 76, 51), // Oak Skin4
|
||||
(203, 154, 98), // Light Skin4
|
||||
(64, 32, 18), // Skin7 Skin4
|
||||
(86, 72, 71), // Ash Skin4
|
||||
(57, 56, 61), // Raven Black
|
||||
(101, 83, 95), // Matte Purple
|
||||
(101, 57, 90), // Witch Purple
|
||||
(111, 54, 117), // Punky Purple
|
||||
(135, 38, 39), // Dark Red
|
||||
(88, 26, 29), // Wine Red
|
||||
(191, 228, 254), // Ice Blue
|
||||
(92, 80, 144), // Kingfisher Blue
|
||||
(146, 198, 238), // Lagoon Blue
|
||||
(66, 66, 59), // Decayed Grey
|
||||
//(224, 182, 184), // Candy Pink
|
||||
(174, 148, 161), // Matte Pink
|
||||
(0, 131, 122), // Rotten Green
|
||||
(163, 186, 192), // Matte Green
|
||||
(84, 139, 107), // Grass Green
|
||||
(48, 61, 52), // Dark Green
|
||||
(20, 19, 17), // Black
|
||||
];
|
||||
|
||||
// Skin colors
|
||||
pub const DANARI_SKIN_COLORS: [Skin; 4] = [
|
||||
Skin::DanariOne,
|
||||
@ -352,17 +220,6 @@ pub const UNDEAD_EYE_COLORS: [EyeColor; 5] = [
|
||||
];
|
||||
|
||||
impl Species {
|
||||
fn hair_colors(self) -> &'static [(u8, u8, u8)] {
|
||||
match self {
|
||||
Species::Danari => &DANARI_HAIR_COLORS,
|
||||
Species::Dwarf => &DWARF_HAIR_COLORS,
|
||||
Species::Elf => &ELF_HAIR_COLORS,
|
||||
Species::Human => &HUMAN_HAIR_COLORS,
|
||||
Species::Orc => &ORC_HAIR_COLORS,
|
||||
Species::Undead => &UNDEAD_HAIR_COLORS,
|
||||
}
|
||||
}
|
||||
|
||||
fn skin_colors(self) -> &'static [Skin] {
|
||||
match self {
|
||||
Species::Danari => &DANARI_SKIN_COLORS,
|
||||
@ -385,16 +242,22 @@ impl Species {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hair_color(self, val: u8) -> Rgb<u8> {
|
||||
self.hair_colors()
|
||||
.get(val as usize)
|
||||
.copied()
|
||||
.unwrap_or((0, 0, 0))
|
||||
.into()
|
||||
/// FIXME: This is a hack! The only reason we need to do this is because
|
||||
/// hair colors are currently just indices into an array, not enum
|
||||
/// variants. Once we have proper variants for hair colors, we won't
|
||||
/// need to do this anymore, since we will use locally defined arrays to
|
||||
/// represent per-species stuff (or have some other solution for validity).
|
||||
pub fn num_hair_colors(self) -> u8 {
|
||||
match self {
|
||||
Species::Danari => 12,
|
||||
Species::Dwarf => 21,
|
||||
Species::Elf => 24,
|
||||
Species::Human => 22,
|
||||
Species::Orc => 11,
|
||||
Species::Undead => 22,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_hair_colors(self) -> u8 { self.hair_colors().len() as u8 }
|
||||
|
||||
pub fn skin_color(self, val: u8) -> Skin {
|
||||
self.skin_colors()
|
||||
.get(val as usize)
|
||||
@ -484,238 +347,78 @@ impl Species {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum BodyType {
|
||||
Female = 0,
|
||||
Male = 1,
|
||||
}
|
||||
make_case_elim!(
|
||||
body_type,
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum BodyType {
|
||||
Female = 0,
|
||||
Male = 1,
|
||||
}
|
||||
);
|
||||
|
||||
pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum EyeColor {
|
||||
VigorousBlack = 0,
|
||||
NobleBlue = 1,
|
||||
CuriousGreen = 2,
|
||||
LoyalBrown = 3,
|
||||
ViciousRed = 4,
|
||||
PumpkinOrange = 5,
|
||||
GhastlyYellow = 6,
|
||||
MagicPurple = 7,
|
||||
ToxicGreen = 8,
|
||||
ExoticPurple = 9,
|
||||
SulfurYellow = 10,
|
||||
AmberOrange = 11,
|
||||
PineGreen = 12,
|
||||
CornflowerBlue = 13,
|
||||
}
|
||||
impl EyeColor {
|
||||
pub fn light_rgb(self) -> Rgb<u8> {
|
||||
match self {
|
||||
EyeColor::VigorousBlack => Rgb::new(71, 59, 49),
|
||||
EyeColor::NobleBlue => Rgb::new(75, 158, 191),
|
||||
EyeColor::CuriousGreen => Rgb::new(110, 167, 113),
|
||||
EyeColor::LoyalBrown => Rgb::new(73, 42, 36),
|
||||
EyeColor::ViciousRed => Rgb::new(182, 0, 0),
|
||||
EyeColor::PumpkinOrange => Rgb::new(220, 156, 19),
|
||||
EyeColor::GhastlyYellow => Rgb::new(221, 225, 31),
|
||||
EyeColor::MagicPurple => Rgb::new(137, 4, 177),
|
||||
EyeColor::ToxicGreen => Rgb::new(1, 223, 1),
|
||||
EyeColor::ExoticPurple => Rgb::new(95, 32, 111),
|
||||
EyeColor::SulfurYellow => Rgb::new(235, 198, 94),
|
||||
EyeColor::AmberOrange => Rgb::new(137, 46, 1),
|
||||
EyeColor::PineGreen => Rgb::new(0, 78, 56),
|
||||
EyeColor::CornflowerBlue => Rgb::new(18, 66, 90),
|
||||
}
|
||||
make_case_elim!(
|
||||
eye_color,
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u32)]
|
||||
pub enum EyeColor {
|
||||
VigorousBlack = 0,
|
||||
NobleBlue = 1,
|
||||
CuriousGreen = 2,
|
||||
LoyalBrown = 3,
|
||||
ViciousRed = 4,
|
||||
PumpkinOrange = 5,
|
||||
GhastlyYellow = 6,
|
||||
MagicPurple = 7,
|
||||
ToxicGreen = 8,
|
||||
ExoticPurple = 9,
|
||||
SulfurYellow = 10,
|
||||
AmberOrange = 11,
|
||||
PineGreen = 12,
|
||||
CornflowerBlue = 13,
|
||||
}
|
||||
);
|
||||
|
||||
pub fn dark_rgb(self) -> Rgb<u8> {
|
||||
match self {
|
||||
EyeColor::VigorousBlack => Rgb::new(32, 32, 32),
|
||||
EyeColor::NobleBlue => Rgb::new(62, 130, 159),
|
||||
EyeColor::CuriousGreen => Rgb::new(81, 124, 84),
|
||||
EyeColor::LoyalBrown => Rgb::new(54, 30, 26),
|
||||
EyeColor::ViciousRed => Rgb::new(148, 0, 0),
|
||||
EyeColor::PumpkinOrange => Rgb::new(209, 145, 18),
|
||||
EyeColor::GhastlyYellow => Rgb::new(205, 212, 29),
|
||||
EyeColor::MagicPurple => Rgb::new(110, 3, 143),
|
||||
EyeColor::ToxicGreen => Rgb::new(1, 185, 1),
|
||||
EyeColor::ExoticPurple => Rgb::new(69, 23, 80),
|
||||
EyeColor::SulfurYellow => Rgb::new(209, 176, 84),
|
||||
EyeColor::AmberOrange => Rgb::new(112, 40, 1),
|
||||
EyeColor::PineGreen => Rgb::new(0, 54, 38),
|
||||
EyeColor::CornflowerBlue => Rgb::new(13, 47, 64),
|
||||
}
|
||||
make_case_elim!(
|
||||
skin,
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u32)]
|
||||
pub enum Skin {
|
||||
Skin1 = 0,
|
||||
Skin2 = 1,
|
||||
Skin3 = 2,
|
||||
Skin4 = 3,
|
||||
Skin5 = 4,
|
||||
Skin6 = 5,
|
||||
Iron = 6,
|
||||
Steel = 7,
|
||||
DanariOne = 8,
|
||||
DanariTwo = 9,
|
||||
DanariThree = 10,
|
||||
DanariFour = 11,
|
||||
ElfOne = 12,
|
||||
ElfTwo = 13,
|
||||
//ElfThree = 14,
|
||||
OrcOne = 14,
|
||||
OrcTwo = 15,
|
||||
OrcThree = 16,
|
||||
UndeadOne = 17,
|
||||
UndeadTwo = 18,
|
||||
UndeadThree = 19,
|
||||
Skin7 = 20,
|
||||
Skin8 = 21,
|
||||
Skin9 = 22,
|
||||
Skin10 = 23,
|
||||
Skin11 = 24,
|
||||
Skin12 = 25,
|
||||
Skin13 = 26,
|
||||
Skin14 = 27,
|
||||
Skin15 = 28,
|
||||
Skin16 = 29,
|
||||
Skin17 = 30,
|
||||
Skin18 = 31,
|
||||
OrcFour = 32,
|
||||
}
|
||||
|
||||
pub fn white_rgb(self) -> Rgb<u8> { Rgb::new(255, 255, 255) }
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Accessory {
|
||||
Nothing = 0,
|
||||
Some = 1,
|
||||
}
|
||||
pub const ALL_ACCESSORIES: [Accessory; 2] = [Accessory::Nothing, Accessory::Some];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(u32)]
|
||||
pub enum Skin {
|
||||
Skin1 = 0,
|
||||
Skin2 = 1,
|
||||
Skin3 = 2,
|
||||
Skin4 = 3,
|
||||
Skin5 = 4,
|
||||
Skin6 = 5,
|
||||
Iron = 6,
|
||||
Steel = 7,
|
||||
DanariOne = 8,
|
||||
DanariTwo = 9,
|
||||
DanariThree = 10,
|
||||
DanariFour = 11,
|
||||
ElfOne = 12,
|
||||
ElfTwo = 13,
|
||||
//ElfThree = 14,
|
||||
OrcOne = 14,
|
||||
OrcTwo = 15,
|
||||
OrcThree = 16,
|
||||
UndeadOne = 17,
|
||||
UndeadTwo = 18,
|
||||
UndeadThree = 19,
|
||||
Skin7 = 20,
|
||||
Skin8 = 21,
|
||||
Skin9 = 22,
|
||||
Skin10 = 23,
|
||||
Skin11 = 24,
|
||||
Skin12 = 25,
|
||||
Skin13 = 26,
|
||||
Skin14 = 27,
|
||||
Skin15 = 28,
|
||||
Skin16 = 29,
|
||||
Skin17 = 30,
|
||||
Skin18 = 31,
|
||||
OrcFour = 32,
|
||||
}
|
||||
impl Skin {
|
||||
pub fn rgb(self) -> Rgb<u8> {
|
||||
let color = match self {
|
||||
Self::Skin1 => (255, 229, 200),
|
||||
Self::Skin2 => (255, 218, 190),
|
||||
Self::Skin3 => (255, 206, 180),
|
||||
Self::Skin4 => (255, 195, 170),
|
||||
Self::Skin5 => (240, 184, 160),
|
||||
Self::Skin6 => (225, 172, 150),
|
||||
Self::Skin7 => (210, 161, 140),
|
||||
Self::Skin8 => (195, 149, 130),
|
||||
Self::Skin9 => (180, 138, 120),
|
||||
Self::Skin10 => (165, 126, 110),
|
||||
Self::Skin11 => (150, 114, 100),
|
||||
Self::Skin12 => (135, 103, 90),
|
||||
Self::Skin13 => (120, 92, 80),
|
||||
Self::Skin14 => (105, 80, 70),
|
||||
Self::Skin15 => (90, 69, 60),
|
||||
Self::Skin16 => (75, 57, 50),
|
||||
Self::Skin17 => (60, 46, 40),
|
||||
Self::Skin18 => (45, 34, 30),
|
||||
Self::Iron => (135, 113, 95),
|
||||
Self::Steel => (108, 94, 86),
|
||||
Self::DanariOne => (104, 168, 196),
|
||||
Self::DanariTwo => (30, 149, 201),
|
||||
Self::DanariThree => (57, 120, 148),
|
||||
Self::DanariFour => (40, 85, 105),
|
||||
Self::ElfOne => (178, 164, 186),
|
||||
Self::ElfTwo => (132, 139, 161),
|
||||
//Self::ElfThree => (230, 188, 198),
|
||||
Self::OrcOne => (61, 130, 42),
|
||||
Self::OrcTwo => (82, 117, 36),
|
||||
Self::OrcThree => (71, 94, 42),
|
||||
Self::OrcFour => (97, 54, 29),
|
||||
Self::UndeadOne => (240, 243, 239),
|
||||
Self::UndeadTwo => (178, 178, 178),
|
||||
Self::UndeadThree => (145, 135, 121),
|
||||
};
|
||||
Rgb::from(color)
|
||||
}
|
||||
|
||||
pub fn light_rgb(self) -> Rgb<u8> {
|
||||
let color = match self {
|
||||
Self::Skin1 => (255, 229, 200),
|
||||
Self::Skin2 => (255, 218, 190),
|
||||
Self::Skin3 => (255, 206, 180),
|
||||
Self::Skin4 => (255, 195, 170),
|
||||
Self::Skin5 => (240, 184, 160),
|
||||
Self::Skin6 => (225, 172, 150),
|
||||
Self::Skin7 => (210, 161, 140),
|
||||
Self::Skin8 => (195, 149, 130),
|
||||
Self::Skin9 => (180, 138, 120),
|
||||
Self::Skin10 => (165, 126, 110),
|
||||
Self::Skin11 => (150, 114, 100),
|
||||
Self::Skin12 => (135, 103, 90),
|
||||
Self::Skin13 => (120, 92, 80),
|
||||
Self::Skin14 => (105, 80, 70),
|
||||
Self::Skin15 => (90, 69, 60),
|
||||
Self::Skin16 => (75, 57, 50),
|
||||
Self::Skin17 => (60, 46, 40),
|
||||
Self::Skin18 => (45, 34, 30),
|
||||
Self::Iron => (144, 125, 106),
|
||||
Self::Steel => (120, 107, 99),
|
||||
Self::DanariOne => (116, 176, 208),
|
||||
Self::DanariTwo => (42, 158, 206),
|
||||
Self::DanariThree => (70, 133, 160),
|
||||
Self::DanariFour => (53, 96, 116),
|
||||
Self::ElfOne => (190, 176, 199), //178, 164, 186
|
||||
Self::ElfTwo => (137, 144, 167),
|
||||
//Self::ElfThree => (242, 199, 209),
|
||||
Self::OrcOne => (83, 165, 56),
|
||||
Self::OrcTwo => (92, 132, 46),
|
||||
Self::OrcThree => (84, 110, 54),
|
||||
Self::OrcFour => (97, 54, 29),
|
||||
Self::UndeadOne => (254, 252, 251),
|
||||
Self::UndeadTwo => (190, 192, 191),
|
||||
Self::UndeadThree => (160, 151, 134),
|
||||
};
|
||||
Rgb::from(color)
|
||||
}
|
||||
|
||||
pub fn dark_rgb(self) -> Rgb<u8> {
|
||||
let color = match self {
|
||||
Self::Skin1 => (242, 217, 189),
|
||||
Self::Skin2 => (242, 207, 189),
|
||||
Self::Skin3 => (242, 197, 172),
|
||||
Self::Skin4 => (242, 186, 162),
|
||||
Self::Skin5 => (212, 173, 150),
|
||||
Self::Skin6 => (212, 163, 142),
|
||||
Self::Skin7 => (196, 151, 132),
|
||||
Self::Skin8 => (181, 139, 121),
|
||||
Self::Skin9 => (168, 129, 113),
|
||||
Self::Skin10 => (153, 117, 103),
|
||||
Self::Skin11 => (138, 105, 92),
|
||||
Self::Skin12 => (122, 93, 82),
|
||||
Self::Skin13 => (107, 82, 72),
|
||||
Self::Skin14 => (92, 70, 62),
|
||||
Self::Skin15 => (77, 59, 51),
|
||||
Self::Skin16 => (61, 47, 41),
|
||||
Self::Skin17 => (48, 37, 32),
|
||||
Self::Skin18 => (33, 25, 22),
|
||||
Self::Iron => (124, 99, 82),
|
||||
Self::Steel => (96, 81, 72),
|
||||
Self::DanariOne => (92, 155, 183),
|
||||
Self::DanariTwo => (25, 142, 192),
|
||||
Self::DanariThree => (52, 115, 143),
|
||||
Self::DanariFour => (34, 80, 99),
|
||||
Self::ElfOne => (170, 155, 175), //170, 157, 179
|
||||
Self::ElfTwo => (126, 132, 153),
|
||||
//Self::ElfThree => (217, 178, 187),
|
||||
Self::OrcOne => (55, 114, 36),
|
||||
Self::OrcTwo => (70, 104, 29),
|
||||
Self::OrcThree => (60, 83, 32),
|
||||
Self::OrcFour => (84, 47, 25),
|
||||
Self::UndeadOne => (229, 231, 230),
|
||||
Self::UndeadTwo => (165, 166, 164),
|
||||
Self::UndeadThree => (130, 122, 106),
|
||||
};
|
||||
Rgb::from(color)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -82,7 +82,8 @@ impl CharacterState {
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
| CharacterState::ChargedRanged(_))
|
||||
| CharacterState::ChargedRanged(_)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_attack(&self) -> bool {
|
||||
@ -93,7 +94,8 @@ impl CharacterState {
|
||||
| CharacterState::TripleStrike(_)
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
| CharacterState::ChargedRanged(_))
|
||||
| CharacterState::ChargedRanged(_)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_aimed(&self) -> bool {
|
||||
@ -104,7 +106,8 @@ impl CharacterState {
|
||||
| CharacterState::TripleStrike(_)
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::ChargedRanged(_))
|
||||
| CharacterState::ChargedRanged(_)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock) }
|
||||
|
@ -3,6 +3,8 @@
|
||||
#![type_length_limit = "1664759"]
|
||||
#![feature(
|
||||
arbitrary_enum_discriminant,
|
||||
const_checked_int_methods,
|
||||
fundamental,
|
||||
option_unwrap_none,
|
||||
bool_to_option,
|
||||
label_break_value,
|
||||
@ -37,6 +39,7 @@ pub mod store;
|
||||
pub mod sync;
|
||||
pub mod sys;
|
||||
pub mod terrain;
|
||||
pub mod typed;
|
||||
pub mod util;
|
||||
pub mod vol;
|
||||
pub mod volumes;
|
||||
|
@ -48,6 +48,127 @@ pub struct CharacterInfo {
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
/// World map information. Note that currently, we always send the whole thing
|
||||
/// in one go, but the structure aims to try to provide information as locally
|
||||
/// as possible, so that in the future we can split up large maps into multiple
|
||||
/// WorldMapMsg fragments.
|
||||
///
|
||||
/// TODO: Update message format to make fragmentable, allowing us to send more
|
||||
/// information without running into bandwidth issues.
|
||||
///
|
||||
/// TODO: Add information for rivers (currently, we just prerender them on the
|
||||
/// server, but this is not a great solution for LoD. The map rendering code is
|
||||
/// already set up to be able to take advantage of the river rendering being
|
||||
/// split out, but the format is a little complicated for space reasons and it
|
||||
/// may take some tweaking to get right, so we avoid sending it for now).
|
||||
///
|
||||
/// TODO: measure explicit compression schemes that might save space, e.g.
|
||||
/// repeating the "small angles" optimization that works well on more detailed
|
||||
/// shadow maps intended for height maps.
|
||||
pub struct WorldMapMsg {
|
||||
/// Log base 2 of world map dimensions (width × height) in chunks.
|
||||
///
|
||||
/// NOTE: Invariant: chunk count fits in a u16.
|
||||
pub dimensions_lg: Vec2<u32>,
|
||||
/// Sea level (used to provide a base altitude).
|
||||
pub sea_level: f32,
|
||||
/// Max height (used to scale altitudes).
|
||||
pub max_height: f32,
|
||||
/// RGB+A; the alpha channel is currently unused, but will be used in the
|
||||
/// future. Entries are in the usual chunk order.
|
||||
pub rgba: Vec<u32>,
|
||||
/// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for
|
||||
/// altitude. The remainder are currently unused, but we have plans to
|
||||
/// use 7 bits for water depth (using an integer f7 encoding), and we
|
||||
/// will find other uses for the remaining 12 bits.
|
||||
pub alt: Vec<u32>,
|
||||
/// Horizon mapping. This is a variant of shadow mapping that is
|
||||
/// specifically designed for height maps; it takes advantage of their
|
||||
/// regular structure (e.g. no holes) to compress all information needed
|
||||
/// to decide when to cast a sharp shadow into a single nagle, the "horizon
|
||||
/// angle." This is the smallest angle with the ground at which light can
|
||||
/// pass through any occluders to reach the chunk, in some chosen
|
||||
/// horizontal direction. This would not be sufficient for a more
|
||||
/// complicated 3D structure, but it works for height maps since:
|
||||
///
|
||||
/// 1. they have no gaps, so as soon as light can shine through it will
|
||||
/// always be able to do so, and
|
||||
/// 2. we only care about lighting from the top, and only from the east and
|
||||
/// west (since at a large scale like this we mostly just want to
|
||||
/// handle variable sunlight; moonlight would present more challenges
|
||||
/// but we currently have no plans to try to cast accurate shadows in
|
||||
/// moonlight).
|
||||
///
|
||||
/// Our chosen format is two pairs of vectors,
|
||||
/// with the first pair representing west-facing light (casting shadows on
|
||||
/// the left side) and the second representing east-facing light
|
||||
/// (casting shadows on the east side).
|
||||
///
|
||||
/// The pair of vectors consists of (with each vector in the usual chunk
|
||||
/// order):
|
||||
///
|
||||
/// * Horizon angle pointing east (1 byte, scaled so 1 unit = 255° / 360).
|
||||
/// We might consider switching to tangent if that represents the
|
||||
/// information we care about better.
|
||||
/// * Approximate (floor) height of maximal occluder. We currently use this
|
||||
/// to try to deliver some approximation of soft shadows, which isn't that
|
||||
/// big a deal on the world map but is probably needed in order to ensure
|
||||
/// smooth transitions between chunks in LoD view. Additionally, when we
|
||||
/// start using the shadow information to do local lighting on the world
|
||||
/// map, we'll want a quick way to test where we can go out of shadoow at
|
||||
/// arbitrary heights (since the player and other entities cajn find
|
||||
/// themselves far from the ground at times). While this is only an
|
||||
/// approximation to a proper distance map, hopefully it will give us
|
||||
/// something that feels reasonable enough for Veloren's style.
|
||||
///
|
||||
/// NOTE: On compression.
|
||||
///
|
||||
/// Horizon mapping has a lot of advantages for height maps (simple, easy to
|
||||
/// understand, doesn't require any fancy math or approximation beyond
|
||||
/// precision loss), though it loses a few of them by having to store
|
||||
/// distance to occluder as well. However, just storing tons
|
||||
/// and tons of regular shadow maps (153 for a full day cycle, stored at
|
||||
/// irregular intervals) combined with clever explicit compression and
|
||||
/// avoiding recording sharp local shadows (preferring retracing for
|
||||
/// these), yielded a compression rate of under 3 bits per column! Since
|
||||
/// we likely want to avoid per-column shadows for worlds of the sizes we
|
||||
/// want, we'd still need to store *some* extra information to create
|
||||
/// soft shadows, but it would still be nice to try to drive down our
|
||||
/// size as much as possible given how compressible shadows of height
|
||||
/// maps seem to be in practice. Therefore, we try to take advantage of the
|
||||
/// way existing compression algorithms tend to work to see if we can
|
||||
/// achieve significant gains without doing a lot of custom work.
|
||||
///
|
||||
/// Specifically, since our rays are cast east/west, we expect that for each
|
||||
/// row, the horizon angles in each direction should be sequences of
|
||||
/// monotonically increasing values (as chunks approach a tall
|
||||
/// occluder), followed by sequences of no shadow, repeated
|
||||
/// until the end of the map. Monotonic sequences and same-byte sequences
|
||||
/// are usually easy to compress and existing algorithms are more likely
|
||||
/// to be able to deal with them than jumbled data. If we were to keep
|
||||
/// both directions in the same vector, off-the-shelf compression would
|
||||
/// probably be less effective.
|
||||
///
|
||||
/// For related reasons, rather than storing distances as in a standard
|
||||
/// distance map (which would lead to monotonically *decreaing* values
|
||||
/// as we approached the occluder from a given direction), we store the
|
||||
/// estimated *occluder height.* The idea here is that we replace the
|
||||
/// monotonic sequences with constant sequences, which are extremely
|
||||
/// straightforward to compress and mostly handled automatically by anything
|
||||
/// that does run-length encoding (i.e. most off-the-shelf compression
|
||||
/// algorithms).
|
||||
///
|
||||
/// We still need to benchmark this properly, as there's no guarantee our
|
||||
/// current compression algorithms will actually work well on this data
|
||||
/// in practice. It's possible that some other permutation (e.g. more
|
||||
/// bits reserved for "distance to occluder" in exchange for an even
|
||||
/// more predictible sequence) would end up compressing better than storing
|
||||
/// angles, or that we don't need as much precision as we currently have
|
||||
/// (256 possible angles).
|
||||
pub horizons: [(Vec<u8>, Vec<u8>); 2],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InviteAnswer {
|
||||
Accepted,
|
||||
@ -68,7 +189,7 @@ pub enum ServerMsg {
|
||||
server_info: ServerInfo,
|
||||
time_of_day: state::TimeOfDay,
|
||||
max_group_size: u32,
|
||||
world_map: (Vec2<u32>, Vec<u32>),
|
||||
world_map: WorldMapMsg,
|
||||
recipe_book: RecipeBook,
|
||||
},
|
||||
/// An error occurred while loading character data
|
||||
|
@ -453,10 +453,10 @@ pub struct Block {
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(kind: BlockKind, color: Rgb<u8>) -> Self {
|
||||
pub const fn new(kind: BlockKind, color: Rgb<u8>) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
color: color.into_array(),
|
||||
color: [color.r, color.g, color.b],
|
||||
}
|
||||
}
|
||||
|
||||
|
713
common/src/terrain/map.rs
Normal file
713
common/src/terrain/map.rs
Normal file
@ -0,0 +1,713 @@
|
||||
use super::{
|
||||
neighbors, quadratic_nearest_point, river_spline_coeffs, uniform_idx_as_vec2,
|
||||
vec2_as_uniform_idx, TerrainChunkSize, NEIGHBOR_DELTA, TERRAIN_CHUNK_BLOCKS_LG,
|
||||
};
|
||||
use crate::vol::RectVolSize;
|
||||
use core::{f32, f64, iter, ops::RangeInclusive};
|
||||
use vek::*;
|
||||
|
||||
/// Base two logarithm of the maximum size of the precomputed world, in meters,
|
||||
/// along the x (E/W) and y (N/S) dimensions.
|
||||
///
|
||||
/// NOTE: Each dimension is guaranteed to be a power of 2, so the logarithm is
|
||||
/// exact. This is so that it is possible (at least in theory) for compiler or
|
||||
/// runtime optimizations exploiting this are possible. For example, division
|
||||
/// by the chunk size can turn into a bit shift.
|
||||
///
|
||||
/// NOTE: As an invariant, this value is at least [TERRAIN_CHUNK_BLOCKS_LG].
|
||||
///
|
||||
/// NOTE: As an invariant, `(1 << [MAX_WORLD_BLOCKS_LG])` fits in an i32.
|
||||
///
|
||||
/// TODO: Add static assertions for the above invariants.
|
||||
///
|
||||
/// Currently, we define the maximum to be 19 (corresponding to 2^19 m) for both
|
||||
/// directions. This value was derived by backwards reasoning from the following
|
||||
/// conservative estimate of the maximum landmass area (using an approximation
|
||||
/// of 1024 blocks / km instead of 1000 blocks / km, which will result in an
|
||||
/// estimate that is strictly lower than the real landmass):
|
||||
///
|
||||
/// Max area (km²)
|
||||
/// ≌ (2^19 blocks * 1 km / 1024 blocks)^2
|
||||
/// = 2^((19 - 10) * 2) km²
|
||||
/// = 2^18 km²
|
||||
/// = 262,144 km²
|
||||
///
|
||||
/// which is roughly the same area as the entire United Kingdom, and twice the
|
||||
/// horizontal extent of Dwarf Fortress's largest map. Besides the comparison
|
||||
/// to other games without infinite or near-infinite maps (like Dwarf Fortress),
|
||||
/// there are other reasons to choose this as a good maximum size:
|
||||
///
|
||||
/// * It is large enough to include geological features of fairly realistic
|
||||
/// scale. It may be hard to do justice to truly enormous features like the
|
||||
/// Amazon River, and natural temperature variation not related to altitude
|
||||
/// would probably not produce climate extremes on an Earth-like planet, but
|
||||
/// it can comfortably fit enormous river basins, Everest-scale mountains,
|
||||
/// large islands and inland lakes, vast forests and deserts, and so on.
|
||||
///
|
||||
/// * It is large enough that making it from one side of the map to another will
|
||||
/// take a *very* long time. We show this with two examples. In each
|
||||
/// example, travel is either purely horizontal or purely vertical (to
|
||||
/// minimize distance traveled) across the whole map, and we assume there are
|
||||
/// no obstacles or slopes.
|
||||
///
|
||||
/// In example 1, a human is walking at the (real-time) speed of the fastest
|
||||
/// marathon runners (around 6 blocks / real-time s). We assume the human can
|
||||
/// maintain this pace indefinitely without stopping. Then crossing the map
|
||||
/// will take about:
|
||||
///
|
||||
/// 2^19 blocks * 1 real-time s / 6 blocks * 1 real-time min / 60 real-time s
|
||||
/// * 1 real-time hr / 60 real-time min * 1 real-time days / 24 hr = 2^19 / 6 /
|
||||
/// 60 / 60 / 24 real-time days ≌ 1 real-time day.
|
||||
///
|
||||
/// That's right--it will take a full day of *real* time to cross the map at
|
||||
/// an apparent speed of 6 m / s. Moreover, since in-game time passes at a
|
||||
/// rate of 1 in-game min / 1 in-game s, this would also take *60 days* of
|
||||
/// in-game time.
|
||||
///
|
||||
/// Still though, this is the rate of an ordinary human. And besides that, if
|
||||
/// we instead had a marathon runner traveling at 6 m / in-game s, it would
|
||||
/// take just 1 day of in-game time for the runner to cross the map, or a mere
|
||||
/// 0.4 hr of real time. To show that this rate of travel is unrealistic (and
|
||||
/// perhaps make an eventual argument for a slower real-time to in-game time
|
||||
/// conversion rate), our second example will consist of a high-speed train
|
||||
/// running at 300 km / real-time h (the fastest real-world high speed train
|
||||
/// averages under 270 k m / h, with 300 km / h as the designed top speed).
|
||||
/// For a train traveling at this apparent speed (in real time), crossing the
|
||||
/// map would take:
|
||||
///
|
||||
/// 2^19 blocks * 1 km / 1000 blocks * 1 real-time hr / 300 km
|
||||
/// = 2^19 / 1000 / 300 real-time hr
|
||||
/// ≌ 1.75 real-time hr
|
||||
///
|
||||
/// = 2^19 / 1000 / 300 real-time hr * 60 in-game hr / real-time hr
|
||||
/// * 1 in-game days / 24 in-game hr
|
||||
/// = 2^19 / 1000 / 300 * 60 / 24 in-game days
|
||||
/// ≌ 4.37 in-game days
|
||||
///
|
||||
/// In other words, something faster in real-time than any existing high-speed
|
||||
/// train would be over 4 times slower (in real-time) than our hypothetical
|
||||
/// top marathon runner running at 6 m / s in in-game speed. This suggests
|
||||
/// that the gap between in-game time and real-time is probably much too large
|
||||
/// for most purposes; however, what it definitely shows is that even
|
||||
/// extremely fast in-game transport across the world will not trivialize its
|
||||
/// size.
|
||||
///
|
||||
/// It follows that cities or towns of realistic scale, player housing,
|
||||
/// fields, and so on, will all fit comfortably on a map of this size, while
|
||||
/// at the same time still being reachable by non-warping, in-game mechanisms
|
||||
/// (such as high-speed transit). It also provides plenty of room for mounts
|
||||
/// of varying speeds, which can help ensure that players don't feel cramped or
|
||||
/// deliberately slowed down by their own speed.
|
||||
///
|
||||
/// * It is small enough that it is (barely) plausible that we could still
|
||||
/// generate maps for a world of this size using detailed and realistic
|
||||
/// erosion algorithms. At 1/4 of this map size along each dimension,
|
||||
/// generation currently takes around 5 hours on a good computer, and one
|
||||
/// could imagine (since the bottleneck step appears to be roughly O(n)) that
|
||||
/// with a smart implementation generation times of under a week could be
|
||||
/// achievable.
|
||||
///
|
||||
/// * The map extends further than the resolution of human eyesight under
|
||||
/// Earthlike conditions, even from tall mountains across clear landscapes.
|
||||
/// According to one calculation, even from Mt. Everest in the absence of
|
||||
/// cloud cover, you could only see for about 339 km before the Earth's
|
||||
/// horizon prevented you from seeing further, and other sources suggest that
|
||||
/// in practice the limit is closer to 160 km under realistic conditions. This
|
||||
/// implies that making the map much larger in a realistic way would require
|
||||
/// incorporating curvature, and also implies that any features that cannot
|
||||
/// fit on the map would not (under realistic atmospheric conditions) be fully
|
||||
/// visible from any point on Earth. Therefore, even if we cannot represent
|
||||
/// features larger than this accurately, nothing should be amiss from a
|
||||
/// visual perspective, so this should not significantly impact the player
|
||||
/// experience.
|
||||
pub const MAX_WORLD_BLOCKS_LG: Vec2<u32> = Vec2 { x: 19, y: 19 };
|
||||
|
||||
/// Base two logarithm of a world size, in chunks, per dimension
|
||||
/// (each dimension must be a power of 2, so the logarithm is exact).
|
||||
///
|
||||
/// NOTE: As an invariant, each dimension must be between 0 and
|
||||
/// `[MAX_WORLD_BLOCKS_LG] - [TERRAIN_CHUNK_BLOCKS_LG]`.
|
||||
///
|
||||
/// NOTE: As an invariant, `(1 << ([DEFAULT_WORLD_CHUNKS_LG] +
|
||||
/// [TERRAIN_CHUNK_BLOCKS_LG]))` fits in an i32 (derived from the invariant
|
||||
/// on [MAX_WORLD_BLOCKS_LG]).
|
||||
///
|
||||
/// NOTE: As an invariant, each dimension (in chunks) must fit in a u16.
|
||||
///
|
||||
/// NOTE: As an invariant, the product of dimensions (in chunks) must fit in a
|
||||
/// usize.
|
||||
///
|
||||
/// These invariants are all checked on construction of a `MapSizeLg`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MapSizeLg(Vec2<u32>);
|
||||
|
||||
impl MapSizeLg {
|
||||
// FIXME: We cannot use is_some() here because it is not currently marked as a
|
||||
// `const fn`. Since being able to use conditionals in constant expressions has
|
||||
// not technically been stabilized yet, Clippy probably doesn't check for this
|
||||
// case yet. When it can, or when is_some() is stabilized as a `const fn`,
|
||||
// we should deal with this.
|
||||
#[allow(clippy::redundant_pattern_matching)]
|
||||
/// Construct a new `MapSizeLg`, returning an error if the needed invariants
|
||||
/// do not hold and the vector otherwise.
|
||||
///
|
||||
/// TODO: In the future, we may use unsafe code to assert to the compiler
|
||||
/// that these invariants indeed hold, safely opening up optimizations
|
||||
/// that might not otherwise be available at runtime.
|
||||
#[inline(always)]
|
||||
pub const fn new(map_size_lg: Vec2<u32>) -> Result<Self, ()> {
|
||||
// Assertion on dimensions: must be between
|
||||
// 0 and ([MAX_WORLD_BLOCKS_LG] - [TERRAIN_CHUNK_BLOCKS_LG])
|
||||
let is_le_max = map_size_lg.x <= MAX_WORLD_BLOCKS_LG.x - TERRAIN_CHUNK_BLOCKS_LG
|
||||
&& map_size_lg.y <= MAX_WORLD_BLOCKS_LG.y - TERRAIN_CHUNK_BLOCKS_LG;
|
||||
// Assertion on dimensions: chunks must fit in a u16.
|
||||
let chunks_in_range =
|
||||
/* 1u16.checked_shl(map_size_lg.x).is_some() &&
|
||||
1u16.checked_shl(map_size_lg.y).is_some(); */
|
||||
map_size_lg.x <= 16 &&
|
||||
map_size_lg.y <= 16;
|
||||
if is_le_max && chunks_in_range {
|
||||
// Assertion on dimensions: blocks must fit in a i32.
|
||||
let blocks_in_range =
|
||||
/* 1i32.checked_shl(map_size_lg.x + TERRAIN_CHUNK_BLOCKS_LG).is_some() &&
|
||||
1i32.checked_shl(map_size_lg.y + TERRAIN_CHUNK_BLOCKS_LG).is_some(); */
|
||||
map_size_lg.x + TERRAIN_CHUNK_BLOCKS_LG < 32 &&
|
||||
map_size_lg.y + TERRAIN_CHUNK_BLOCKS_LG < 32;
|
||||
// Assertion on dimensions: product of dimensions must fit in a usize.
|
||||
let chunks_product_in_range =
|
||||
matches!(1usize.checked_shl(map_size_lg.x + map_size_lg.y), Some(_));
|
||||
if blocks_in_range && chunks_product_in_range {
|
||||
// Cleared all invariants.
|
||||
Ok(MapSizeLg(map_size_lg))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Acquire the `MapSizeLg`'s inner vector.
|
||||
pub const fn vec(self) -> Vec2<u32> { self.0 }
|
||||
|
||||
#[inline(always)]
|
||||
/// Get the size of this map in chunks.
|
||||
pub const fn chunks(self) -> Vec2<u16> { Vec2::new(1 << self.0.x, 1 << self.0.y) }
|
||||
|
||||
/// Get the size of an array of the correct size to hold all chunks.
|
||||
pub const fn chunks_len(self) -> usize { 1 << (self.0.x + self.0.y) }
|
||||
}
|
||||
|
||||
impl From<MapSizeLg> for Vec2<u32> {
|
||||
#[inline(always)]
|
||||
fn from(size: MapSizeLg) -> Self { size.vec() }
|
||||
}
|
||||
|
||||
pub struct MapConfig<'a> {
|
||||
/// Base two logarithm of the chunk dimensions of the base map.
|
||||
/// Has no default; set explicitly during initial orthographic projection.
|
||||
pub map_size_lg: MapSizeLg,
|
||||
/// Dimensions of the window being written to.
|
||||
///
|
||||
/// Defaults to `1 << [MapConfig::map_size_lg]`.
|
||||
pub dimensions: Vec2<usize>,
|
||||
/// x, y, and z of top left of map.
|
||||
///
|
||||
/// Default x and y are 0.0; no reasonable default for z, so set during
|
||||
/// initial orthographic projection.
|
||||
pub focus: Vec3<f64>,
|
||||
/// Altitude is divided by gain and clamped to [0, 1]; thus, decreasing gain
|
||||
/// makes smaller differences in altitude appear larger.
|
||||
///
|
||||
/// No reasonable default for z; set during initial orthographic projection.
|
||||
pub gain: f32,
|
||||
/// `fov` is used for shading purposes and refers to how much impact a
|
||||
/// change in the z direction has on the perceived slope relative to the
|
||||
/// same change in x and y.
|
||||
///
|
||||
/// It is stored as cos θ in the range (0, 1\] where θ is the FOV
|
||||
/// "half-angle" used for perspective projection. At 1.0, we treat it
|
||||
/// as the limit value for θ = 90 degrees, and use an orthographic
|
||||
/// projection.
|
||||
///
|
||||
/// Defaults to 1.0.
|
||||
///
|
||||
/// FIXME: This is a hack that tries to incorrectly implement a variant of
|
||||
/// perspective projection (which generates ∂P/∂x and ∂P/∂y for screen
|
||||
/// coordinate P by using the hyperbolic function \[assuming frustum of
|
||||
/// \[l, r, b, t, n, f\], rh coordinates, and output from -1 to 1 in
|
||||
/// s/t, 0 to 1 in r, and NDC is left-handed \[so visible z ranges from
|
||||
/// -n to -f\]\]):
|
||||
///
|
||||
/// P.s(x, y, z) = -1 + 2(-n/z x - l) / ( r - l)
|
||||
/// P.t(x, y, z) = -1 + 2(-n/z y - b) / ( t - b)
|
||||
/// P.r(x, y, z) = 0 + -f(-n/z - 1) / ( f - n)
|
||||
///
|
||||
/// Then arbitrarily using W_e_x = (r - l) as the width of the projected
|
||||
/// image, we have W_e_x = 2 n_e tan θ ⇒ tan Θ = (r - l) / (2n_e), for a
|
||||
/// perspective projection
|
||||
///
|
||||
/// (where θ is the half-angle of the FOV).
|
||||
///
|
||||
/// Taking the limit as θ → 90, we show that this degenrates to an
|
||||
/// orthogonal projection:
|
||||
///
|
||||
/// lim{n → ∞}(-f(-n / z - 1) / (f - n)) = -(z - -n) / (f - n).
|
||||
///
|
||||
/// (Proof not currently included, but has been formalized for the P.r case
|
||||
/// in Coq-tactic notation; the proof can be added on request, but is
|
||||
/// large and probably not well-suited to Rust documentation).
|
||||
///
|
||||
/// For this reason, we feel free to store `fov` as cos θ in the range (0,
|
||||
/// 1\].
|
||||
///
|
||||
/// However, `fov` does not actually work properly yet, so for now we just
|
||||
/// treat it as a visual gimmick.
|
||||
pub fov: f64,
|
||||
/// Scale is like gain, but for x and y rather than z.
|
||||
///
|
||||
/// Defaults to (1 << world_size_lg).x / dimensions.x (NOTE: fractional, not
|
||||
/// integer, division!).
|
||||
pub scale: f64,
|
||||
/// Vector that indicates which direction light is coming from, if shading
|
||||
/// is turned on.
|
||||
///
|
||||
/// Right-handed coordinate system: light is going left, down, and
|
||||
/// "backwards" (i.e. on the map, where we translate the y coordinate on
|
||||
/// the world map to z in the coordinate system, the light comes from -y
|
||||
/// on the map and points towards +y on the map). In a right
|
||||
/// handed coordinate system, the "camera" points towards -z, so positive z
|
||||
/// is backwards "into" the camera.
|
||||
///
|
||||
/// "In world space the x-axis will be pointing east, the y-axis up and the
|
||||
/// z-axis will be pointing south"
|
||||
///
|
||||
/// Defaults to (-0.8, -1.0, 0.3).
|
||||
pub light_direction: Vec3<f64>,
|
||||
/// If Some, uses the provided horizon map.
|
||||
///
|
||||
/// Defaults to None.
|
||||
pub horizons: Option<&'a [(Vec<f32>, Vec<f32>); 2]>,
|
||||
/// If true, only the basement (bedrock) is used for altitude; otherwise,
|
||||
/// the surface is used.
|
||||
///
|
||||
/// Defaults to false.
|
||||
pub is_basement: bool,
|
||||
/// If true, water is rendered; otherwise, the surface without water is
|
||||
/// rendered, even if it is underwater.
|
||||
///
|
||||
/// Defaults to true.
|
||||
pub is_water: bool,
|
||||
/// If true, 3D lighting and shading are turned on. Otherwise, a plain
|
||||
/// altitude map is used.
|
||||
///
|
||||
/// Defaults to true.
|
||||
pub is_shaded: bool,
|
||||
/// If true, the red component of the image is also used for temperature
|
||||
/// (redder is hotter). Defaults to false.
|
||||
pub is_temperature: bool,
|
||||
/// If true, the blue component of the image is also used for humidity
|
||||
/// (bluer is wetter).
|
||||
///
|
||||
/// Defaults to false.
|
||||
pub is_humidity: bool,
|
||||
/// Record debug information.
|
||||
///
|
||||
/// Defaults to false.
|
||||
pub is_debug: bool,
|
||||
}
|
||||
|
||||
pub const QUADRANTS: usize = 4;
|
||||
|
||||
pub struct MapDebug {
|
||||
pub quads: [[u32; QUADRANTS]; QUADRANTS],
|
||||
pub rivers: u32,
|
||||
pub lakes: u32,
|
||||
pub oceans: u32,
|
||||
}
|
||||
|
||||
/// Connection kind (per edge). Currently just supports rivers, but may be
|
||||
/// extended to support paths or at least one other kind of connection.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ConnectionKind {
|
||||
/// Connection forms a visible river.
|
||||
River,
|
||||
}
|
||||
|
||||
/// Map connection (per edge).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Connection {
|
||||
/// The kind of connection this is (e.g. river or path).
|
||||
pub kind: ConnectionKind,
|
||||
/// Assumed to be the "b" part of a 2d quadratic function.
|
||||
pub spline_derivative: Vec2<f32>,
|
||||
/// Width of the connection.
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
/// Per-chunk data the map needs to be able to sample in order to correctly
|
||||
/// render.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MapSample {
|
||||
/// the base RGB color for a particular map pixel using the current settings
|
||||
/// (i.e. the color *without* lighting).
|
||||
pub rgb: Rgb<u8>,
|
||||
/// Surface altitude information
|
||||
/// (correctly reflecting settings like is_basement and is_water)
|
||||
pub alt: f64,
|
||||
/// Downhill chunk (may not be meaningful on ocean tiles, or at least edge
|
||||
/// tiles)
|
||||
pub downhill_wpos: Vec2<i32>,
|
||||
/// Connection information about any connections to/from this chunk (e.g.
|
||||
/// rivers).
|
||||
///
|
||||
/// Connections at each index correspond to the same index in
|
||||
/// NEIGHBOR_DELTA.
|
||||
pub connections: Option<[Option<Connection>; 8]>,
|
||||
}
|
||||
|
||||
impl<'a> MapConfig<'a> {
|
||||
/// Constructs the configuration settings for an orthographic projection of
|
||||
/// a map from the top down, rendering (by default) the complete map to
|
||||
/// an image such that the chunk:pixel ratio is 1:1.
|
||||
///
|
||||
/// Takes two arguments: the base two logarithm of the horizontal map extent
|
||||
/// (in chunks), and the z bounds of the projection.
|
||||
pub fn orthographic(map_size_lg: MapSizeLg, z_bounds: RangeInclusive<f32>) -> Self {
|
||||
assert!(z_bounds.start() <= z_bounds.end());
|
||||
// NOTE: Safe cast since map_size_lg is restricted by the prior assert.
|
||||
let dimensions = map_size_lg.chunks().map(usize::from);
|
||||
Self {
|
||||
map_size_lg,
|
||||
dimensions,
|
||||
focus: Vec3::new(0.0, 0.0, f64::from(*z_bounds.start())),
|
||||
gain: z_bounds.end() - z_bounds.start(),
|
||||
fov: 1.0,
|
||||
scale: 1.0,
|
||||
light_direction: Vec3::new(-1.2, -1.0, 0.8),
|
||||
horizons: None,
|
||||
|
||||
is_basement: false,
|
||||
is_water: true,
|
||||
is_shaded: true,
|
||||
is_temperature: false,
|
||||
is_humidity: false,
|
||||
is_debug: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the base 2 logarithm of the underlying map size.
|
||||
pub fn map_size_lg(&self) -> MapSizeLg { self.map_size_lg }
|
||||
|
||||
/// Generates a map image using the specified settings. Note that it will
|
||||
/// write from left to write from (0, 0) to dimensions - 1, inclusive,
|
||||
/// with 4 1-byte color components provided as (r, g, b, a). It is up
|
||||
/// to the caller to provide a function that translates this information
|
||||
/// into the correct format for a buffer and writes to it.
|
||||
///
|
||||
/// sample_pos is a function that, given a chunk position, returns enough
|
||||
/// information about the chunk to attempt to render it on the map.
|
||||
/// When in doubt, try using `MapConfig::sample_pos` for this.
|
||||
///
|
||||
/// sample_wpos is a simple function that, given a *column* position,
|
||||
/// returns the approximate altitude at that column. When in doubt, try
|
||||
/// using `MapConfig::sample_wpos` for this.
|
||||
#[allow(clippy::if_same_then_else)] // TODO: Pending review in #587
|
||||
#[allow(clippy::unnested_or_patterns)] // TODO: Pending review in #587
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub fn generate(
|
||||
&self,
|
||||
sample_pos: impl Fn(Vec2<i32>) -> MapSample,
|
||||
sample_wpos: impl Fn(Vec2<i32>) -> f32,
|
||||
mut write_pixel: impl FnMut(Vec2<usize>, (u8, u8, u8, u8)),
|
||||
) -> MapDebug {
|
||||
let MapConfig {
|
||||
map_size_lg,
|
||||
dimensions,
|
||||
focus,
|
||||
gain,
|
||||
fov,
|
||||
scale,
|
||||
light_direction,
|
||||
horizons,
|
||||
|
||||
is_shaded,
|
||||
// is_debug,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let light_direction = Vec3::new(
|
||||
light_direction.x,
|
||||
light_direction.y,
|
||||
0.0, // we currently ignore light_direction.z.
|
||||
);
|
||||
let light_shadow_dir = if light_direction.x >= 0.0 { 0 } else { 1 };
|
||||
let horizon_map = horizons.map(|horizons| &horizons[light_shadow_dir]);
|
||||
let light = light_direction.normalized();
|
||||
let /*mut */quads = [[0u32; QUADRANTS]; QUADRANTS];
|
||||
let /*mut */rivers = 0u32;
|
||||
let /*mut */lakes = 0u32;
|
||||
let /*mut */oceans = 0u32;
|
||||
|
||||
let focus_rect = Vec2::from(focus);
|
||||
|
||||
let chunk_size = TerrainChunkSize::RECT_SIZE.map(|e| e as f64);
|
||||
|
||||
/* // NOTE: Asserting this to enable LLVM optimizations. Ideally we should come up
|
||||
// with a principled way to do this (especially one with no runtime
|
||||
// cost).
|
||||
assert!(
|
||||
map_size_lg
|
||||
.vec()
|
||||
.cmple(&(MAX_WORLD_BLOCKS_LG - TERRAIN_CHUNK_BLOCKS_LG))
|
||||
.reduce_and()
|
||||
); */
|
||||
let world_size = map_size_lg.chunks();
|
||||
|
||||
(0..dimensions.y * dimensions.x).for_each(|chunk_idx| {
|
||||
let i = chunk_idx % dimensions.x as usize;
|
||||
let j = chunk_idx / dimensions.x as usize;
|
||||
|
||||
let wposf = focus_rect + Vec2::new(i as f64, j as f64) * scale;
|
||||
let pos = wposf.map(|e: f64| e as i32);
|
||||
let wposf = wposf * chunk_size;
|
||||
|
||||
let chunk_idx = if pos.reduce_partial_min() >= 0
|
||||
&& pos.x < world_size.x as i32
|
||||
&& pos.y < world_size.y as i32
|
||||
{
|
||||
Some(vec2_as_uniform_idx(map_size_lg, pos))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let MapSample {
|
||||
rgb,
|
||||
alt,
|
||||
downhill_wpos,
|
||||
..
|
||||
} = sample_pos(pos);
|
||||
|
||||
let alt = alt as f32;
|
||||
let wposi = pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
|
||||
let mut rgb = rgb.map(|e| e as f64 / 255.0);
|
||||
|
||||
// Material properties:
|
||||
//
|
||||
// For each material in the scene,
|
||||
// k_s = (RGB) specular reflection constant
|
||||
let mut k_s = Rgb::new(1.0, 1.0, 1.0);
|
||||
// k_d = (RGB) diffuse reflection constant
|
||||
let mut k_d = rgb;
|
||||
// k_a = (RGB) ambient reflection constant
|
||||
let mut k_a = rgb;
|
||||
// α = (per-material) shininess constant
|
||||
let mut alpha = 4.0; // 4.0;
|
||||
|
||||
// Compute connections
|
||||
let mut has_river = false;
|
||||
// NOTE: consider replacing neighbors with local_cells, since it is more
|
||||
// accurate (though I'm not sure if it can matter for these
|
||||
// purposes).
|
||||
chunk_idx
|
||||
.into_iter()
|
||||
.flat_map(|chunk_idx| {
|
||||
neighbors(map_size_lg, chunk_idx).chain(iter::once(chunk_idx))
|
||||
})
|
||||
.for_each(|neighbor_posi| {
|
||||
let neighbor_pos = uniform_idx_as_vec2(map_size_lg, neighbor_posi);
|
||||
let neighbor_wpos = neighbor_pos.map(|e| e as f64) * chunk_size;
|
||||
let MapSample { connections, .. } = sample_pos(neighbor_pos);
|
||||
NEIGHBOR_DELTA
|
||||
.iter()
|
||||
.zip(connections.iter().flatten())
|
||||
.for_each(|(&delta, connection)| {
|
||||
let connection = if let Some(connection) = connection {
|
||||
connection
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let downhill_wpos = neighbor_wpos
|
||||
+ Vec2::from(delta).map(|e: i32| e as f64) * chunk_size;
|
||||
let coeffs = river_spline_coeffs(
|
||||
neighbor_wpos,
|
||||
connection.spline_derivative,
|
||||
downhill_wpos,
|
||||
);
|
||||
let (_t, _pt, dist) = if let Some((t, pt, dist)) =
|
||||
quadratic_nearest_point(&coeffs, wposf)
|
||||
{
|
||||
(t, pt, dist)
|
||||
} else {
|
||||
let ndist = wposf.distance_squared(neighbor_wpos);
|
||||
let ddist = wposf.distance_squared(downhill_wpos);
|
||||
if ndist <= ddist {
|
||||
(0.0, neighbor_wpos, ndist)
|
||||
} else {
|
||||
(1.0, downhill_wpos, ddist)
|
||||
}
|
||||
};
|
||||
let connection_dist =
|
||||
(dist.sqrt() - (connection.width as f64 * 0.5).max(1.0)).max(0.0);
|
||||
if connection_dist == 0.0 {
|
||||
match connection.kind {
|
||||
ConnectionKind::River => {
|
||||
has_river = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Color in connectins.
|
||||
let water_color_factor = 2.0;
|
||||
let g_water = 32.0 * water_color_factor;
|
||||
let b_water = 64.0 * water_color_factor;
|
||||
if has_river {
|
||||
let water_rgb = Rgb::new(0, ((g_water) * 1.0) as u8, ((b_water) * 1.0) as u8)
|
||||
.map(|e| e as f64 / 255.0);
|
||||
rgb = water_rgb;
|
||||
k_s = Rgb::new(1.0, 1.0, 1.0);
|
||||
k_d = water_rgb;
|
||||
k_a = water_rgb;
|
||||
alpha = 0.255;
|
||||
}
|
||||
|
||||
let downhill_alt = sample_wpos(downhill_wpos);
|
||||
let cross_pos = wposi
|
||||
+ ((downhill_wpos - wposi)
|
||||
.map(|e| e as f32)
|
||||
.rotated_z(f32::consts::FRAC_PI_2)
|
||||
.map(|e| e as i32));
|
||||
let cross_alt = sample_wpos(cross_pos);
|
||||
// TODO: Fix use of fov to match proper perspective projection, as described in
|
||||
// the doc comment.
|
||||
// Pointing downhill, forward
|
||||
// (index--note that (0,0,1) is backward right-handed)
|
||||
let forward_vec = Vec3::new(
|
||||
(downhill_wpos.x - wposi.x) as f64,
|
||||
((downhill_alt - alt) * gain) as f64 * fov,
|
||||
(downhill_wpos.y - wposi.y) as f64,
|
||||
);
|
||||
// Pointing 90 degrees left (in horizontal xy) of downhill, up
|
||||
// (middle--note that (1,0,0), 90 degrees CCW backward, is right right-handed)
|
||||
let up_vec = Vec3::new(
|
||||
(cross_pos.x - wposi.x) as f64,
|
||||
((cross_alt - alt) * gain) as f64 * fov,
|
||||
(cross_pos.y - wposi.y) as f64,
|
||||
);
|
||||
// let surface_normal = Vec3::new(fov* (f.y * u.z - f.z * u.y), -(f.x * u.z -
|
||||
// f.z * u.x), fov* (f.x * u.y - f.y * u.x)).normalized();
|
||||
// Then cross points "to the right" (upwards) on a right-handed coordinate
|
||||
// system. (right-handed coordinate system means (0, 0, 1.0) is
|
||||
// "forward" into the screen).
|
||||
let surface_normal = forward_vec.cross(up_vec).normalized();
|
||||
|
||||
// TODO: Figure out if we can reimplement debugging.
|
||||
/* if is_debug {
|
||||
let quad =
|
||||
|x: f32| ((x as f64 * QUADRANTS as f64).floor() as usize).min(QUADRANTS - 1);
|
||||
if river_kind.is_none() || humidity != 0.0 {
|
||||
quads[quad(humidity)][quad(temperature)] += 1;
|
||||
}
|
||||
match river_kind {
|
||||
Some(RiverKind::River { .. }) => {
|
||||
rivers += 1;
|
||||
},
|
||||
Some(RiverKind::Lake { .. }) => {
|
||||
lakes += 1;
|
||||
},
|
||||
Some(RiverKind::Ocean { .. }) => {
|
||||
oceans += 1;
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
} */
|
||||
|
||||
let shade_frac = horizon_map
|
||||
.and_then(|(angles, heights)| {
|
||||
chunk_idx
|
||||
.and_then(|chunk_idx| angles.get(chunk_idx))
|
||||
.map(|&e| (e as f64, heights))
|
||||
})
|
||||
.and_then(|(e, heights)| {
|
||||
chunk_idx
|
||||
.and_then(|chunk_idx| heights.get(chunk_idx))
|
||||
.map(|&f| (e, f as f64))
|
||||
})
|
||||
.map(|(angle, height)| {
|
||||
let w = 0.1;
|
||||
let height = (height - f64::from(alt * gain)).max(0.0);
|
||||
if angle != 0.0 && light_direction.x != 0.0 && height != 0.0 {
|
||||
let deltax = height / angle;
|
||||
let lighty = (light_direction.y / light_direction.x * deltax).abs();
|
||||
let deltay = lighty - height;
|
||||
let s = (deltay / deltax / w).min(1.0).max(0.0);
|
||||
// Smoothstep
|
||||
s * s * (3.0 - 2.0 * s)
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
})
|
||||
.unwrap_or(1.0);
|
||||
|
||||
let rgb = if is_shaded {
|
||||
// Phong reflection model with shadows:
|
||||
//
|
||||
// I_p = k_a i_a + shadow * Σ {m ∈ lights} (k_d (L_m ⋅ N) i_m,d + k_s (R_m ⋅
|
||||
// V)^α i_m,s)
|
||||
//
|
||||
// where for the whole scene,
|
||||
// i_a = (RGB) intensity of ambient lighting component
|
||||
let i_a = Rgb::new(0.1, 0.1, 0.1);
|
||||
// V = direction pointing towards the viewer (e.g. virtual camera).
|
||||
let v = Vec3::new(0.0, 0.0, -1.0).normalized();
|
||||
|
||||
// for each light m,
|
||||
// i_m,d = (RGB) intensity of diffuse component of light source m
|
||||
let i_m_d = Rgb::new(1.0, 1.0, 1.0);
|
||||
// i_m,s = (RGB) intensity of specular component of light source m
|
||||
let i_m_s = Rgb::new(0.45, 0.45, 0.45);
|
||||
|
||||
// for each light m and point p,
|
||||
// L_m = (normalized) direction vector from point on surface to light source m
|
||||
let l_m = light;
|
||||
// N = (normalized) normal at this point on the surface,
|
||||
let n = surface_normal;
|
||||
// R_m = (normalized) direction a perfectly reflected ray of light from m would
|
||||
// take from point p = 2(L_m ⋅ N)N - L_m
|
||||
let r_m = (-l_m).reflected(n); // 2 * (l_m.dot(n)) * n - l_m;
|
||||
//
|
||||
// and for each point p in the scene,
|
||||
// shadow = computed shadow factor at point p
|
||||
// FIXME: Should really just be shade_frac, but with only ambient light we lose
|
||||
// all local lighting detail... some sort of global illumination (e.g.
|
||||
// radiosity) is of course the "right" solution, but maybe we can find
|
||||
// something cheaper?
|
||||
let shadow = 0.2 + 0.8 * shade_frac;
|
||||
|
||||
let lambertian = l_m.dot(n).max(0.0);
|
||||
let spec_angle = r_m.dot(v).max(0.0);
|
||||
|
||||
let ambient = k_a * i_a;
|
||||
let diffuse = k_d * lambertian * i_m_d;
|
||||
let specular = k_s * spec_angle.powf(alpha) * i_m_s;
|
||||
(ambient + shadow * (diffuse + specular)).map(|e| e.min(1.0))
|
||||
} else {
|
||||
rgb
|
||||
}
|
||||
.map(|e| (e * 255.0) as u8);
|
||||
|
||||
let rgba = (rgb.r, rgb.g, rgb.b, 255);
|
||||
write_pixel(Vec2::new(i, j), rgba);
|
||||
});
|
||||
|
||||
MapDebug {
|
||||
quads,
|
||||
rivers,
|
||||
lakes,
|
||||
oceans,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,17 @@
|
||||
pub mod biome;
|
||||
pub mod block;
|
||||
pub mod chonk;
|
||||
pub mod map;
|
||||
pub mod structure;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
biome::BiomeKind,
|
||||
block::{Block, BlockKind},
|
||||
map::MapSizeLg,
|
||||
structure::Structure,
|
||||
};
|
||||
use roots::find_roots_cubic;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{vol::RectVolSize, volumes::vol_grid_2d::VolGrid2d};
|
||||
@ -19,8 +22,24 @@ use vek::*;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TerrainChunkSize;
|
||||
|
||||
/// Base two logarithm of the number of blocks along either horizontal axis of
|
||||
/// a chunk.
|
||||
///
|
||||
/// NOTE: (1 << CHUNK_SIZE_LG) is guaranteed to fit in a u32.
|
||||
///
|
||||
/// NOTE: A lot of code assumes that the two dimensions are equal, so we make it
|
||||
/// explicit here.
|
||||
///
|
||||
/// NOTE: It is highly unlikely that a value greater than 5 will work, as many
|
||||
/// frontend optimizations rely on being able to pack chunk horizontal
|
||||
/// dimensions into 5 bits each.
|
||||
pub const TERRAIN_CHUNK_BLOCKS_LG: u32 = 5;
|
||||
|
||||
impl RectVolSize for TerrainChunkSize {
|
||||
const RECT_SIZE: Vec2<u32> = Vec2 { x: 32, y: 32 };
|
||||
const RECT_SIZE: Vec2<u32> = Vec2 {
|
||||
x: (1 << TERRAIN_CHUNK_BLOCKS_LG),
|
||||
y: (1 << TERRAIN_CHUNK_BLOCKS_LG),
|
||||
};
|
||||
}
|
||||
|
||||
// TerrainChunkMeta
|
||||
@ -50,3 +69,140 @@ impl TerrainChunkMeta {
|
||||
|
||||
pub type TerrainChunk = chonk::Chonk<Block, TerrainChunkSize, TerrainChunkMeta>;
|
||||
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
||||
|
||||
// Terrain helper functions used across multiple crates.
|
||||
|
||||
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
||||
/// generated by uniform_noise.
|
||||
///
|
||||
/// NOTE: Dimensions obey constraints on [map::MapConfig::map_size_lg].
|
||||
#[inline(always)]
|
||||
pub fn uniform_idx_as_vec2(map_size_lg: MapSizeLg, idx: usize) -> Vec2<i32> {
|
||||
let x_mask = (1 << map_size_lg.vec().x) - 1;
|
||||
Vec2::new((idx & x_mask) as i32, (idx >> map_size_lg.vec().x) as i32)
|
||||
}
|
||||
|
||||
/// Computes the index of a Vec2 of a SimChunk from a position, where the index
|
||||
/// is generated by uniform_noise. NOTE: Both components of idx should be
|
||||
/// in-bounds!
|
||||
#[inline(always)]
|
||||
pub fn vec2_as_uniform_idx(map_size_lg: MapSizeLg, idx: Vec2<i32>) -> usize {
|
||||
((idx.y as usize) << map_size_lg.vec().x) | idx.x as usize
|
||||
}
|
||||
|
||||
// NOTE: want to keep this such that the chunk index is in ascending order!
|
||||
pub const NEIGHBOR_DELTA: [(i32, i32); 8] = [
|
||||
(-1, -1),
|
||||
(0, -1),
|
||||
(1, -1),
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(-1, 1),
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
/// Iterate through all cells adjacent to a chunk.
|
||||
#[inline(always)]
|
||||
pub fn neighbors(map_size_lg: MapSizeLg, posi: usize) -> impl Clone + Iterator<Item = usize> {
|
||||
let pos = uniform_idx_as_vec2(map_size_lg, posi);
|
||||
let world_size = map_size_lg.chunks();
|
||||
NEIGHBOR_DELTA
|
||||
.iter()
|
||||
.map(move |&(x, y)| Vec2::new(pos.x + x, pos.y + y))
|
||||
.filter(move |pos| {
|
||||
pos.x >= 0 && pos.y >= 0 && pos.x < world_size.x as i32 && pos.y < world_size.y as i32
|
||||
})
|
||||
.map(move |pos| vec2_as_uniform_idx(map_size_lg, pos))
|
||||
}
|
||||
|
||||
pub fn river_spline_coeffs(
|
||||
// _sim: &WorldSim,
|
||||
chunk_pos: Vec2<f64>,
|
||||
spline_derivative: Vec2<f32>,
|
||||
downhill_pos: Vec2<f64>,
|
||||
) -> Vec3<Vec2<f64>> {
|
||||
let dxy = downhill_pos - chunk_pos;
|
||||
// Since all splines have been precomputed, we don't have to do that much work
|
||||
// to evaluate the spline. The spline is just ax^2 + bx + c = 0, where
|
||||
//
|
||||
// a = dxy - chunk.river.spline_derivative
|
||||
// b = chunk.river.spline_derivative
|
||||
// c = chunk_pos
|
||||
let spline_derivative = spline_derivative.map(|e| e as f64);
|
||||
Vec3::new(dxy - spline_derivative, spline_derivative, chunk_pos)
|
||||
}
|
||||
|
||||
/// Find the nearest point from a quadratic spline to this point (in terms of t,
|
||||
/// the "distance along the curve" by which our spline is parameterized). Note
|
||||
/// that if t < 0.0 or t >= 1.0, we probably shouldn't be considered "on the
|
||||
/// curve"... hopefully this works out okay and gives us what we want (a
|
||||
/// river that extends outwards tangent to a quadratic curve, with width
|
||||
/// configured by distance along the line).
|
||||
#[allow(clippy::let_and_return)] // TODO: Pending review in #587
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub fn quadratic_nearest_point(
|
||||
spline: &Vec3<Vec2<f64>>,
|
||||
point: Vec2<f64>,
|
||||
) -> Option<(f64, Vec2<f64>, f64)> {
|
||||
let a = spline.z.x;
|
||||
let b = spline.y.x;
|
||||
let c = spline.x.x;
|
||||
let d = point.x;
|
||||
let e = spline.z.y;
|
||||
let f = spline.y.y;
|
||||
let g = spline.x.y;
|
||||
let h = point.y;
|
||||
// This is equivalent to solving the following cubic equation (derivation is a
|
||||
// bit annoying):
|
||||
//
|
||||
// A = 2(c^2 + g^2)
|
||||
// B = 3(b * c + g * f)
|
||||
// C = ((a - d) * 2 * c + b^2 + (e - h) * 2 * g + f^2)
|
||||
// D = ((a - d) * b + (e - h) * f)
|
||||
//
|
||||
// Ax³ + Bx² + Cx + D = 0
|
||||
//
|
||||
// Once solved, this yield up to three possible values for t (reflecting minimal
|
||||
// and maximal values). We should choose the minimal such real value with t
|
||||
// between 0.0 and 1.0. If we fall outside those bounds, then we are
|
||||
// outside the spline and return None.
|
||||
let a_ = (c * c + g * g) * 2.0;
|
||||
let b_ = (b * c + g * f) * 3.0;
|
||||
let a_d = a - d;
|
||||
let e_h = e - h;
|
||||
let c_ = a_d * c * 2.0 + b * b + e_h * g * 2.0 + f * f;
|
||||
let d_ = a_d * b + e_h * f;
|
||||
let roots = find_roots_cubic(a_, b_, c_, d_);
|
||||
let roots = roots.as_ref();
|
||||
|
||||
let min_root = roots
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(|root| {
|
||||
let river_point = spline.x * root * root + spline.y * root + spline.z;
|
||||
let river_zero = spline.z;
|
||||
let river_one = spline.x + spline.y + spline.z;
|
||||
if root > 0.0 && root < 1.0 {
|
||||
Some((root, river_point))
|
||||
} else if river_point.distance_squared(river_zero) < 0.5 {
|
||||
Some((root, /*river_point*/ river_zero))
|
||||
} else if river_point.distance_squared(river_one) < 0.5 {
|
||||
Some((root, /*river_point*/ river_one))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|(root, river_point)| {
|
||||
let river_distance = river_point.distance_squared(point);
|
||||
(root, river_point, river_distance)
|
||||
})
|
||||
// In the (unlikely?) case that distances are equal, prefer the earliest point along the
|
||||
// river.
|
||||
.min_by(|&(ap, _, a), &(bp, _, b)| {
|
||||
(a, ap < 0.0 || ap > 1.0, ap)
|
||||
.partial_cmp(&(b, bp < 0.0 || bp > 1.0, bp))
|
||||
.unwrap()
|
||||
});
|
||||
min_root
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::BlockKind;
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
make_case_elim,
|
||||
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
|
||||
volumes::dyna::{Dyna, DynaError},
|
||||
};
|
||||
@ -9,25 +10,29 @@ use serde::Deserialize;
|
||||
use std::{fs::File, io::BufReader, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum StructureBlock {
|
||||
None,
|
||||
Grass,
|
||||
TemperateLeaves,
|
||||
PineLeaves,
|
||||
Acacia,
|
||||
Mangrove,
|
||||
PalmLeavesInner,
|
||||
PalmLeavesOuter,
|
||||
Water,
|
||||
GreenSludge,
|
||||
Fruit,
|
||||
Coconut,
|
||||
Chest,
|
||||
Hollow,
|
||||
Liana,
|
||||
Normal(Rgb<u8>),
|
||||
}
|
||||
make_case_elim!(
|
||||
structure_block,
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(u32)]
|
||||
pub enum StructureBlock {
|
||||
None = 0,
|
||||
Grass = 1,
|
||||
TemperateLeaves = 2,
|
||||
PineLeaves = 3,
|
||||
Acacia = 4,
|
||||
Mangrove = 5,
|
||||
PalmLeavesInner = 6,
|
||||
PalmLeavesOuter = 7,
|
||||
Water = 8,
|
||||
GreenSludge = 9,
|
||||
Fruit = 10,
|
||||
Coconut = 11,
|
||||
Chest = 12,
|
||||
Hollow = 13,
|
||||
Liana = 14,
|
||||
Normal(color: Rgb<u8>) = 15,
|
||||
}
|
||||
);
|
||||
|
||||
impl Vox for StructureBlock {
|
||||
fn empty() -> Self { StructureBlock::None }
|
||||
|
243
common/src/typed.rs
Normal file
243
common/src/typed.rs
Normal file
@ -0,0 +1,243 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
pub trait SubContext<Context> {
|
||||
fn sub_context(self) -> Context;
|
||||
}
|
||||
|
||||
impl<Context> SubContext<Context> for Context {
|
||||
fn sub_context(self) -> Context { self }
|
||||
}
|
||||
|
||||
impl<Head, Tail> SubContext<Tail> for (Head, Tail) {
|
||||
fn sub_context(self) -> Tail { self.1 }
|
||||
}
|
||||
|
||||
pub trait Typed<Context, Type, S> {
|
||||
fn reduce(self, context: Context) -> (Type, S);
|
||||
}
|
||||
|
||||
pub struct Pure<T>(pub T);
|
||||
|
||||
impl<Context: SubContext<S>, T, S> Typed<Context, Pure<T>, S> for T {
|
||||
fn reduce(self, context: Context) -> (Pure<T>, S) { (Pure(self), context.sub_context()) }
|
||||
}
|
||||
|
||||
/// A lazy pattern match reified as a Rust type.
|
||||
///
|
||||
/// `expr` is the expression being matched on, generally of some enum type `Ty`.
|
||||
///
|
||||
/// `case` represents the pattern match--it will generally be a structure with
|
||||
/// one field per constructor in `Ty`. The field should contain enough
|
||||
/// information to run the match arm for that constructor, given the information
|
||||
/// contained in the constructor arguments.
|
||||
///
|
||||
/// `ty` represents the return type of the match expression. It does not carry
|
||||
/// any runtime-relevant information, but is needed in order to simplify our
|
||||
/// trait definitions.
|
||||
///
|
||||
/// The intent is that you should not construct this structure directly, nor
|
||||
/// should you define or construct the `Cases` structure directly. Instead, to
|
||||
/// use this you are expected to wrap your enum declaration in a call to
|
||||
/// [make_case_elim!], as follows:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(arbitrary_enum_discriminant)]
|
||||
/// # #[macro_use] extern crate veloren_common;
|
||||
///
|
||||
/// veloren_common::make_case_elim!(
|
||||
/// my_type_module,
|
||||
/// #[repr(u32)]
|
||||
/// #[derive(Clone,Copy)]
|
||||
/// pub enum MyType {
|
||||
/// Constr1 = 0,
|
||||
/// Constr2(arg : u8) = 1,
|
||||
/// /* ..., */
|
||||
/// }
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// This macro automatically does a few things. First, it creates the `enum`
|
||||
/// type `MyType` in the current scope, as expected. Second, it creates a
|
||||
/// module named `my_type_module` in the current scope, into which it dumps a
|
||||
/// few things. In this case:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(arbitrary_enum_discriminant)]
|
||||
/// # #[macro_use] extern crate veloren_common;
|
||||
///
|
||||
/// #[repr(u32)]
|
||||
/// #[derive(Clone, Copy)]
|
||||
/// pub enum MyType {
|
||||
/// Constr1 = 0,
|
||||
/// Constr2(u8) = 1,
|
||||
/// /* ..., */
|
||||
/// }
|
||||
///
|
||||
/// # #[allow(non_snake_case)]
|
||||
/// # #[allow(dead_code)]
|
||||
/// mod my_type_module {
|
||||
/// use ::serde::{Deserialize, Serialize};
|
||||
///
|
||||
/// /// The number of variants in this enum.
|
||||
/// pub const NUM_VARIANTS: usize = 2;
|
||||
///
|
||||
/// /// An array of all the variant indices (in theory, this can be used by this or other
|
||||
/// /// macros in order to easily build up things like uniform random samplers).
|
||||
/// pub const ALL_INDICES: [u32; NUM_VARIANTS] = [0, 1];
|
||||
///
|
||||
/// /// A convenience trait used to store a different type for each constructor in this
|
||||
/// /// pattern.
|
||||
/// pub trait PackedElim {
|
||||
/// type Constr1;
|
||||
/// type Constr2;
|
||||
/// }
|
||||
///
|
||||
/// /// The actual *cases.* If you think of pattern match arms as being closures that accept
|
||||
/// /// the cconstructor types as arguments, you can think of this structure as somehow
|
||||
/// /// representing just the data *owned* by the closure. This is also what you will
|
||||
/// /// generally store in your ron file--it has a field for each constructor of your enum,
|
||||
/// /// with the types of all the fields specified by the implementation of [PackedElim] for
|
||||
/// /// the [Elim] argument. Each field has the same name as the constructor it represents.
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// pub struct Cases<Elim: PackedElim> {
|
||||
/// pub Constr1: Elim::Constr1,
|
||||
/// pub Constr2: Elim::Constr2,
|
||||
/// }
|
||||
///
|
||||
/// /// Finally, because it represents by an overwhelming margin the most common usecase, we
|
||||
/// /// predefine a particular pattern matching strategy--"pure"--where every arm holds data of
|
||||
/// /// the exact same type, T.
|
||||
/// impl<T> PackedElim for veloren_common::typed::Pure<T> {
|
||||
/// type Constr1 = T;
|
||||
/// type Constr2 = T;
|
||||
/// }
|
||||
///
|
||||
/// /// Because PureCases is so convenient, we have an alias for it. Thus, in order to
|
||||
/// /// represent a pattern match on an argument that returns a constant of type (u8,u8,u8) for
|
||||
/// /// each arm, you'd use the type `PureCases<(u8, u8, u8)>`.
|
||||
/// pub type PureCases<Elim> = Cases<veloren_common::typed::Pure<Elim>>;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Finally, a useful implementation of the [Typed] trait completes this story,
|
||||
/// providing a way to evaluate this lazy math statement within Rust.
|
||||
/// Unfortunately, [Typed] is quite complicated, and this story is still being
|
||||
/// fully evaluated, so showing teh type may not be that elucidating.
|
||||
/// Instead, we'll just present the method you can use most easily to pattern
|
||||
/// match using the PureCases pattern we mentioned earlier:
|
||||
///
|
||||
/// pub fn elim_case_pure<'a, Type>(&'a self, cases: &'a $mod::PureCases<Type>)
|
||||
/// -> &'a Type
|
||||
///
|
||||
/// If self is expression of your defined enum type, and match data defined by
|
||||
/// PureCases, this evaluates the pattern match on self and returns the matched
|
||||
/// case.
|
||||
///
|
||||
/// To see how this is used in more detail, check out
|
||||
/// `common/src/body/humanoid.rs`; it is also used extensively in the world
|
||||
/// repository.
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
/// Limitations:
|
||||
///
|
||||
/// Unfortunately, due to restrictions on procedural macros, we currently always
|
||||
/// require the types defined to #[repr(inttype)] as you can see above. There
|
||||
/// are also some other current limitations that we hopefully will be able to
|
||||
/// lift at some point; struct variants are not yet supported, and neither
|
||||
/// attributes on fields.
|
||||
#[fundamental]
|
||||
pub struct ElimCase<Expr, Cases, Type> {
|
||||
pub expr: Expr,
|
||||
pub cases: Cases,
|
||||
pub ty: PhantomData<Type>,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! as_item {
|
||||
($i:item) => {
|
||||
$i
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! make_case_elim {
|
||||
($mod:ident, $( #[$ty_attr:meta] )* $vis:vis enum $ty:ident {
|
||||
$( $constr:ident $( ( $( $arg_name:ident : $arg_ty:ty ),* ) )? = $index:expr ),* $(,)?
|
||||
}) => {
|
||||
$crate::as_item! {
|
||||
$( #[$ty_attr] )*
|
||||
$vis enum $ty {
|
||||
$( $constr $( ($( $arg_ty, )*) )? = $index, )*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
$vis mod $mod {
|
||||
use ::serde::{Deserialize, Serialize};
|
||||
|
||||
pub const NUM_VARIANTS: usize = 0 $( + { let _ = $index; 1 } )*;
|
||||
|
||||
pub const ALL_INDICES: [u32; NUM_VARIANTS] = [ $( $index, )* ];
|
||||
|
||||
pub trait PackedElim {
|
||||
$( type $constr; )*
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Cases<Elim: PackedElim> {
|
||||
$( pub $constr : Elim::$constr, )*
|
||||
}
|
||||
|
||||
impl<T> PackedElim for $crate::typed::Pure<T> {
|
||||
$( type $constr = T; )*
|
||||
}
|
||||
|
||||
pub type PureCases<Elim> = Cases<$crate::typed::Pure<Elim>>;
|
||||
}
|
||||
|
||||
#[allow(unused_parens)]
|
||||
impl<'a, Elim: $mod::PackedElim, Context, Type, S>
|
||||
$crate::typed::Typed<Context, Type, S> for $crate::typed::ElimCase<&'a $ty, &'a $mod::Cases<Elim>, Type>
|
||||
where
|
||||
$( &'a Elim::$constr: $crate::typed::Typed<($( ($( &'a $arg_ty, )*), )? Context), Type, S>, )*
|
||||
{
|
||||
fn reduce(self, context: Context) -> (Type, S)
|
||||
{
|
||||
let Self { expr, cases, .. } = self;
|
||||
match expr {
|
||||
$( $ty::$constr $( ($( $arg_name, )*) )? =>
|
||||
<_ as $crate::typed::Typed<_, Type, _>>::reduce(
|
||||
&cases.$constr,
|
||||
($( ($( $arg_name, )*), )? context),
|
||||
),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $ty {
|
||||
pub fn elim_case<'a, Elim: $mod::PackedElim, Context, S, Type>(&'a self, cases: &'a $mod::Cases<Elim>, context: Context) ->
|
||||
(Type, S)
|
||||
where
|
||||
$crate::typed::ElimCase<&'a $ty, &'a $mod::Cases<Elim>, Type> : $crate::typed::Typed<Context, Type, S>,
|
||||
{
|
||||
use $crate::typed::Typed;
|
||||
|
||||
let case = $crate::typed::ElimCase {
|
||||
expr: self,
|
||||
cases,
|
||||
ty: ::core::marker::PhantomData,
|
||||
};
|
||||
case.reduce(context)
|
||||
}
|
||||
|
||||
pub fn elim_case_pure<'a, Type>(&'a self, cases: &'a $mod::PureCases<Type>) -> &'a Type
|
||||
{
|
||||
let ($crate::typed::Pure(expr), ()) = self.elim_case(cases, ());
|
||||
expr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -98,13 +98,20 @@ pub fn hsv_to_rgb(hsv: Vec3<f32>) -> Rgb<f32> {
|
||||
Rgb::new(r + m, g + m, b + m)
|
||||
}
|
||||
|
||||
/// Convert linear rgb to CIEXYZ
|
||||
#[inline(always)]
|
||||
pub fn rgb_to_xyz(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
// XYZ
|
||||
Mat3::new(
|
||||
0.4124, 0.3576, 0.1805, 0.2126, 0.7152, 0.0722, 0.0193, 0.1192, 0.9504,
|
||||
) * Vec3::from(rgb)
|
||||
}
|
||||
|
||||
/// Convert linear rgb to CIExyY
|
||||
#[inline(always)]
|
||||
pub fn rgb_to_xyy(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
// XYZ
|
||||
let xyz = Mat3::new(
|
||||
0.4124, 0.3576, 0.1805, 0.2126, 0.7152, 0.0722, 0.0193, 0.1192, 0.9504,
|
||||
) * Vec3::from(rgb);
|
||||
let xyz = rgb_to_xyz(rgb);
|
||||
|
||||
let sum = xyz.sum();
|
||||
Vec3::new(xyz.x / sum, xyz.y / sum, xyz.y)
|
||||
|
@ -25,7 +25,7 @@ pub trait BaseVol {
|
||||
type Vox: Vox;
|
||||
type Error: Debug;
|
||||
|
||||
fn scaled_by(&self, scale: Vec3<f32>) -> Scaled<Self>
|
||||
fn scaled_by(self, scale: Vec3<f32>) -> Scaled<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -1,28 +1,36 @@
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox};
|
||||
use vek::*;
|
||||
|
||||
pub struct Scaled<'a, V> {
|
||||
pub inner: &'a V,
|
||||
pub struct Scaled<V> {
|
||||
pub inner: V,
|
||||
pub scale: Vec3<f32>,
|
||||
}
|
||||
|
||||
impl<'a, V: BaseVol> BaseVol for Scaled<'a, V> {
|
||||
impl<V: BaseVol> BaseVol for Scaled<V> {
|
||||
type Error = V::Error;
|
||||
type Vox = V::Vox;
|
||||
}
|
||||
|
||||
impl<'a, V: ReadVol> ReadVol for Scaled<'a, V> {
|
||||
impl<V: ReadVol> ReadVol for Scaled<V> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
|
||||
let ideal_pos = pos.map2(self.scale, |e, scale| e as f32 / scale);
|
||||
let pos = ideal_pos.map(|e| e.trunc() as i32);
|
||||
// let ideal_pos = pos.map2(self.scale, |e, scale| (e as f32 + 0.5) / scale);
|
||||
// let pos = ideal_pos.map(|e| e.trunc() as i32);
|
||||
let min_pos = pos.map2(self.scale, |e, scale| ((e as f32) / scale).floor() as i32);
|
||||
let max_pos = pos.map2(self.scale, |e, scale| {
|
||||
((e as f32 + 1.0) / scale).ceil() as i32
|
||||
});
|
||||
let pos = pos.map2(self.scale, |e, scale| {
|
||||
(((e as f32 + 0.5) / scale) - 0.5).round() as i32
|
||||
});
|
||||
|
||||
let ideal_search_size = Vec3::<f32>::one() / self.scale;
|
||||
// let ideal_search_size = Vec3::<f32>::one() / self.scale;
|
||||
let range_iter = |i: usize| {
|
||||
std::iter::successors(Some(0), |p| Some(if *p < 0 { -*p } else { -(*p + 1) }))
|
||||
.take_while(move |p| {
|
||||
((ideal_pos[i] - ideal_search_size[i] / 2.0).round() as i32
|
||||
..(ideal_pos[i] + ideal_search_size[i] / 2.0).round() as i32)
|
||||
(min_pos[i]..max_pos[i])
|
||||
/* ((ideal_pos[i] - ideal_search_size[i] / 2.0).ceil() as i32
|
||||
..(ideal_pos[i] + ideal_search_size[i] / 2.0).ceil() as i32) */
|
||||
.contains(&(pos[i] + *p))
|
||||
})
|
||||
};
|
||||
@ -36,7 +44,7 @@ impl<'a, V: ReadVol> ReadVol for Scaled<'a, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: SizedVol> SizedVol for Scaled<'a, V> {
|
||||
impl<V: SizedVol> SizedVol for Scaled<V> {
|
||||
#[inline(always)]
|
||||
fn lower_bound(&self) -> Vec3<i32> {
|
||||
self.inner
|
||||
@ -48,6 +56,6 @@ impl<'a, V: SizedVol> SizedVol for Scaled<'a, V> {
|
||||
fn upper_bound(&self) -> Vec3<i32> {
|
||||
self.inner
|
||||
.upper_bound()
|
||||
.map2(self.scale, |e, scale| (e as f32 * scale).ceil() as i32 + 1)
|
||||
.map2(self.scale, |e, scale| (e as f32 * scale).ceil() as i32)
|
||||
}
|
||||
}
|
||||
|
@ -99,37 +99,17 @@ pub(crate) fn partial_eq_io_error(first: &io::Error, second: &io::Error) -> bool
|
||||
}
|
||||
|
||||
pub(crate) fn partial_eq_bincode(first: &bincode::ErrorKind, second: &bincode::ErrorKind) -> bool {
|
||||
use bincode::ErrorKind::*;
|
||||
match *first {
|
||||
bincode::ErrorKind::Io(ref f) => match *second {
|
||||
bincode::ErrorKind::Io(ref s) => partial_eq_io_error(f, s),
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidUtf8Encoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidUtf8Encoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidBoolEncoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidBoolEncoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidCharEncoding => {
|
||||
matches!(*second, bincode::ErrorKind::InvalidCharEncoding)
|
||||
},
|
||||
bincode::ErrorKind::InvalidTagEncoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidTagEncoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::DeserializeAnyNotSupported => {
|
||||
matches!(*second, bincode::ErrorKind::DeserializeAnyNotSupported)
|
||||
},
|
||||
bincode::ErrorKind::SizeLimit => matches!(*second, bincode::ErrorKind::SizeLimit),
|
||||
bincode::ErrorKind::SequenceMustHaveLength => {
|
||||
matches!(*second, bincode::ErrorKind::SequenceMustHaveLength)
|
||||
},
|
||||
bincode::ErrorKind::Custom(ref f) => match *second {
|
||||
bincode::ErrorKind::Custom(ref s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
Io(ref f) => matches!(*second, Io(ref s) if partial_eq_io_error(f, s)),
|
||||
InvalidUtf8Encoding(f) => matches!(*second, InvalidUtf8Encoding(s) if f == s),
|
||||
InvalidBoolEncoding(f) => matches!(*second, InvalidBoolEncoding(s) if f == s),
|
||||
InvalidCharEncoding => matches!(*second, InvalidCharEncoding),
|
||||
InvalidTagEncoding(f) => matches!(*second, InvalidTagEncoding(s) if f == s),
|
||||
DeserializeAnyNotSupported => matches!(*second, DeserializeAnyNotSupported),
|
||||
SizeLimit => matches!(*second, SizeLimit),
|
||||
SequenceMustHaveLength => matches!(*second, SequenceMustHaveLength),
|
||||
Custom(ref f) => matches!(*second, Custom(ref s) if f == s),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "spec
|
||||
|
||||
tracing = "0.1"
|
||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["shred-derive"], rev = "7a2e348ab2223818bad487695c66c43db88050a5" }
|
||||
vek = "0.11.0"
|
||||
vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] }
|
||||
uvth = "3.1.1"
|
||||
futures-util = "0.3"
|
||||
futures-executor = "0.3"
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
use crate::test_world::World;
|
||||
use crate::test_world::{IndexOwned, World};
|
||||
use common::{generation::ChunkSupplement, terrain::TerrainChunk};
|
||||
use crossbeam::channel;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
@ -9,11 +9,12 @@ use std::sync::{
|
||||
Arc,
|
||||
};
|
||||
use vek::*;
|
||||
#[cfg(feature = "worldgen")] use world::World;
|
||||
#[cfg(feature = "worldgen")]
|
||||
use world::{IndexOwned, World};
|
||||
|
||||
type ChunkGenResult = (
|
||||
Vec2<i32>,
|
||||
Result<(TerrainChunk, ChunkSupplement), EcsEntity>,
|
||||
Result<(TerrainChunk, ChunkSupplement), Option<EcsEntity>>,
|
||||
);
|
||||
|
||||
pub struct ChunkGenerator {
|
||||
@ -34,10 +35,11 @@ impl ChunkGenerator {
|
||||
|
||||
pub fn generate_chunk(
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
entity: Option<EcsEntity>,
|
||||
key: Vec2<i32>,
|
||||
thread_pool: &mut uvth::ThreadPool,
|
||||
world: Arc<World>,
|
||||
index: IndexOwned,
|
||||
) {
|
||||
let v = if let Entry::Vacant(v) = self.pending_chunks.entry(key) {
|
||||
v
|
||||
@ -48,8 +50,9 @@ impl ChunkGenerator {
|
||||
v.insert(Arc::clone(&cancel));
|
||||
let chunk_tx = self.chunk_tx.clone();
|
||||
thread_pool.execute(move || {
|
||||
let index = index.as_index_ref();
|
||||
let payload = world
|
||||
.generate_chunk(key, || cancel.load(Ordering::Relaxed))
|
||||
.generate_chunk(index, key, || cancel.load(Ordering::Relaxed))
|
||||
.map_err(|_| entity);
|
||||
let _ = chunk_tx.send((key, payload));
|
||||
});
|
||||
@ -74,4 +77,10 @@ impl ChunkGenerator {
|
||||
cancel.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cancel_all(&mut self) {
|
||||
self.pending_chunks.drain().for_each(|(_, cancel)| {
|
||||
cancel.store(true, Ordering::Relaxed);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1473,7 +1473,7 @@ fn handle_debug_column(
|
||||
let spawn_rate = sim.get_interpolated(wpos, |chunk| chunk.spawn_rate)?;
|
||||
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
||||
let chunk = sim.get(chunk_pos)?;
|
||||
let col = sampler.get((wpos, server.world.index()))?;
|
||||
let col = sampler.get((wpos, server.index.as_index_ref()))?;
|
||||
let downhill = chunk.downhill;
|
||||
let river = &chunk.river;
|
||||
let flux = chunk.flux;
|
||||
|
@ -119,7 +119,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
|
||||
.create_object(Pos(pos), comp::object::Body::CampfireLit)
|
||||
.with(LightEmitter {
|
||||
col: Rgb::new(1.0, 0.65, 0.2),
|
||||
strength: 2.0,
|
||||
strength: 5.0,
|
||||
flicker: 1.0,
|
||||
animated: true,
|
||||
})
|
||||
|
@ -33,6 +33,14 @@ pub fn handle_damage(server: &Server, uid: Uid, change: HealthChange) {
|
||||
/// other players. If the entity that killed it had stats, then give it exp for
|
||||
/// the kill. Experience given is equal to the level of the entity that was
|
||||
/// killed times 10.
|
||||
// NOTE: Clippy incorrectly warns about a needless collect here because it does not
|
||||
// understand that the pet count (which is computed during the first iteration over the
|
||||
// members in range) is actually used by the second iteration over the members in range;
|
||||
// since we have no way of knowing the pet count before the first loop finishes, we
|
||||
// definitely need at least two loops. Then (currently) our only options are to store
|
||||
// the member list in temporary space (e.g. by collecting to a vector), or to repeat
|
||||
// the loop; but repeating the loop would currently be very inefficient since it has to
|
||||
// rescan every entity on the server again.
|
||||
#[allow(clippy::needless_collect)]
|
||||
pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSource) {
|
||||
let state = server.state_mut();
|
||||
|
@ -337,6 +337,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
.and_then(|ldt| slot::loadout_remove(slot, ldt)),
|
||||
};
|
||||
|
||||
// FIXME: We should really require the drop and write to be atomic!
|
||||
if let (Some(item), Some(pos)) =
|
||||
(item, state.ecs().read_storage::<comp::Pos>().get(entity))
|
||||
{
|
||||
@ -363,6 +364,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
let recipe_book = default_recipe_book();
|
||||
let craft_result = recipe_book.get(&recipe).and_then(|r| r.perform(inv).ok());
|
||||
|
||||
// FIXME: We should really require the drop and write to be atomic!
|
||||
if craft_result.is_some() {
|
||||
let _ = state.ecs().write_storage().insert(
|
||||
entity,
|
||||
|
@ -33,7 +33,7 @@ use common::{
|
||||
cmd::ChatCommand,
|
||||
comp::{self, ChatType},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{ClientState, ServerInfo, ServerMsg},
|
||||
msg::{server::WorldMapMsg, ClientState, ServerInfo, ServerMsg},
|
||||
outcome::Outcome,
|
||||
recipe::default_recipe_book,
|
||||
state::{State, TimeOfDay},
|
||||
@ -55,15 +55,15 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
use test_world::{World, WORLD_SIZE};
|
||||
use test_world::{IndexOwned, World};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use uvth::{ThreadPool, ThreadPoolBuilder};
|
||||
use vek::*;
|
||||
#[cfg(feature = "worldgen")]
|
||||
use world::{
|
||||
civ::SiteKind,
|
||||
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP, WORLD_SIZE},
|
||||
World,
|
||||
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
||||
IndexOwned, World,
|
||||
};
|
||||
|
||||
#[macro_use] extern crate diesel;
|
||||
@ -82,7 +82,8 @@ pub struct Tick(u64);
|
||||
pub struct Server {
|
||||
state: State,
|
||||
world: Arc<World>,
|
||||
map: Vec<u32>,
|
||||
index: IndexOwned,
|
||||
map: WorldMapMsg,
|
||||
|
||||
network: Network,
|
||||
|
||||
@ -173,7 +174,7 @@ impl Server {
|
||||
state.ecs_mut().insert(AliasValidator::new(banned_words));
|
||||
|
||||
#[cfg(feature = "worldgen")]
|
||||
let world = World::generate(settings.world_seed, WorldOpts {
|
||||
let (world, index) = World::generate(settings.world_seed, WorldOpts {
|
||||
seed_elements: true,
|
||||
world_file: if let Some(ref opts) = settings.map_file {
|
||||
opts.clone()
|
||||
@ -184,21 +185,27 @@ impl Server {
|
||||
..WorldOpts::default()
|
||||
});
|
||||
#[cfg(feature = "worldgen")]
|
||||
let map = world.get_map_data();
|
||||
let map = world.get_map_data(index.as_index_ref());
|
||||
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
let world = World::generate(settings.world_seed);
|
||||
let (world, index) = World::generate(settings.world_seed);
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
let map = vec![0];
|
||||
let map = WorldMapMsg {
|
||||
dimensions: Vec2::new(1, 1),
|
||||
max_height: 1.0,
|
||||
rgba: vec![0],
|
||||
horizons: [(vec![0], vec![0]), (vec![0], vec![0])],
|
||||
};
|
||||
|
||||
#[cfg(feature = "worldgen")]
|
||||
let spawn_point = {
|
||||
let index = index.as_index_ref();
|
||||
// NOTE: all of these `.map(|e| e as [type])` calls should compile into no-ops,
|
||||
// but are needed to be explicit about casting (and to make the compiler stop
|
||||
// complaining)
|
||||
|
||||
// spawn in the chunk, that is in the middle of the world
|
||||
let center_chunk: Vec2<i32> = WORLD_SIZE.map(|e| e as i32) / 2;
|
||||
let center_chunk: Vec2<i32> = world.sim().map_size_lg().chunks().map(i32::from) / 2;
|
||||
|
||||
// Find a town to spawn in that's close to the centre of the world
|
||||
let spawn_chunk = world
|
||||
@ -219,11 +226,11 @@ impl Server {
|
||||
// get a z cache for the collumn in which we want to spawn
|
||||
let mut block_sampler = world.sample_blocks();
|
||||
let z_cache = block_sampler
|
||||
.get_z_cache(spawn_location, world.index())
|
||||
.get_z_cache(spawn_location, index)
|
||||
.expect(&format!("no z_cache found for chunk: {}", spawn_chunk));
|
||||
|
||||
// get the minimum and maximum z values at which there could be soild blocks
|
||||
let (min_z, _, max_z) = z_cache.get_z_limits(&mut block_sampler, world.index());
|
||||
let (min_z, _, max_z) = z_cache.get_z_limits(&mut block_sampler, index);
|
||||
// round range outwards, so no potential air block is missed
|
||||
let min_z = min_z.floor() as i32;
|
||||
let max_z = max_z.ceil() as i32;
|
||||
@ -239,7 +246,7 @@ impl Server {
|
||||
Vec3::new(spawn_location.x, spawn_location.y, *z),
|
||||
Some(&z_cache),
|
||||
false,
|
||||
world.index(),
|
||||
index,
|
||||
)
|
||||
.map(|b| b.is_air())
|
||||
.unwrap_or(false)
|
||||
@ -283,6 +290,7 @@ impl Server {
|
||||
let this = Self {
|
||||
state,
|
||||
world: Arc::new(world),
|
||||
index,
|
||||
map,
|
||||
|
||||
network,
|
||||
@ -489,6 +497,42 @@ impl Server {
|
||||
},
|
||||
});
|
||||
|
||||
{
|
||||
// Check for new chunks; cancel and regenerate all chunks if the asset has been
|
||||
// reloaded. Note that all of these assignments are no-ops, so the
|
||||
// only work we do here on the fast path is perform a relaxed read on an atomic.
|
||||
// boolean.
|
||||
let index = &mut self.index;
|
||||
let thread_pool = &mut self.thread_pool;
|
||||
let world = &mut self.world;
|
||||
let ecs = self.state.ecs_mut();
|
||||
|
||||
index.reload_colors_if_changed(|index| {
|
||||
let mut chunk_generator = ecs.write_resource::<ChunkGenerator>();
|
||||
let client = ecs.read_storage::<Client>();
|
||||
let mut terrain = ecs.write_resource::<common::terrain::TerrainGrid>();
|
||||
|
||||
// Cancel all pending chunks.
|
||||
chunk_generator.cancel_all();
|
||||
|
||||
if client.is_empty() {
|
||||
// No cilents, so just clear all terrain.
|
||||
terrain.clear();
|
||||
} else {
|
||||
// There's at leasat one client, so regenerate all chunks.
|
||||
terrain.iter().for_each(|(pos, _)| {
|
||||
chunk_generator.generate_chunk(
|
||||
None,
|
||||
pos,
|
||||
thread_pool,
|
||||
world.clone(),
|
||||
index.clone(),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let end_of_server_tick = Instant::now();
|
||||
|
||||
// 8) Update Metrics
|
||||
@ -700,7 +744,7 @@ impl Server {
|
||||
server_info: self.get_server_info(),
|
||||
time_of_day: *self.state.ecs().read_resource(),
|
||||
max_group_size: self.settings().max_player_group_size,
|
||||
world_map: (WORLD_SIZE.map(|e| e as u32), self.map.clone()),
|
||||
world_map: self.map.clone(),
|
||||
recipe_book: (&*default_recipe_book()).clone(),
|
||||
});
|
||||
|
||||
@ -723,7 +767,13 @@ impl Server {
|
||||
self.state
|
||||
.ecs()
|
||||
.write_resource::<ChunkGenerator>()
|
||||
.generate_chunk(entity, key, &mut self.thread_pool, self.world.clone());
|
||||
.generate_chunk(
|
||||
Some(entity),
|
||||
key,
|
||||
&mut self.thread_pool,
|
||||
self.world.clone(),
|
||||
self.index.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
fn process_chat_cmd(&mut self, entity: EcsEntity, cmd: String) {
|
||||
|
@ -206,7 +206,6 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::map_identity)] // TODO: Pending review in #587
|
||||
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) {
|
||||
let (body, stats, inventory, loadout) = components;
|
||||
// Make sure physics are accepted.
|
||||
@ -215,7 +214,6 @@ impl StateExt for State {
|
||||
// Notify clients of a player list update
|
||||
let client_uid = self
|
||||
.read_component_cloned::<Uid>(entity)
|
||||
.map(|u| u)
|
||||
.expect("Client doesn't have a Uid!!!");
|
||||
|
||||
self.notify_registered_clients(ServerMsg::PlayerListUpdate(
|
||||
|
@ -60,7 +60,7 @@ impl<'a> System<'a> for Sys {
|
||||
'insert_terrain_chunks: while let Some((key, res)) = chunk_generator.recv_new_chunk() {
|
||||
let (chunk, supplement) = match res {
|
||||
Ok((chunk, supplement)) => (chunk, supplement),
|
||||
Err(entity) => {
|
||||
Err(Some(entity)) => {
|
||||
if let Some(client) = clients.get_mut(entity) {
|
||||
client.notify(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
@ -69,6 +69,9 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
continue 'insert_terrain_chunks;
|
||||
},
|
||||
Err(None) => {
|
||||
continue 'insert_terrain_chunks;
|
||||
},
|
||||
};
|
||||
// Send the chunk to all nearby players.
|
||||
for (view_distance, pos, client) in (&players, &positions, &mut clients)
|
||||
|
@ -1,23 +1,49 @@
|
||||
use common::{
|
||||
generation::{ChunkSupplement, EntityInfo},
|
||||
terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
terrain::{Block, BlockKind, MapSizeLg, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
vol::{ReadVol, RectVolSize, Vox, WriteVol},
|
||||
};
|
||||
use rand::{prelude::*, rngs::SmallRng};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
pub const WORLD_SIZE: Vec2<usize> = Vec2 { x: 1, y: 1 };
|
||||
const DEFAULT_WORLD_CHUNKS_LG: MapSizeLg =
|
||||
if let Ok(map_size_lg) = MapSizeLg::new(Vec2 { x: 1, y: 1 }) {
|
||||
map_size_lg
|
||||
} else {
|
||||
panic!("Default world chunk size does not satisfy required invariants.");
|
||||
};
|
||||
|
||||
pub struct World;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IndexOwned;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct IndexRef<'a>(&'a IndexOwned);
|
||||
|
||||
impl IndexOwned {
|
||||
pub fn reload_colors_if_changed<R>(
|
||||
&mut self,
|
||||
_reload: impl FnOnce(&mut Self) -> R,
|
||||
) -> Option<R> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn as_index_ref(&self) -> IndexRef { IndexRef(self) }
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn generate(_seed: u32) -> Self { Self }
|
||||
pub fn generate(_seed: u32) -> (Self, IndexOwned) { (Self, IndexOwned) }
|
||||
|
||||
pub fn tick(&self, dt: Duration) {}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn map_size_lg(&self) -> MapSizeLg { DEFAULT_WORLD_CHUNKS_LG }
|
||||
|
||||
pub fn generate_chunk(
|
||||
&self,
|
||||
_index: IndexRef,
|
||||
chunk_pos: Vec2<i32>,
|
||||
_should_continue: impl FnMut() -> bool,
|
||||
) -> Result<(TerrainChunk, ChunkSupplement), ()> {
|
||||
|
@ -9,7 +9,7 @@ default-run = "veloren-voxygen"
|
||||
# autobins = false
|
||||
|
||||
[features]
|
||||
gl = ["gfx_device_gl"]
|
||||
gl = ["gfx_device_gl", "gfx_gl"]
|
||||
singleplayer = ["server"]
|
||||
tweak = ["const-tweaker"]
|
||||
hot-anim = ["anim/use-dyn-lib"]
|
||||
@ -25,6 +25,7 @@ anim = { package = "veloren-voxygen-anim", path = "src/anim", default-features =
|
||||
# Graphics
|
||||
gfx = "0.18.2"
|
||||
gfx_device_gl = { version = "0.16.2", optional = true }
|
||||
gfx_gl = { version = "0.6.1", optional = true }
|
||||
old_school_gfx_glutin_ext = "0.24"
|
||||
glutin = "0.24.1"
|
||||
winit = { version = "0.22.2", features = ["serde"] }
|
||||
@ -37,7 +38,7 @@ specs = { git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818
|
||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", branch = "specs-git" }
|
||||
|
||||
# Mathematics
|
||||
vek = { version = "0.11.0", features = ["serde"] }
|
||||
vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] }
|
||||
|
||||
# Controller
|
||||
gilrs = { version = "0.7", features = ["serde"] }
|
||||
@ -49,11 +50,11 @@ server = { package = "veloren-server", path = "../server", optional = true }
|
||||
glsl-include = "0.3.1"
|
||||
failure = "0.1.6"
|
||||
dot_vox = "4.0"
|
||||
image = { version = "0.22.5", default-features = false, features = ["ico", "png"] }
|
||||
image = { version = "0.23.8", default-features = false, features = ["ico", "png"] }
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
ron = { version = "0.6", default-features = false }
|
||||
guillotiere = { git = "https://github.com/Imberflur/guillotiere" }
|
||||
guillotiere = "0.5.2"
|
||||
msgbox = { git = "https://github.com/bekker/msgbox-rs.git", default-features = false, rev = "68fe39a", optional = true }
|
||||
directories-next = "1.0.1"
|
||||
num = "0.2"
|
||||
@ -68,6 +69,7 @@ chrono = "0.4.9"
|
||||
bincode = "1.2"
|
||||
deunicode = "1.0"
|
||||
uvth = "3.1.1"
|
||||
# vec_map = { version = "0.8.2" }
|
||||
const-tweaker = { version = "0.3.1", optional = true }
|
||||
itertools = "0.9.0"
|
||||
|
||||
|
@ -15,7 +15,7 @@ const GEN_SIZE: i32 = 4;
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
// Generate chunks here to test
|
||||
let mut terrain = TerrainGrid::new().unwrap();
|
||||
let world = World::generate(42, sim::WorldOpts {
|
||||
let (world, index) = World::generate(42, sim::WorldOpts {
|
||||
// NOTE: If this gets too expensive, we can turn it off.
|
||||
// TODO: Consider an option to turn off all erosion as well, or even provide altitude
|
||||
// directly with a closure.
|
||||
@ -23,10 +23,11 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
world_file: sim::FileOpts::LoadAsset(sim::DEFAULT_WORLD_MAP.into()),
|
||||
..Default::default()
|
||||
});
|
||||
let index = index.as_index_ref();
|
||||
(0..GEN_SIZE)
|
||||
.flat_map(|x| (0..GEN_SIZE).map(move |y| Vec2::new(x, y)))
|
||||
.map(|offset| offset + CENTER)
|
||||
.map(|pos| (pos, world.generate_chunk(pos, || false).unwrap()))
|
||||
.map(|pos| (pos, world.generate_chunk(index, pos, || false).unwrap()))
|
||||
.for_each(|(key, chunk)| {
|
||||
terrain.insert(key, Arc::new(chunk.0));
|
||||
});
|
||||
@ -132,7 +133,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
c.bench(
|
||||
"meshing",
|
||||
Benchmark::new(&format!("Terrain mesh {}, {}", x, y), move |b| {
|
||||
b.iter(|| volume.generate_mesh(black_box(range)))
|
||||
b.iter(|| volume.generate_mesh(black_box((range, Vec2::new(8192, 8192)))))
|
||||
})
|
||||
// Lower sample size to save time
|
||||
.sample_size(15),
|
||||
|
2
voxygen/clippy.toml
Normal file
2
voxygen/clippy.toml
Normal file
@ -0,0 +1,2 @@
|
||||
# Because 7 is just very low, it corresponds to a 6-argument method.
|
||||
too-many-arguments-threshold = 10
|
@ -22,16 +22,8 @@ fn main() {
|
||||
|
||||
let (_context, device, factory, color_view, depth_view) = init_headless(context, dim);
|
||||
|
||||
let mut renderer = render::Renderer::new(
|
||||
device,
|
||||
factory,
|
||||
color_view,
|
||||
depth_view,
|
||||
render::AaMode::SsaaX4,
|
||||
render::CloudMode::Regular,
|
||||
render::FluidMode::Shiny,
|
||||
)
|
||||
.unwrap();
|
||||
let mut renderer =
|
||||
render::Renderer::new(device, factory, color_view, depth_view, Default::default()).unwrap();
|
||||
|
||||
// Create character
|
||||
let body = comp::humanoid::Body::random();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user