(See sharp/lod-history) LOD, shadows, greedy meshing, new lighting, perf

---

Pretty much a Veloren fork at this point.  Here's a high level overview of the changes (will be added to CHANGELOG just before merge).

At a high level this MR incorporates roughly two groups of changes.

The first group consists of new game features: more flexible map sizes, level of detail terrain, shadow maps, and a new lighting
engine.  This is "feature work" that (mostly)  only adds new things to Veloren, and mostly shouldn't affect old stuff.

The second big group of changes are those addressing the fallout from all the new features.  These include performance fixes of
various sorts: the addition of multiple graphics options and optimization of the cheap ones to avoid work, switching all voxel
models to use some variant of greedy meshing, switching over much of our CPU-side vector math to exploit SIMD instructions
(coinciding with a fork of `vek`), and a rewrite of how the UI handles text rendering (coinciding with updates to our fork
of `conrod`).  Making Veloren's hardcoded colors appear correct under the new lighting engine also required considerably
changes (TODO: Fill in this section when it's complete).

The second category of changes often heavily touches code owned by other people, including frequently modified code "owned" by a
handful of people, so I recommend that this code be reviewed particularly carefully.

---

At a high level (each will be described in more detail below):
- The world map has been refactored.
  - The world size is no longer hardcoded (@zesterer).
  - The map generation code was made generic to allow using it outside of the `world` crate (@zesterer).
  - On world creation, we now compute *horizon maps* (@zesterer).
  - The way we pass the world from the server to the client has been updated (@xMAC94x).
  - Artifacts related to image rotation were fixed (@imbris).
  - Multiflow rivers were enabled (@zesterer).
  - In the process of making changes related to the world map, various incidental fixes and optimizations were required.
- The new *level of detail* feature was added (@zesterer wrote part of this and has checked out the rest).
  - A new LOD terrain rendering step was added to the pipeline.
  - The LOD terrain quality was made configurable via a graphics setting.
  - Horizon maps were used to cast shadows from LOD chunks on both LOD and non-LOD terrain.
  - A "voxelization" effect was incorporated into rendered LOD terrain to make it blend better into the world.
  - In the process of making changes related to LOD, various incidental fixes and optimizations were required.
- Veloren's lighting has been completely overhauled (@zesterer has already checked most of this out).
  - A semi-accurate index of refraction was assigned to our materials.
  - A new, more realistic, physically based approach to lighting was used using the *Ashikhmin Shirley* BRDF.
  - We emulate *atmospheric scattering* using equations designed for measuring solar panel light exposure.
  - We attempt to compute *realistic light attenuation* in water using its real material properties.
  - In the process of making changes related to LOD, various incidental fixes and optimizations were required.
- Point and directional lights now cast realistic shadows, using *shadow mapping.* (@imbris, @zesterer, @Treeco, @YuriMomo)
  - Point light shadow maps were added to the rendering pipeline, using geometry shaders and *seamless cube maps*.
  - Directional light shadows were added to the rendering pipeline, using LISPSM together with disabling *depth clamping*.
  - "Shadow-only" chunks and NPCs were added to prevent shadows from models behind you from disappearing.
  - In the process of making changes related to shadow maps, various incidental fixes and optimizations were required.

The addition of shadow maps, LOD terrain, and the new lighting all led to significant performance degradation, on top of other
changes happening in master.  Therefore, a large number of performance improvements were also needed:

- The graphics options were made much more flexible and configurable, and shaders were optimize.
  - New options were provided for how to render lights and shadows  (@Pfauenauge, @zesterer).
  - Graphic setting storage and configuration were overhauled to make adding new features easier (@Pfauenauge, @imbris).
  - Shaders were rewritten to utilize GLSL's preprocessor to avoid overhead (@zesterer, @YuriMomo).
  - In the process of making changes related to providing additional rendering options, various incidental fixes and optimizations were required.
- Voxel model creation was switched to use *greedy meshing.*
  - A new voxel meshing method, greedy meshing, was added (@imbris).
  - Uses of the older meshing methods were migrated to use greedy meshing (@imbris, @jshipsey, @Pfauenauge).
  - New restrictions were added to terrain, figure, and sprites to future proof them for further optimizations (@jshipsey, @Pfauenauge, @zesterer).
  - Most positions are now relative to either chunk or player position for better precision (@imbris, @zesterer, @scottc).
  - In the process of making changes related to greedy meshing, various incidental fixes and optimizations were required.
- Animation and terrain math were switched to use SIMD where possible.
  - Fixes were made to vek to make its SIMD feature usable for us (@zesterer, @imbris).
  - The interface and types used in bone animation were changed in various ways (@jshipsey, @Snowram, @Pfauenauge).
  - Redundant code generation for body animation is now partly taken care of by a macro (@jshipsey, @Snowram, @Pfauenauge).
  - Animation code was modified to to use vek's SIMD representation where possible (@jshipsey, @Snowram, @Pfauenauge).
  - Terrain meshing code and shadow map math were also modified to use vek's SIMD representation (@imbris).
  - SIMD instruction generation was enabled (@YuriMomo, @jshipsey, @Snowram, @imbris, @Angelonfira, @xMAC94x).
  - In the process of making changes related to greedy meshing, various incidental fixes and optimizations were required.
- The way we cache glyphs was completely refactored, fixed, and optimized.
  - Our fork of `conrod` was optimized in various ways (@imbris).
  - Our fork of `conrod` now exposes whether a widget was updated during the current frame (@imbris).
  - Our use of the glyph cache was rewritten for correctness (@imbris).
  - A *text cache* was introduced that lets us skip remeshing glyphs that have not changed (@imbris).
  - Various changes were made to reduce pressure on the glyph cache, with more planned (@imbris, @Pfauenauge).
  - In the process of making changes related to the glyph cache, various incidental fixes and optimizations were required.
- Colors were changed to keep Veloren's look consistent with master.
  - Some older tree models were brought back (@Pfauenauge).
  - TODO(@Sharp): All hardcoded colors were extracted and made hotloadable.
  - TODO(@Treeco, @Pfauenauge, @imbris, @jshipsey): Hardcoded colors were fixed to conform to Veloren's style.
  - TODO(@Treeco, @Pfauenauge, @imbris, @jshipsey): Color models were fixed to conform to Veloren's style.

A detailed description of the involved changes follows.

---

- The world size is no longer hardcoded.  All functions dependent on world size now take a `WorldSizeLg`, which holds the base 2 logarithm of each actual world dimension and is guaranteed to maintain certain properties (outlined in `common/src/terrain/map.rs`).  Additionally, many utility functions that utilize the world size were moved into `common` as well (mostly `common/src/terrain/mod.rs`).  Finally, the world map format was updated in order to store its size explicitly, with a migration path from the old format that should work whenever the old formatted map was a square (practically always).  See `world/src/sim/mod.rs` for these changes.
- The map generation code was made generic to allow using it outside of the `world` crate.  The parts of the map generating code that do not need to query the world were moved over to `common/src/terrain/map.rs`, allowing them to be used from the client without creating a dependency on `world`.  The rest of it was turned into helper functions in `world/src/sim/map.rs`, which can be passed as closures to the generic map generation code to complete its construction.  This also means that colors are now passed in separately to the map generation function.  See <https://veloren.net/devblog-78/> for more details.
- On world creation, we now compute *horizon maps*.  See the function in `world/src/sim/util.rs`.

  Given a height map and a plane intersecting that height map, our horizon maps allow us to encode enough information to reconstruct shadows for each point on the height map using only the *horizon angle* (the angle at which the sun starts to become visible).  As Veloren's sun only covers one plane, this is sufficient for encoding sun shadows for LOD terrain, by encoding two angles per chunk (one for each 90 degrees the sun covers).  We can also use this for the moon, if we want, since the moon follows the same path.  Additionally, we store the *height* of the furthest occluder, to try to make the shadows volumetric; so this means 4 bytes in total for each chunk.

  Support for horizon maps has been merged into the map functionality in common as well.
- The way we pass the world from the server to the client has been updated.  Rather than passing the prerendered map, we instead pass three maps with values for each chunk; one with the color information, a second with altitude information, and a third with horizon map information.  We then reconstruct the map on the client, together with some additional information we send from the server (like the sea level and maximum height).  See `common/src/msg/server.rs` for a detailed description of the format of `WorldMapMsg`, and `server/src/libr.rs` and `client/src/lib.rs` for details of the map construction and parsing.
- Artifacts related to image rotation were fixed.  See the commit message for commit SHA `cf74d55f2e3d2ae7d25fd68d5c73b01a6afde86e` for a detailed explanation.  This involved changes to shaders, the addition of a new type of graphic (also reflected in the graphic cache) that allows specifying a border color (which automatically makes the associated texture immutable), and some related fixes.  I reproduce the first two paragraphs of the MR description as well:

 ```
 Fix map image artifacts and remove unneeded allocations.

 Specifically, we address three concerns (the image stretching during
 rotation, artifacts around the image due to clamping to the nearest
 border color when the image is drawn to a larger space than the image
 itself takes up, and potential artifacts around a rotated image which
 accidentally ended up in an atlas and didn't have enough extra space to
 guarantee the rotation would work).
 ```
- Multiflow rivers were enabled.
  This does not really need to be part of this MR, and would be easy to revert, but since it seemed to provide a nice improvement it's currently packaged with it.
  We already computed multiple outflows from each chunk for erosion purposes long before this MR.
  However, we never modified river rendering to be able to handle this case (just a single downhill river flow is complex enough!) so this was not exposed when deciding which chunks were rivers.
  Now that
- In the process of making changes related to the world map, various incidental fixes and optimizations were required.  Some examples of fixes include making sure terrain is never lowered to below sea level (to make the shadow maps report correct values), fixing map altitudes and colors to understand things like cliffs and "block level" coloring (that doesn'te xist on the column level), and fixing a crashbug when rendering images for the UI where source pixels are strongly rectangular.  Some examples of related performance fixes include avoiding allocating a fresh vector for all the maps (i.e. copying it over to change the format from `[u32; n]` to `DynamicImage` and then copying again to convert to `RgbaImage`), and instead using the `gfx::memory::slice` function to accomplish the same thing.  These sorts of changes are spread all arond the code.

This includes the additon of a new scene, `voxygen/src/scene/lod.rs`, a new pipeline `voxygen/src/render/pipeline/lod_terrain.rs`, and new shaders `assets/vxygen/shaders/lod-terrain-vert.glsl` and `assets/vxygen/shaders/lod-terrain-frag.glsl`, as well as associated changes to the renderer in `voxygen/src/render/renderer.rs`.

The main idea behind our initial approach to LOD was to take the world data we now get from the server (altitude, color, and horizon mapping).

  - Some previously computed values were turned into shader uniforms for better prediction on weak processors. (@zesterer)
  - Calls to power or trig functions were removed or replaced with multiplications, where possible.
  - After some deliberation
  - To properly handle sprite "waving" for nearby sprites,

We explicitly designed the greedy meshing system with figures and sprites in mind.
In both cases, we want to be able to *efficiently* pack many different models into the same texture, especially in cases where we know
we will either not be removing any of the grouped-together from the models from the texture, or will remove all of them at once (so
they can be packed into some specific subtexture).
For sprites, since we know every model in advance and never intend to deallocate them, we currently pack them all as efficiently as
possible into one giant tetxure atlas.  However, in the future we might opt to pack them slightly less efficiently in exchange for
shrinking the sprite vertex size.
For figures, we pack all the textures for each *model* into the same atlas.
is a global texture atlas used for every sprite, and for figures which is why we have the ability to mesh multiple
models to the same texture area (using the simple texture atlas allocator) without requiring intermediate vector allocations.
This is accomplished by delaying the time when we actually write the color and light data to the texture until *after* all the
model vertices have been meshed; then, we can just allocate the whole color/light array at once, making the atlas we use an
exact fit.  In computer science-y terms, we accomplish this delay by, after we perform the initial greedy meshing (without
texture information), not continuing to create the texture data, but instead constructing a *continuation*--that is, a function
that, when called, will execute the rest of the computation.  We push this continuation (which in Rust terms is a `FnOnce` closure
that takes the `ColLightsInfo` that it is supposed to write to as context) onto a

onto a vector

resizing.  To allow for suspended writes to texture data, Rust pointed out to me that the continuation that would eventually write the color and light data to the texture atlas (the one that is shared by all models sharing the same greedy mesher) would have to *own* whatever data it mshed.  Because we often generate the model data to mesh as a temporary in `voxygen/src/load.rs`, the

  - Matrix multiplications in the shader were reduced for figure data (@zesterer).
  - Vertex "waves" for fluid data were removed.
  - Terrain "bending" near edges was removed.
  - Scaling was fixed to make sure empty space was not introduced in a space previously occupied by a block.  It was also changed to take ownership of its voxel data,
    rather than sharing it, to let it be used with meshing.
  - Rust's nightly version was bumped in order to use the `array_map` function, which lets us reuse more code between the simple map and `FigureModelCache`.

- PositionedGlyph::standalone.

---

I tried to cite sources in many cases[^realtime],[^lloyd],[^lispsm],[^pbrt],[^greedy],[^tjunctions]
where I needed features from elsewhere but I am particularly grateful for the following resources,
esepcially where they have accompanying source code.  I linked all of them that are accessible to the public (those that are not were
obtained through legal means).

[^realtime]: Eisemann, Elmar, Michael Schwarz, Ulf Assarsson, Michael Wimmer. Real-Time Shadows. A K Peters/CRC Press (T&F), 20160419.
[^lloyd]: Lloyd,B. 2007. [Logarithmic perspective shadow maps](http://gamma.cs.unc.edu/papers/documents/dissertations/lloyd07.pdf). PhD thesis, University of North Carolina.
[^lispsm]: Wimmer, M., Scherzer, D., and Purgathofer, W. 2004. [Light space perspective shadow maps](http://gamma.cs.unc.edu/papers/documents/dissertations/lloyd07.pdf). In Proceedings of Eurographics Symposium on Rendering 2004, pp. 143– 152.

[^pbrt]: Pharr, Matt, et al. [http://gamma.cs.unc.edu/papers/documents/dissertations/lloyd07.pdf](Physically Based Rendering: From Theory to Implementation). Third edition, Morgan Kaufmann Publishers/Elsevier, 2017.
[^greedy]: mikolalysenko. “Meshing in a Minecraft Game.” 0 FPS, 30 June 2012, <https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/>.
[^tjunctions]: blackflux. “Meshing in Voxel Engines – Part 1.” Blackflux.Com, 23 Feb. 2014, <https://blackflux.wordpress.com/2014/02/23/meshing-in-voxel-engines-part-1/>.

I am also especially grateful to Khronos, Wikiepdia, and stackoverflow for answering many of my specific questions while writing the MR.

---

Squashed commit of the following:

commit 300505e730
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 18:46:25 2020 +0200

    Fixing cargo doc and typo in CHANGELOG.

commit ec0aeb18e8
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 15:38:50 2020 +0200

    Hopefully final commit for the LOD branch.

commit 5e8ea0b1ea
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 10:14:26 2020 +0200

    Falling back to power as stopgap.

commit e44a1cbf46
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 09:25:41 2020 +0200

    Address imbris feedback.

    Temporarily disables shiny water, lowers max VD.

    These restrictions will be lifted soon after merging.

commit 561e25778a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 08:31:13 2020 +0200

    Tweaking shaders a bit.

commit 7d19259078
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 07:59:43 2020 +0200

    Fix view example as well.

commit 051cd4934e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 07:29:06 2020 +0200

    Fix meshing benchmark.

commit c95e07db3b
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 05:46:22 2020 +0200

    Address MR feedback, fix scene clouds.

commit 1bfb816cab
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 04:39:36 2020 +0200

    Incorporating Pfau's figure color changes.

    New eyes and new humanoid colors.

commit 3f9b89a3ac
Merge: e2f5162e4 62c53963a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 04:29:41 2020 +0200

    Merge remote-tracking branch 'origin/sharp/small-fixes' into sharp/small-fixes

commit e2f5162e4f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 20 04:28:38 2020 +0200

    World colors are all hotloadable.

    They live in assets/world/style/colors.ron.

    Only a small handful of hardcoed colors remain in World; they are either
    part of the map, or difficult to disentangle from the rest of the
    computation.  Comments are made where appropriate.

commit 62c53963ab
Author: Marcel Märtens <marcel.cochem@googlemail.com>
Date:   Wed Aug 19 15:59:00 2020 +0200

    replace pretty_env_logger with tracing

commit 5b1625f99d
Merge: d71003acd 4942b5b39
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 19 05:15:56 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit d71003acda
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 19 05:14:34 2020 +0200

    Hotloading colors, part 1: colors in common.

    Currently, this just entails humanoid colors.  There are only three
    colors not handled; the light emitter colors in
    common/src/comp/inventory/item/tool.rs.  These don't seem important
    enough to me to warrant making hotloadable, at least not right now, but
    if it's needed later we can always add them to the file.

commit 63b5e0e553
Merge: c32b337a4 6d2c4b9c1
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Aug 17 13:05:37 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit c32b337a46
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Aug 17 05:52:04 2020 +0200

    Fixing LOD grid, for real.

commit a166ae0360
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Aug 17 05:28:05 2020 +0200

    Addressing imbris's initial feedback.

    Fixes two minor bugs: explosion particles were no longer spawning
    randomly, and LOD grids were not perfectly even.

commit 4cbad004f4
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Aug 16 19:27:58 2020 +0200

    Bumping nightly per request.

commit 548680276a
Merge: acc098604 8f8b20c91
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Aug 16 19:26:06 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit acc0986040
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Aug 15 22:28:32 2020 +0200

    Lower resolution due to lying drivers.

commit d3b878de2a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Aug 15 22:15:38 2020 +0200

    Fix issues msh encountered with Intel 4600.

commit 10245e0c1b
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Aug 15 21:15:02 2020 +0200

    Merge more models into one mesh than we did previously.

commit 3155c31e66
Merge: 7204cc8a7 3c199280e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 13 22:35:22 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 7204cc8a7a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 13 22:34:43 2020 +0200

    Fix not yet done NPC animations.

    This forces them all to be the idle animation if not specified.

    This fixes issues where you'd have giant NPCs in water.

commit bc83360f2a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 13 19:36:37 2020 +0200

    Try to fix some bugs:

    - Z fighting with LOD terrain and water.
    - Audio SFX not playing.

commit 1fd104aa60
Merge: 862df3c99 7c2c392a3
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 13 12:02:31 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 862df3c997
Merge: 0a4218ed9 75c1d4401
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 13 05:52:56 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 0a4218ed9d
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 12 22:27:14 2020 +0200

    Fix particle depth.

commit f51dfdeb44
Merge: c6251a956 5e6dc0471
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 12 20:19:04 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit c6251a956a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 12 20:15:46 2020 +0200

    Cache figures more intelligently.

    Cache figures for longer, and don't cache character states for the
    player except where they actually affect the rendered model.

commit 0ed801d540
Merge: c11b9bdf0 eea64f78f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 12 16:32:24 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit c11b9bdf0a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Aug 12 11:47:15 2020 +0200

    Remove unneeded Clippy annotation.

commit 16aa9ef40a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Aug 8 00:53:02 2020 +0200

    Fix hotloading and Clippy.

commit 3dc973e0be
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 23:50:27 2020 +0200

    Major speedups with SIMD.

commit fba64a7d93
Merge: 76429d00e d1e10b178
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 13:23:19 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 76429d00ee
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 13:23:10 2020 +0200

    Add clippy.toml.

commit c79f512f84
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 11:55:20 2020 +0200

    Fix all clippy issues, clean up Rust code.

commit 6f90e010b3
Merge: 77a8c7c26 5929cfa5c
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 06:47:30 2020 +0200

    Merge remote-tracking branch 'origin/sharp/small-fixes' into sharp/small-fixes

commit 77a8c7c267
Merge: b44e44232 44febaabd
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Aug 7 06:47:10 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 5929cfa5c7
Author: jshipsey <jshipsey18@gmail.com>
Date:   Thu Aug 6 20:47:27 2020 -0400

    fixed in-hand arrow bug

commit b44e442325
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Aug 6 13:40:35 2020 +0200

    Miscellaneous performance improvements.

commit be37acf287
Merge: 125d7fc6c c11876547
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Aug 3 05:49:27 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit 125d7fc6c4
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Aug 3 04:55:31 2020 +0200

    Abstract over simd vs. repr_c vectors.

    Also some minor improvements to Event size.

commit d4d4956e92
Merge: 5f3b7294a aced5f979
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Aug 2 20:56:54 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit 5f3b7294af
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Aug 2 20:43:52 2020 +0200

    Fix formatting issues I missed before.

commit a428a3ebba
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Aug 2 20:41:51 2020 +0200

    Fix clippy warnings, part 1.

    There aer still a bunch of type too complex and
    function takes too many arguments warnings that I'll fix later
    (or ignore, since in the one case I did fix a function takes too
    many arguments warning I think it made the code *less* readable).

commit ba54307540
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Jul 30 13:22:42 2020 +0200

    Fix light animations so they are removed when the light turns off.

commit 7e0f4bcbf0
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 29 21:10:20 2020 +0200

    Fix crash in edge case for pixel art.

commit 56da06f7a3
Merge: cf74d55f2 9f53a4a19
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 29 18:56:52 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit cf74d55f2e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 29 18:29:52 2020 +0200

    Fix map image artifacts and remove unneeded allocations.

    Specifically, we address three concerns (the image stretching during
    rotation, artifacts around the image due to clamping to the nearest
    border color when the image is drawn to a larger space than the image
    itself takes up, and potential artifacts around a rotated image which
    accidentally ended up in an atlas and didn't have enough extra space to
    guarantee the rotation would work).

    The first concern was addressed by fixing the dimensions of the map
    images drawn from the UI (so that we always use a square source
    rectangle, rather than a rectangular one according to the dimensions of
    the map).  We also fixed the way rotation was done in the fragment
    shader for north-facing sources to make it properly handle aspect ratio
    (this was already done for north-facing targets).  Together, these fix
    rendering issues peculiar to rectangular maps.

    The second and third concerns were jointly addressed by adding an
    optional border color to every 2D image drawn by the UI.  This turns
    out not to waste extra space even though we hold a full f32 color
    (to avoid an extra dependency on gfx's PackedColor), since voxel
    images already take up more space than Optiion<[f32; 4]> requires.
    This is then implemented automatically using the "border color"
    wrapping method in the attached sampler.

    Since this is implemented in graphics hardware, it only works (at
    least naively) if the actual image bounds match the texture bounds.
    Therefore, we altered the way the graphics cache stores images
    with a border color to guarantee that they are always in their own
    texture, whose size exactly matches their extent.  Since the easiest
    currently exposed way to set a border color is to do so for an
    immutable texture, we went a bit further and added a new "immutable"
    texture storage type used for these cases; currently, it is always
    and automatically used only when there is a specified border color,
    but in theory there's no reason we couldn't provide immutable-only
    images that use the default wrapping mdoe (though clamp to border
    is admittedly not a great default).

    To fix the maps case specifically, we set the border color to a
    translucent version of the ocean border color.  This may need
    tweaking going forward, which shouldn't be hard.

    As part of this process, we had to modify graphics replacement to
    make sure immutable images are *removed* when invalidated, rather
    than just having a validity flag unset (this is normally done by
    the UI to try to reuse allocations in place if images are updated
    in benign ways, since the texture atlases used for Ui do not
    support deallocation; currently this is only used for item images,
    so there should be no overlap with immutable image replacement,
    so this was purely precautionary).

    Since we were already touching the relevant code, we also updated
    the image dependency to a newer version that provides more ways
    to avoid allocations, and made a few other changes that should
    hopefully eliminate redundant most of the intermediate buffer
    allocations we were performing for what should be zero-cost
    conversions.  This may slightly improve performance in some
    cases.

commit ad18ce9399
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 28 13:21:09 2020 +0200

    Fix continent scale hack.

commit 36b1cb074f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 28 12:11:40 2020 +0200

    Enable loading different sized maps without a recompile.

    We may want to tweak the effects of the continent_scale_hack.

commit 13b6d4d534
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 28 10:55:48 2020 +0200

    Removing WORLD_SIZE, part 1.

    Erased almost every instance of WORLD_SIZE and replaced it with a local
    power of two, map_size_lg (which respects certain invariants; see
    common/src/terrain/map.rs for more details about MapSizeLg).  This also
    means we can avoid a dependency on the world crate from client, as
    desired.

    Now that the rest of the code is not expecting a fixed WORLD_SIZE, the
    next step is to arrange for maps to store their world size, and to use
    that world size as a basis prior to loading the map (as well, probably,
    as prior to configuring some of the noise functions).

commit 30b1d2c642
Merge: 7d56ba31b 1377b369f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Jul 27 13:16:58 2020 +0200

    Merge remote-tracking branch 'origin/sharp/small-fixes' into sharp/small-fixes

commit 7d56ba31b4
Merge: 2101113b4 598f14b25
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Jul 27 13:16:27 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit 1377b369f6
Author: Monty Marz <m.marzouq@gmx.de>
Date:   Sun Jul 19 23:25:38 2020 +0200

    more saturated pumpkins

commit ae8d50527f
Author: Monty Marz <m.marzouq@gmx.de>
Date:   Sat Jul 18 20:29:56 2020 +0200

    acacia models

commit 2101113b46
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 18 18:55:25 2020 +0200

    Higher detail LOD.

commit add2cfae04
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Jul 16 01:57:39 2020 +0200

    Revert some irrelevant stuff.

commit 2e2ab3dc1e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 15 13:30:49 2020 +0200

    Fixing various things about shadows.

    * Correcting optimal LISPSM parameter.
    * Figure shadows are cast when they're not visible.
    * Chunk shadows stay cast until you look away.
    * Seamless cubemaps for point lights.
    * Etc.

commit 6c31e6b562
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Jul 12 19:50:26 2020 +0200

    Fix shadow creation.

commit 6332cbe006
Merge: be438657c 930e0028b
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Jul 12 18:47:00 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit be438657c3
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Jul 12 18:28:08 2020 +0200

    Tweaks to shadows.

    Added shadow map resolution configuration, added seamless cubemaps,
    documented all existing rendering options, and fixed a few Clippy
    errors.

commit 23b4058906
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 8 10:11:19 2020 +0200

    Fix moon, use nonlinear noise for terrain.

    Note that the latter has a bit of performance cost.

commit 7fbe5cbfbb
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 8 02:23:02 2020 +0200

    Address lies about max texture size.

commit bcfc62b5e1
Merge: 75e3626a7 18a08e8fe
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 8 02:22:08 2020 +0200

    Merge remote-tracking branch 'origin/sharp/small-fixes' into sharp/small-fixes

commit 75e3626a78
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Jul 8 02:21:52 2020 +0200

    OpenGL 3.3 minimum.

commit 18a08e8fe2
Author: Monty Marz <m.marzouq@gmx.de>
Date:   Tue Jul 7 23:57:52 2020 +0200

    settings localization

commit 90c5d1ca36
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 7 21:11:48 2020 +0200

    Lower near distance.

commit 0e66f02b25
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 7 20:09:01 2020 +0200

    All sprites sway in the wind now.

commit db1401a691
Merge: 69e508d8c e8b4b29d7
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 7 19:34:17 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 69e508d8c9
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Jul 7 18:41:37 2020 +0200

    Make it easy to switch to SIMD for math.

commit ffe0f5928c
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 21:21:12 2020 +0200

    Fix some issues with underwater rendering.

commit bfda6da42f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 19:17:59 2020 +0200

    Fix some minor display issues.

commit 0ed752e087
Merge: ccc6a06a8 518edcb85
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 18:14:21 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit ccc6a06a8d
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 18:04:34 2020 +0200

    Some minor changes.

commit 4e02024670
Merge: 50a64d927 e05c9267a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 16:17:40 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit 50a64d927e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Jul 4 13:07:03 2020 +0200

    Fix far plane.

commit 7dd06da34c
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Jul 2 22:25:35 2020 +0200

    Add shadows.glsl.

commit 618a18c998
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Jul 2 22:10:22 2020 +0200

    Adding shadows, greedy meshing, and more.

commit eaea83fe6a
Merge: 267018495 2f89b863e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu May 21 22:47:07 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 2670184954
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu May 21 21:20:01 2020 +0200

    Make civsim and sites deterministic.

    For anything in worldgen where you use a HashMap, *please* think
    carefully about which hasher you are going to use!  This is
    especially true if (for some reason) you are depending on hashmap
    iteration order remaining stable for some aspect of worldgen.

commit f8376fd5dc
Merge: 654f7e049 cdee191dd
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu May 21 17:53:57 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 654f7e0492
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed May 20 21:22:30 2020 +0200

    Correct backface culling.

commit 560501df05
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue May 19 17:22:06 2020 +0200

    Greedy messhing for shadows.

commit a4d87e1875
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun May 17 05:59:00 2020 +0200

    Shadow maps work for lantern.

commit 243d0837b8
Merge: 04382dc28 71dd520cd
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri May 15 14:53:13 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 04382dc286
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri May 15 14:22:17 2020 +0200

    WIP: better graphics config, better LOD, shadow maps.

commit 22ddbad3eb
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat May 2 18:54:09 2020 +0200

    Minor shader fixes.

commit 746a10e8d0
Merge: 0f4a0e763 40ab94673
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat May 2 04:02:09 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 0f4a0e763d
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri May 1 23:03:24 2020 +0200

    Switch back to pop-in terrain.

commit dd74fa7e4a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri May 1 22:58:55 2020 +0200

    LOD shading closer to voxel shading.

commit ef67bd58ba
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Apr 28 20:49:03 2020 +0200

    Experimental underwater lighting.

commit 2c5ad9d076
Merge: 748279835 303967a6f
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 22:35:24 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 7482798354
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 21:59:55 2020 +0200

    Replace discard in figure-frag.

commit d83b4ae69b
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 18:45:57 2020 +0200

    Fix sprite lighting, HDR from focus_pos.

commit 0594238004
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 18:14:10 2020 +0200

    Proper HDR from point lights.

commit 48c93d2b41
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 14:01:43 2020 +0200

    Brighter ambiance, darker LOD shadows.

commit e0452e895c
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 13:13:23 2020 +0200

    More proper HDR.

commit 4c6da3ed16
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 27 00:13:10 2020 +0200

    Trying LOD noise.

commit 682a3d74c8
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Apr 26 23:11:08 2020 +0200

    Fix LOD heights in towns.

commit cc39e5734e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sun Apr 26 21:01:23 2020 +0200

    More LOD fixes.

commit 8116b21c2e
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 23:54:43 2020 +0200

    I like this coloring.

commit bc2560ea90
Merge: 14effdd5d e690efe71
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 23:48:33 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit 14effdd5db
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 22:24:35 2020 +0200

    Re-saturate.

commit 48a643955d
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 22:23:57 2020 +0200

    Various fixes.

commit f7b497a0c2
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 03:22:49 2020 +0200

    Render figures again.

commit 44e4aad48d
Merge: e6f0a5a98 9ec319a18
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 25 02:01:04 2020 +0200

    Merge remote-tracking branch 'origin/master' into sharp/small-fixes

commit e6f0a5a981
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Apr 24 16:12:20 2020 +0200

    Add atmospheric scattering.

commit f2953087f6
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 23 00:01:20 2020 +0200

    Fix shadowing for specular reflections.

commit ddd4a67a97
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Wed Apr 22 22:56:12 2020 +0200

    HDR fixes.

commit 1015e60dee
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Tue Apr 21 18:25:19 2020 +0200

    More lighting changes.

commit 80c264abd1
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Mon Apr 13 00:29:59 2020 +0200

    Lighting experiments.

commit 8414987e58
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 9 02:38:40 2020 +0200

    WIP -- lighting changes and soft shadows.

commit 9cd2b3fb0d
Merge: c7ea687eb 8b149ad11
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 4 02:33:29 2020 +0200

    Merge branch 'sharp/new-lighting' into sharp/small-fixes

commit c7ea687ebb
Merge: 476441531 22f3319b4
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 4 02:33:02 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/small-fixes

commit 8b149ad11a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Sat Apr 4 02:32:39 2020 +0200

    Trying out a new lighting model.

commit b0ac9f36f7
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Apr 3 07:56:11 2020 +0200

    Use bicubic interpolation for terrain.

commit f6fc9307a1
Merge: 33140a295 22f3319b4
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Apr 3 05:01:41 2020 +0200

    Merge remote-tracking branch 'origin/master' into zesterer/lod

commit 4764415312
Merge: ed2d0111d 13388ee6a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Apr 3 04:54:48 2020 +0200

    Merge branch 'sharp/map-colors' into sharp/small-fixes

commit 13388ee6a4
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 20:30:08 2020 +0200

    Various fixes (to coloring and to soft shadows).

commit fbd084a94a
Merge: 5a089863b 4fdf6896a
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 18:50:38 2020 +0200

    Merge branch 'master' of gitlab.com:veloren/veloren into sharp/map-colors

commit ed2d0111d9
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 06:49:27 2020 +0200

    Combining colors and LOD.

commit 88342640c6
Merge: 33140a295 5a089863b
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 04:49:20 2020 +0200

    Merge branch 'sharp/map-colors' into sharp/small-fixes

commit 33140a2951
Merge: 4c65a5aed f34d4b379
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 04:36:21 2020 +0200

    Merge remote-tracking branch 'origin/master' into zesterer/lod

commit 5a089863be
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 03:17:49 2020 +0200

    Making maps brighter.

    This is probably not the right way to do it, but oh well!

commit 32b2c99109
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Thu Apr 2 02:46:36 2020 +0200

    Horizon mapping and "layered" map generation.

    Horizon mapping is a method of shadow mapping specific to height maps.
    It can handle any angle between 0 and 90 degrees from the ground, as
    long as know the horizontal direction in advance, by remembering only a
    single angle (the "horizon angle" of the shadow map).  More is explained
    in common/src/msg/server.rs.  We also remember the approximate height of
    the largest occluder, to try to be able to generate soft shadows and
    create a vertical position where the shadows can't go higher.

    Additionally, map generation has been reworked.  Instead of computing
    everything from explicit samples, we pass in sampling functions that
    return exactly what the map generator needs.  This allows us to cleanly
    separate the way we sample things like altitudes and colors from the map
    generation process.  We exploit this to generate maps *partially* on the
    server (with colors and rivers, but not shading).  We can then send the
    partially completed map to the client, which can combine it with shadow
    information to generate the final map.  This is useful for two reasons:
    first, it makes sure the client can apply shadow information by itself,
    and second, it lets us pass the unshaded map for use with level of
    detail functionality.

    For similar reasons, river generation is split
    out into its own layer, but for now we opt to still generate rivers on
    the server (since the river wire format is more complicated to compress
    and may require some extra work to make sure we have enough precision to
    draw rivers well enough for LoD).

    Finally, the mostly ad-hoc lighting we were performing has been (mostly)
    replaced with explicit Phong reflection shading (including specular
    highlights).  Regularizing this seems useful and helps clarify the
    "meaning" of the various light intensities, and helps us keep a more
    physically plausible basis.  However, its interaction with soft shadows
    is still imperfect, and it's not yet clear to me what we need to do to
    turn this into something useful for LoD.

commit f8926a5737
Merge: a1aee931e 875ae6ced
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Mar 13 13:32:42 2020 +0100

    Merge remote-tracking branch 'origin/master' into sharp/map-colors

commit 4c65a5aed3
Author: Treeco <5021038-Treeco@users.noreply.gitlab.com>
Date:   Mon Feb 24 16:48:05 2020 +0000

    Made LOD setting slider exponential

commit 2fa7b2d20d
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Feb 24 17:49:53 2020 +0000

    Added mist to LoD

commit aab059a450
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Feb 24 15:14:06 2020 +0000

    Added LoD slider

commit 779c36b538
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Feb 24 12:54:55 2020 +0000

    Reduced cost of vertex pushing

commit 9fea150473
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Feb 24 12:38:53 2020 +0000

    Fixed maths, improved LoD resolution

commit 5481df38fe
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Feb 24 11:22:50 2020 +0000

    Dynamically relocate LoD vertices to enhance details

commit a3e36a50ab
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Sun Feb 23 18:13:51 2020 +0000

    Simpler terrain spiral rendering

commit 255f450ae9
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Sun Feb 23 16:53:17 2020 +0000

    Better LoD precision

commit 3d027aebe8
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Sun Feb 23 16:04:03 2020 +0000

    Better falloff

commit be775c9484
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Sun Feb 23 15:30:45 2020 +0000

    Applied good ideas from experimental branch

commit 58587b6854
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 16:15:13 2020 +0000

    Minor fixes to LoD merging

commit 7b42aebd70
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 15:04:44 2020 +0000

    Capped LoD dragging

commit 8aafc559f8
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 14:54:37 2020 +0000

    Better blending between LoD and terrain border

commit edd3455d51
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 14:40:19 2020 +0000

    Fixed LoD z depth, added sea level offset

commit b9b0674462
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 14:27:43 2020 +0000

    Better LoD smoothing

commit a1aee931e7
Author: Joshua Yanovski <pythonesque@gmail.com>
Date:   Fri Feb 21 14:52:17 2020 +0100

    Adding shadows.

commit 2400786c13
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Feb 21 13:48:40 2020 +0000

    Use world map as LoD source

commit dbf650f504
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Mon Jan 20 00:48:14 2020 +0000

    Better clouds at distance

commit 5e6f81b86c
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Sun Jan 19 23:59:02 2020 +0000

    sync

commit 745e7540dd
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Nov 22 12:40:48 2019 +0000

    Improved cloud falloff mist, faster noise sampling

commit f6a200d0cb
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Fri Nov 22 10:09:00 2019 +0000

    Improved long-range depth precision, removed unnecessary LoD polygons

commit 63d1b2bb22
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Thu Nov 21 20:57:46 2019 +0000

    Working LoD shader

commit f13d98ee3e
Author: Joshua Barretto <joshua.s.barretto@gmail.com>
Date:   Thu Nov 21 11:03:40 2019 +0000

    LoD first attempt (stack overflow issue)
This commit is contained in:
Joshua Yanovski 2020-08-20 20:34:59 +02:00
parent 4942b5b394
commit 2dfd3b13d1
261 changed files with 23131 additions and 11885 deletions

View File

@ -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
View File

@ -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",
]

View File

@ -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" }

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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);
// 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;
// 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;
// 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 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);
diffuse_light *= point_shadow;
ambient_light *= point_shadow;
vec3 point_light = light_at(f_pos, f_norm);
light += point_light;
diffuse_light += point_light;
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 ao = pow(f_ao, 0.5) * 0.85 + 0.15;
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);
ambient_light *= ao;
diffuse_light *= ao;
vec3 k_a = vec3(1.0);
vec3 k_d = vec3(1.0);
vec3 k_s = vec3(R_s);
vec3 surf_color = illuminate(srgb_to_linear(model_col.rgb * f_col), light, diffuse_light, ambient_light);
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);
}

View File

@ -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;
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);
}

View File

@ -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;
ivec4 atlas_offs;
};
uniform sampler2D t_waves;
@ -20,10 +50,13 @@ out vec4 tgt_color;
#include <sky.glsl>
#include <light.glsl>
#include <lod.glsl>
void main() {
// 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(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) );
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;
@ -32,25 +65,134 @@ 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;
// 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));
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 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
#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*/);
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(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds);
float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag);
vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + diffuse_light)), passthrough);
tgt_color = mix(color, vec4(fog_color, 0.0), 0.0);
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;
}

View File

@ -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;
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);
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);
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);
// Water is transparent so both normals are valid.
vec3 cam_norm = faceforward(norm, norm, cam_to_frag);
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;
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);
// 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;
}

View File

@ -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;
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;
// 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(
/* 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;
gl_Position =
all_mat *
vec4(f_pos, 1);
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
// 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);
}

View File

@ -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);
}

View File

@ -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

View 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
*/

View File

@ -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;

View File

@ -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);
}

View 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

View File

@ -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;

View 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

View File

@ -1,53 +1,79 @@
#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));
//}
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));
}
const float PERSISTENT_AMBIANCE = 0.1;
float get_sun_brightness(vec3 sun_dir) {
float get_sun_brightness(/*vec3 sun_dir*/) {
return max(-sun_dir.z + 0.6, 0.0) * 0.9;
}
float get_moon_brightness(vec3 moon_dir) {
return max(-moon_dir.z + 0.6, 0.0) * 0.07;
float get_moon_brightness(/*vec3 moon_dir*/) {
return max(-moon_dir.z + 0.6, 0.0) * 0.4;
}
vec3 get_sun_color(vec3 sun_dir) {
vec3 get_sun_color(/*vec3 sun_dir*/) {
return mix(
mix(
DUSK_LIGHT,
@ -59,31 +85,254 @@ vec3 get_sun_color(vec3 sun_dir) {
);
}
vec3 get_moon_color(vec3 moon_dir) {
vec3 get_moon_color(/*vec3 moon_dir*/) {
return vec3(0.05, 0.05, 0.6);
}
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;
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 sun_dir = get_sun_dir(time_of_day);
vec3 moon_dir = get_moon_dir(time_of_day);
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)*/);
}
float sun_light = get_sun_brightness(sun_dir);
float moon_light = get_moon_brightness(moon_dir);
// // 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_color = get_sun_color(sun_dir);
vec3 moon_color = get_moon_color(moon_dir);
// 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;
vec3 sun_chroma = sun_color * sun_light;
vec3 moon_chroma = moon_color * moon_light;
/* vec3 sun_dir = sun_info.dir;
vec3 moon_dir = moon_info.dir; */
vec3 sun_dir = sun_dir.xyz;
vec3 moon_dir = moon_dir.xyz;
light = sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
float sun_light = get_sun_brightness(/*sun_dir*/);//sun_info.brightness;;
float moon_light = get_moon_brightness(/*moon_dir*/);//moon_info.brightness;
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;
// 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);
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.
@ -107,10 +356,22 @@ float is_star_at(vec3 dir) {
return 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) {
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 = 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;
@ -129,7 +390,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
);
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_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
@ -153,8 +414,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
);
vec3 sky_mid = mix(
mix(
SKY_DUSK_MID,
mix( SKY_DUSK_MID,
SKY_NIGHT_MID,
max(pow(sun_dir.z, 0.2), 0)
),
@ -186,17 +446,30 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
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);
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) {
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) {
return max(1.0 - 5000.0 / (1.0 + distance(f_pos.xy, focus_pos.xy)), 0.0);
float fog_radius = view_distance.x;
float mist_radius = 10000000.0;
@ -213,3 +486,104 @@ float fog(vec3 f_pos, vec3 focus_pos, uint medium) {
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)));
}

View File

@ -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

View 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
}
}

View 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
}

View 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
}

View 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
//}
}

View 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
}

View 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);
}

View 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);
}

View 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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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() {
// 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;
// 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;
vec3 sprite_pos = (inst_mat * vec4(0, 0, 0, 1)).xyz;
// vec3 sprite_pos = floor(inst_mat3.xyz * SCALE) + inst_offs;
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);
// f_pos_norm = v_pos;
// 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 v_pos = vec3(gl_VertexID * 32, gl_VertexID % 32, 1.0);
// f_pos = v_pos + (model_offs - focus_off.xyz);
// 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);
// 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);
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
f_pos += inst_wind_sway * vec3(
/* 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) * SCALE, 1.3) * 0.2;
// 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 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;
// Select glowing
if (select_pos.w > 0 && select_pos.xyz == floor(sprite_pos)) {
f_col *= 8.0;
) * pow(abs(v_pos_.z/* + sprites[0].offs.z*/)/* * SCALE*/, 1.3) * /*0.2;*/SCALE_FACTOR;
}
f_light = 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));
// 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 = -1000.0 / (gl_Position.z + 10000.0);
// 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);
}

View File

@ -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);
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 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 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);
// 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);
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;
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 col = f_col + hash(vec4(floor(f_chunk_pos * 3.0 - f_norm * 0.5), 0)) * 0.02; // Small-scale noise
float max_light = 0.0;
// 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;
}
}
// 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;
vec3 surf_color = illuminate(srgb_to_linear(col), light, diffuse_light, ambient_light);
// 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);
}

View File

@ -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);
}

View File

@ -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);
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;
}

Binary file not shown.

Binary file not shown.

View 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)

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

View 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)

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

View File

@ -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" }

View File

@ -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,15 +153,24 @@ 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 {
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 {
@ -146,14 +178,14 @@ impl Client {
server_info,
time_of_day,
max_group_size,
world_map: (map_size, world_map),
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 is running {}[{}], you are running {}[{}], versions might \
be incompatible!",
server_info.git_hash,
server_info.git_date,
common::util::GIT_HASH.to_string(),
@ -173,29 +205,154 @@ impl Client {
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);
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 world_map = Arc::new(
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),
);
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(),
);
))
};
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),
lod_base,
lod_alt,
lod_horizon,
(world_map, map_size, map_bounds),
recipe_book,
max_group_size,
));
@ -206,8 +363,7 @@ impl Client {
},
}
}
},
)?;
})?;
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,

View File

@ -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"

View File

@ -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
}
}
}

View File

@ -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>,

View File

@ -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 {
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,15 +242,21 @@ 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()
@ -484,17 +347,23 @@ impl Species {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u32)]
pub enum BodyType {
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 {
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,
@ -509,60 +378,14 @@ pub enum EyeColor {
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),
}
}
);
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),
}
}
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 {
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,
@ -597,125 +420,5 @@ pub enum Skin {
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)
}
}
);

View File

@ -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) }

View File

@ -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;

View File

@ -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

View File

@ -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
View 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,
}
}
}

View File

@ -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
}

View File

@ -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
View 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
}
}
}
}

View File

@ -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)

View File

@ -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,
{

View File

@ -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)
}
}

View File

@ -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),
}
}

View File

@ -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"

View File

@ -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);
});
}
}

View File

@ -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;

View File

@ -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,
})

View File

@ -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();

View File

@ -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,

View File

@ -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) {

View File

@ -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(

View File

@ -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)

View File

@ -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), ()> {

View File

@ -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"

View File

@ -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
View File

@ -0,0 +1,2 @@
# Because 7 is just very low, it corresponds to a 6-argument method.
too-many-arguments-threshold = 10

View File

@ -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();

View File

@ -17,7 +17,7 @@ be-dyn-lib = []
default = ["be-dyn-lib"]
[dependencies]
vek = { version = "0.11.2", features = ["serde"] }
vek = { version = "0.12.0", features = ["platform_intrinsics", "serde"] }
common = { package = "veloren-common", path = "../../../common" }
libloading = { version = "0.6.2", optional = true }
notify = { version = "5.0.0-pre.2", optional = true }

Some files were not shown because too many files have changed in this diff Show More