11 Commits

Author SHA1 Message Date
c00f05aafd feat(renderer): smooth shadow sun direction transitions using quantized directions and slerp 2026-06-17 22:09:50 +08:00
dc1ef70231 fix(texture): set texture wrap mode to clamp to edge 2026-06-17 21:13:23 +08:00
e224110452 feat(renderer): add runtime shader and shadow mode controls
Introduce user-controllable shader on/off, shadow mode (rotated Poisson disk, 3x3 grid, or off), light cull face, and discard transparent in depth pass. Expose all settings in new dev panel "shader" tab. Move ambient strength slider to the new tab.
2026-06-17 20:16:20 +08:00
74b0aebc9f chore(world): add missing <numbers> include 2026-06-17 19:16:02 +08:00
be425a705c feat(dev-panel): add tick freeze toggle and fix TickType sign
Add checkbox to freeze tick advancement in dev panel.
Change TickType from unsigned long long to signed long long to prevent underflow.
2026-06-17 19:15:16 +08:00
31bf337f6f perf(shadow): increase depth map resolution and refine PCF sampling 2026-06-17 15:23:38 +08:00
662f10047a feat(renderer): add shadow mapping with PCF soft shadows
Introduce shadow mapping using a dedicated depth framebuffer and shader. The block fragment shader now performs percentage-closer filtering (PCF) with Poisson disk sampling and random rotation for soft shadows. The vertex shader outputs light-space coordinates. A new depth shader pair handles rendering from the light's perspective, discarding transparent fragments. The renderer sets up the light projection based on the camera position and sun direction, and applies the shadow factor to diffuse lighting. Day/night cycle can now be toggled off in the world server thread.
2026-06-16 22:27:08 +08:00
943c6f1f46 fix(game_time): use unsigned tick type and enforce positive tick speed 2026-06-16 18:51:47 +08:00
7ede49da72 feat(renderer): make ambient strength adjustable via dev panel 2026-06-16 18:44:59 +08:00
a4f92e3659 feat(world): add day/night cycle with server tick system 2026-06-16 16:17:47 +08:00
f43ef64691 feat(rendering): add basic diffuse and ambient lighting to block rendering 2026-06-16 13:53:47 +08:00
876 changed files with 3215 additions and 219317 deletions

View File

@@ -1,3 +1,4 @@
# .github/workflows/format-check.yml
name: Code Format Check
on: [push, pull_request]
@@ -8,22 +9,9 @@ permissions:
jobs:
formatting:
runs-on: ubuntu-latest
container: silkeh/clang:latest
steps:
- uses: actions/checkout@v4
- name: Install LLVM 22
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 22
sudo apt-get install -y clang-format-22
clang-format-22 --version
- name: Run clang-format
run: |
find src include \
\( -name '*.cpp' -o -name '*.hpp' \) \
-print0 | xargs -0 clang-format-22 --dry-run --Werror
find src include -name '*.cpp' -o -name '*.h' -print0 | xargs -0 clang-format --dry-run --Werror

View File

@@ -1,154 +0,0 @@
name: Release-Build
on:
workflow_dispatch:
inputs:
version:
description: Version
required: false
default: dev
push:
tags:
- "v*"
permissions:
contents: write
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2022
platform: windows
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Get Version
id: version
shell: bash
run: |
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
else
VERSION="${{ github.event.inputs.version }}"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Setup MSVC
if: matrix.platform == 'windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Bootstrap vcpkg
run: |
git clone https://github.com/microsoft/vcpkg.git
./vcpkg/bootstrap-vcpkg.bat
- name: Configure
if: matrix.platform == 'windows'
run: >
cmake
-B build
-G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake
-DVCPKG_TARGET_TRIPLET=x64-windows-release
-DVCPKG_BUILD_TYPE=release
-DBUILD_TESTING=OFF
"-DCUBED_VERSION=${{ steps.version.outputs.version }}"
- name: Build
run: cmake --build build --config Release --target Cubed
- name: Copy assets
if: matrix.platform == 'windows'
shell: pwsh
run: |
if (Test-Path assets) {
Copy-Item -Path assets -Destination build/Cubed -Recurse
} else {
Write-Warning "assets folder not found, skipping copy"
}
- name: Create Zip
if: matrix.platform == 'windows'
shell: pwsh
run: |
Compress-Archive `
-Path build/Cubed/* `
-DestinationPath Cubed-${{ steps.version.outputs.version }}-windows-x64.zip
####################################################################
# Upload
####################################################################
- name: Upload Windows Artifacts
if: matrix.platform == 'windows'
uses: actions/upload-artifact@v4
with:
name: windows
path: |
*.zip
##########################################################################
# Release
##########################################################################
release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Generate SHA256
run: |
cd artifacts
find . -type f | while read file
do
sha256sum "$file"
done > SHA256SUMS
- name: Determine prerelease
id: prerelease
run: |
MAIN_BRANCH="${{ github.event.repository.default_branch }}"
git fetch origin "$MAIN_BRANCH" --depth=1 2>/dev/null || true
if git merge-base --is-ancestor "${{ github.sha }}" "origin/$MAIN_BRANCH"; then
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "is_prerelease=false"
else
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "is_prerelease=true"
fi
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
artifacts/**/*
artifacts/SHA256SUMS
generate_release_notes: true
draft: false
prerelease: ${{ steps.prerelease.outputs.is_prerelease }}

4
.gitignore vendored
View File

@@ -41,6 +41,4 @@ CMakeError.log
*~
.DS_Store
assets/config.toml
.venv/
pyout/
vcpkg_installed/
.venv/

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.21)
cmake_minimum_required(VERSION 3.14...3.24)
project(Cubed LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 23)
@@ -6,120 +6,167 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(NOT CMAKE_CONFIGURATION_TYPES
AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
endif()
if(NOT DEFINED CUBED_VERSION)
set(CUBED_VERSION "dev")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
if(MSVC)
add_compile_options(/utf-8)
endif()
find_package(OpenGL REQUIRED)
if (UNIX AND NOT APPLE)
find_package(Freetype REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(EGL REQUIRED egl)
pkg_check_modules(Wayland REQUIRED wayland-client wayland-egl)
find_package(glfw3 REQUIRED)
endif()
add_library(glad STATIC third_party/glad/src/glad.c)
target_include_directories(glad PUBLIC third_party/glad/include)
include(FetchContent)
if (WIN32)
FetchContent_Declare(
glfw
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.4
)
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
set(GLFW_VULKAN_STATIC ON CACHE BOOL "" FORCE)
set(GLFW_STATIC ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(glfw)
FetchContent_Declare(
freetype
GIT_REPOSITORY https://gitlab.freedesktop.org/freetype/freetype.git
GIT_TAG VER-2-14-3
)
FetchContent_MakeAvailable(freetype)
if(TARGET freetype)
add_library(Freetype::Freetype ALIAS freetype)
endif()
set(_BUILD_SHARED_LIBS_SAVED ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS ON)
FetchContent_Declare(
onetbb
GIT_REPOSITORY https://github.com/uxlfoundation/oneTBB.git
GIT_TAG v2023.0.0
)
set(BUILD_TESTING OFF CACHE BOOL "Build tests" FORCE)
set(TBB_TEST OFF CACHE BOOL "Build TBB tests" FORCE)
FetchContent_MakeAvailable(onetbb)
set(BUILD_SHARED_LIBS ${_BUILD_SHARED_LIBS_SAVED})
unset(_BUILD_SHARED_LIBS_SAVED)
endif()
FetchContent_Declare(
glm
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG 1.0.3
)
include(Dependencies)
add_subdirectory(third_party/glad)
FetchContent_MakeAvailable(glm)
FetchContent_Declare(
soil2
GIT_REPOSITORY https://github.com/SpartanJ/SOIL2.git
GIT_TAG 1.31
)
FetchContent_MakeAvailable(soil2)
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)
add_subdirectory(third_party/imgui)
add_subdirectory(third_party/dr_libs)
set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
add_executable(${PROJECT_NAME})
add_subdirectory(src)
file(GLOB_RECURSE PROTO_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/proto/*.proto
add_executable(${PROJECT_NAME}
src/main.cpp
src/app.cpp
src/debug_collector.cpp
src/camera.cpp
src/config.cpp
src/dev_panel.cpp
src/gameplay/biome.cpp
src/gameplay/chunk.cpp
src/gameplay/chunk_generator.cpp
src/gameplay/player.cpp
src/gameplay/tree.cpp
src/gameplay/world.cpp
src/input.cpp
src/map_table.cpp
src/renderer.cpp
src/shader.cpp
src/texture_manager.cpp
src/tools/cubed_random.cpp
src/tools/math_tools.cpp
src/tools/shader_tools.cpp
src/tools/font.cpp
src/tools/perlin_noise.cpp
src/ui/text.cpp
src/window.cpp
src/gameplay/builders/biome_builder.cpp
src/gameplay/builders/plain_builder.cpp
src/gameplay/builders/mountain_builder.cpp
src/gameplay/builders/river_builder.cpp
src/gameplay/builders/desert_builder.cpp
src/gameplay/builders/forest_builder.cpp
src/gameplay/cave_carver.cpp
src/gameplay/cave_path.cpp
src/gameplay/builders/snowy_plain_builder.cpp
src/gameplay/river_worm.cpp
src/gameplay/river_path.cpp
src/block.cpp
src/gameplay/vertex_data.cpp
src/gameplay/builders/ocean_builder.cpp
)
protobuf_generate(
TARGET ${PROJECT_NAME}
LANGUAGE cpp
PROTOS ${PROTO_FILES}
IMPORT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/proto
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}")
configure_file(
src/version.hpp.in
${CMAKE_BINARY_DIR}/generated/version.hpp
@ONLY
)
target_compile_options(${PROJECT_NAME} PRIVATE
#-fsanitize=address
#-fsanitize=thread
-fno-omit-frame-pointer
-g
)
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<CONFIG:Debug>:-fno-omit-frame-pointer>
$<$<CONFIG:Debug>:-g>
#$<$<CONFIG:Debug>:-fsanitize=address>
#$<$<CONFIG:Debug>:-fsanitize=thread>
target_link_options(${PROJECT_NAME} PRIVATE
#-fsanitize=address
#-fsanitize=thread
)
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall>
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wextra>
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wpedantic>
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
$<$<CXX_COMPILER_ID:MSVC>:/W4>
)
target_link_options(${PROJECT_NAME}
PRIVATE
#$<$<CONFIG:Debug>:-fsanitize=address>
#$<$<CONFIG:Debug>:-fsanitize=thread>
)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
ASIO_STANDALONE
ASIO_NO_DEPRECATED
$<$<CONFIG:Debug>:DEBUG_MODE>
$<$<CXX_COMPILER_ID:MSVC>:
WIN32_LEAN_AND_MEAN
NOMINMAX
_CRT_SECURE_NO_WARNINGS
>
)
if(CMAKE_CONFIGURATION_TYPES)
# Visual Studio / Xcode multi-configuration generator
target_compile_definitions(${PROJECT_NAME}
PRIVATE
ASSETS_PATH="$<$<CONFIG:Debug>:${PROJECT_SOURCE_DIR}/assets/>$<$<NOT:$<CONFIG:Debug>>:./assets/>"
target_compile_definitions(${PROJECT_NAME} PRIVATE DEBUG_MODE)
target_compile_definitions(${PROJECT_NAME} PRIVATE
ASSETS_PATH="${CMAKE_SOURCE_DIR}/assets/"
)
else()
# Ninja / Makefiles single-configuration generator
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${PROJECT_NAME}
PRIVATE
ASSETS_PATH="${PROJECT_SOURCE_DIR}/assets/"
)
else()
target_compile_definitions(${PROJECT_NAME}
PRIVATE
ASSETS_PATH="./assets/"
)
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE
ASSETS_PATH="./assets/"
)
endif()
target_include_directories(${PROJECT_NAME}
PRIVATE
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/third_party/asio/include
${CMAKE_BINARY_DIR}/generated
${PROJECT_BINARY_DIR}
${PROJECT_BINARY_DIR}/src
)
target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME}
PRIVATE
@@ -131,27 +178,43 @@ target_link_libraries(${PROJECT_NAME}
Freetype::Freetype
tomlplusplus::tomlplusplus
imgui
dr_libs
tbb
protobuf::libprotobuf
absl::log
absl::check
absl::base
absl::strings
absl::flat_hash_map
zstd::zstd
OpenAL::OpenAL
$<$<PLATFORM_ID:Windows>:ws2_32>
)
if(WIN32)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:${PROJECT_NAME}>
$<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMAND_EXPAND_LISTS
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# target_link_libraries(${PROJECT_NAME} PRIVATE tbb)
endif()
if (UNIX AND NOT APPLE)
target_link_libraries(${PROJECT_NAME}
PRIVATE
${EGL_LIBRARIES}
${Wayland_LIBRARIES}
)
target_include_directories(${PROJECT_NAME}
PRIVATE
${EGL_INCLUDE_DIRS}
${Wayland_INCLUDE_DIRS}
)
target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER})
endif()
if (WIN32)
foreach(TBB_LIB IN ITEMS tbb tbbmalloc tbbmalloc_proxy)
if(TARGET ${TBB_LIB})
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${TBB_LIB}>
$<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMENT "Copying ${TBB_LIB}.dll"
)
else()
message(STATUS "Target ${TBB_LIB} not found, skipping copy")
endif()
endforeach()
endif()

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'air'
roughness = 1.0
name = 'air'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'dirt'
roughness = 1.0
name = 'dirt'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'grass'
roughness = 0.9
name = 'grass'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'grass_block'
roughness = 0.9
name = 'grass_block'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = false
is_transparent = true
name = 'leaf'
roughness = 0.7
name = 'leaf'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = false
is_transparent = false
name = 'log'
roughness = 0.7
name = 'log'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'sand'
roughness = 0.8
name = 'sand'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'snowy_grass_block'
roughness = 0.9
name = 'snowy_grass_block'

View File

@@ -7,5 +7,4 @@ is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'stone'
roughness = 0.75
name = 'stone'

View File

@@ -8,4 +8,3 @@ is_transparent = false
is_discard = false
is_blend = false
is_transitional = false
roughness = 1.0

View File

@@ -7,5 +7,4 @@ is_liquid = true
is_passable = true
is_transitional = false
is_transparent = true
name = 'water'
roughness = 0.02
name = 'water'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,11 +0,0 @@
#version 460
out vec4 frag_color;
uniform vec3 color;
void main(void) {
frag_color = vec4(color, 1.0);
}

View File

@@ -1,10 +0,0 @@
#version 460
layout (location = 0) in vec3 vertices_pos;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void) {
gl_Position = proj_matrix * mv_matrix * vec4(vertices_pos, 1.0);
}

View File

@@ -4,21 +4,10 @@ layout (location = 0) out vec4 accum;
layout (location = 1) out float reveal;
in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in float roughness;
flat in int tex_layer;
in float v_depth;
layout (binding = 0) uniform sampler2DArray samp;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 ambientColor;
uniform vec3 sunlightDir;
uniform vec3 cameraPos;
uniform bool shader_on;
uniform float specularStrength;
float weight(float z, float a) {
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
@@ -26,71 +15,7 @@ float weight(float z, float a) {
}
void main() {
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
if (!shader_on) {
vec4 color = objectColor;
float alpha = color.a;
if (alpha < 1e-4) discard;
float w = weight(v_depth, alpha);
accum = vec4(color.rgb * alpha * w, alpha * w);
reveal = alpha;
return;
}
vec3 lightDir = normalize(-sunlightDir);
vec3 norm = normalize(normal);
vec3 V =
normalize(cameraPos - vert_pos);
vec3 H =
normalize(lightDir + V);
vec3 ambient = ambientStrength * ambientColor;
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float r =
clamp(roughness, 0.0, 1.0);
float shininess =
mix(
512.0,
4.0,
r
);
float ks =
mix(
0.8,
0.02,
r
);
float spec = 0.0;
if(diff > 0.0)
{
spec =
ks *
pow(
max(dot(norm,H),0.0),
shininess
);
}
vec3 specular = spec * sunlightColor * specularStrength;
vec4 color = vec4((ambient + diffuse) * objectColor.rgb + specular, objectColor.a);
vec4 color = texture(samp, vec3(tc, tex_layer));
float alpha = color.a;
if (alpha < 1e-4) discard;

View File

@@ -3,28 +3,19 @@
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
layout (location = 3) in vec3 aNormal;
layout (location = 4) in float Roughness;
out vec2 tc;
out vec3 normal;
out vec3 vert_pos;
flat out int tex_layer;
out float roughness;
out float v_depth;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;
void main(void) {
vec4 view_pos = mv_matrix * vec4(pos, 1.0);
vert_pos = pos;
roughness = Roughness;
gl_Position = proj_matrix * view_pos;
tc = texCoord;
tex_layer = int(layer);
v_depth = -view_pos.z;
normal = mat3(norm_matrix) * aNormal;
gl_Position = proj_matrix * view_pos;
}

View File

@@ -3,34 +3,97 @@
in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in vec3 tangent;
in vec3 bitangent;
in vec4 FragPosLightSpace;
in float roughness;
flat in int tex_layer;
out vec4 color;
layout (binding = 0) uniform sampler2D shadowMap;
layout (binding = 1) uniform sampler2DArray samp;
layout (binding = 2) uniform sampler2DArray normMap;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 ambientColor;
uniform vec3 sunlightDir;
uniform vec3 cameraPos;
uniform bool shader_on;
uniform int shadowMode;
uniform float specularStrength;
uniform float lightSizeUV;
uniform float minRadius;
uniform float maxRadius;
uniform bool enablePBR;
uniform bool flipY;
uniform int renderDistance;
uniform vec3 skyColor;
const vec2 poissonDisk[8] = vec2[](
vec2( 0.1440, 0.7659), vec2(-0.5761, 0.4479),
vec2(-0.3220, -0.6058), vec2( 0.5693, -0.4048),
vec2(-0.1276, 0.1657), vec2(-0.0649, -0.0165),
vec2( 0.2773, -0.0305), vec2(-0.1134, -0.2122)
);
float random(vec3 seed) {
return fract(sin(dot(seed, vec3(12.9898,78.233,45.5432))) * 43758.5453);
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
{
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
projCoords.z < 0.0 || projCoords.z > 1.0) {
return 0.0;
}
float currentDepth = projCoords.z;
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
float shadow = 0.0;
float bias =
max(
0.0003,
0.001 * (1.0 - dot(norm, lightDir))
);
if (shadowMode == 0) {
vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0;
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
float radius = 0.7;
const int samples = 8;
for (int i = 0; i < samples; ++i) {
vec2 offset = rot * poissonDisk[i] * radius * texelSize;
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
shadow /= float(samples);
} else if (shadowMode == 1) {
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
vec2 offset = vec2(x, y) * texelSize;
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
}
shadow /= 9.0;
} else if (shadowMode == 2) {
// pcf off
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
} else {
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
}
return shadow;
}
#include "shadow.glsl"
#include "normal.glsl"
void main(void) {
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
@@ -45,73 +108,18 @@ void main(void) {
vec3 lightDir = normalize(-sunlightDir);
vec3 norm;
if (enablePBR) {
norm = calcNewNormal();
} else {
norm = normalize(normal);
}
vec3 V =
normalize(cameraPos - vert_pos);
vec3 H =
normalize(lightDir + V);
vec3 ambient = ambientStrength * ambientColor;
vec3 ambient = ambientStrength * sunlightColor;
vec3 norm = normalize(normal);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float r =
clamp(roughness, 0.0, 1.0);
float shininess =
mix(
512.0,
4.0,
r
);
float ks =
mix(
0.8,
0.02,
r
);
float spec = 0.0;
if(diff > 0.0)
{
spec =
ks *
pow(
max(dot(norm,H),0.0),
shininess
);
}
vec3 specular = spec * sunlightColor * specularStrength;
float shadow = ShadowCalculation(FragPosLightSpace, norm, lightDir);
// fog
float dist = length(cameraPos - vert_pos);
vec4 fogColor = vec4(skyColor, 1.0);
float fogStart = renderDistance * 16 * 0.9;
float fogEnd = renderDistance * 16;
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb, objectColor.a);
float fogFactor = smoothstep(fogEnd, fogStart, dist);
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb + (1.0-shadow) * specular * objectColor.rgb, objectColor.a);
color = mix(fogColor, color, fogFactor);
//color = vec4(normal * 0.5 + 0.5, 1.0);
//color = vec4(tangent * 0.5 + 0.5, 1.0);;
//color = vec4(norm * 0.5 + 0.5, 1.0);
//color = vec4(calcNewNormal(), 1.0);
//color = varyingColor;
}

View File

@@ -4,16 +4,11 @@ layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
layout (location = 3) in vec3 aNormal;
layout (location = 4) in float Roughness;
layout (location = 5) in vec3 aTangent;
out vec2 tc;
out vec3 normal;
out vec3 tangent;
out vec3 bitangent;
out vec3 vert_pos;
flat out int tex_layer;
out vec4 FragPosLightSpace;
out float roughness;
mat4 buildRotateX(float rad);
mat4 buildRotateY(float rad);
@@ -22,7 +17,6 @@ mat4 buildTranslate(float x, float y, float z);
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 model_matrix;
uniform mat4 norm_matrix;
uniform mat4 lightSpaceMatrix;
@@ -34,10 +28,8 @@ void main(void) {
tc = texCoord;
tex_layer = int(layer);
roughness = Roughness;
normal = normalize(mat3(norm_matrix) * aNormal);
tangent = normalize(mat3(model_matrix) * aTangent);
bitangent = cross(normal, tangent);
normal = mat3(norm_matrix) * aNormal;
FragPosLightSpace = lightSpaceMatrix * vec4(pos, 1.0);
gl_Position = proj_matrix * viewPos;
}

View File

@@ -1,46 +0,0 @@
#include "noise.glsl"
vec3 computeSkyColor(vec3 dir) {
vec3 sund = normalize(sunDir);
float t =
clamp(
dir.y * 0.5 + 0.5,
0.0,
1.0
);
vec3 sky =
mix(
skyBottom,
skyTop,
pow(t, horizonSharpness)
);
// cloud
if (dir.y > 0.0) {
vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002);
float cloud_density = fbm(cloud_uv * 2.0);
float safeLow = cloudThresholdLow;
float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001);
cloud_density = smoothstep(safeLow,safeHigh, cloud_density);
float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y));
cloud_density *= fade;
vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix);
sky = mix(sky, cloud_color, cloud_density * 0.6);
}
float sunAmount = max(dot(dir, sund), 0.0);
//float glow = pow(sunAmount, 8.0) * 0.15;
float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3;
sky += glow * sunColor;
return sky;
}

View File

@@ -1,7 +0,0 @@
#version 460
in vec2 tc;
void main() {
}

View File

@@ -1,15 +0,0 @@
#version 460
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
uniform mat4 lightSpaceMatrix;
uniform mat4 modelMatrix;
out vec2 tc;
flat out int tex_layer;
void main() {
tc = texCoord;
gl_Position = lightSpaceMatrix * modelMatrix * vec4(pos, 1.0);
}

View File

@@ -1,25 +0,0 @@
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
f = f * f * (3.0 - 2.0 * f);
float a = hash(i);
float b = hash(i + vec2(1.0, 0.0));
float c = hash(i + vec2(0.0, 1.0));
float d = hash(i + vec2(1.0, 1.0));
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}
float fbm(vec2 p) {
float v = 0.0;
float amp = 0.5;
for (int i = 0; i < 5; i++) {
v += amp * noise(p);
p *= 2.0;
amp *= 0.5;
}
return v;
}

View File

@@ -1,10 +0,0 @@
vec3 calcNewNormal() {
mat3 TBN = mat3(normalize(tangent), normalize(bitangent), normalize(normal));
vec3 retrievedNormal = texture(normMap, vec3(tc, tex_layer)).xyz;
retrievedNormal = retrievedNormal * 2.0 - 1.0;
if (flipY) {
retrievedNormal.y = -retrievedNormal.y;
}
vec3 newNormal = TBN * retrievedNormal;
return normalize(newNormal);
}

View File

@@ -1,47 +0,0 @@
#version 460
in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in vec4 FragPosLightSpace;
out vec4 color;
layout (binding = 0) uniform sampler2D shadowMap;
layout (binding = 1) uniform sampler2D samp;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 ambientColor;
uniform vec3 sunlightDir;
uniform bool shader_on;
uniform int shadowMode;
uniform float lightSizeUV;
uniform float minRadius;
uniform float maxRadius;
#include "shadow.glsl"
void main() {
vec4 objectColor = texture(samp, tc);
if (!shader_on) {
color = objectColor;
return;
}
vec3 lightDir = normalize(-sunlightDir);
vec3 norm = normalize(normal);
vec3 ambient = ambientStrength * ambientColor;
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float shadow = ShadowCalculation(FragPosLightSpace, norm, lightDir);
//float shadow = 0.0;
//color = vec4(vec3(shadow),1);
//color = vec4(vec3(diff),1);
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb, objectColor.a);
}

View File

@@ -1,27 +0,0 @@
#version 460
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 aNormal;
layout (location = 3) in vec3 aTangent;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;
uniform mat4 lightSpaceMatrix;
uniform mat4 modelMatrix;
out vec4 FragPosLightSpace;
out vec3 normal;
out vec2 tc;
out vec3 vert_pos;
void main() {
vec4 worldPos = modelMatrix * vec4(pos, 1.0);
FragPosLightSpace = lightSpaceMatrix * worldPos;
vec4 viewPos = mv_matrix * vec4(pos, 1.0);
tc = texCoord;
vert_pos = pos;
normal = normalize(mat3(norm_matrix) * aNormal);
gl_Position = proj_matrix * viewPos;
}

View File

@@ -1,238 +0,0 @@
const vec2 poissonDisk32[32] = vec2[](
vec2(-0.975402, -0.071138),
vec2(-0.920347, -0.411420),
vec2(-0.883908, 0.217872),
vec2(-0.815442, -0.879125),
vec2(-0.775043, 0.543896),
vec2(-0.698126, -0.227570),
vec2(-0.682433, 0.801894),
vec2(-0.563905, 0.021517),
vec2(-0.443233, -0.975116),
vec2(-0.412231, 0.361307),
vec2(-0.264969, -0.418930),
vec2(-0.241888, 0.997065),
vec2(-0.094184, -0.929389),
vec2(-0.019101, 0.680997),
vec2( 0.143832, -0.141008),
vec2( 0.199841, 0.786414),
vec2( 0.344959, 0.293878),
vec2( 0.443233, -0.475115),
vec2( 0.537430, -0.473734),
vec2( 0.589349, 0.569135),
vec2( 0.674281, -0.178897),
vec2( 0.791975, 0.190902),
vec2( 0.815442, 0.879125),
vec2( 0.896420, -0.613392),
vec2( 0.945586, -0.768907),
vec2( 0.974844, 0.756484),
vec2(-0.814100, 0.914376),
vec2(-0.382775, 0.276768),
vec2(-0.915886, 0.457714),
vec2( 0.537800, 0.912200),
vec2(-0.620000, -0.650000),
vec2( 0.120000, -0.780000)
);
const vec2 poissonDisk16[16] = vec2[](
vec2(-0.94201624, -0.39906216), vec2(0.94558609, -0.76890725),
vec2(-0.09418410, -0.92938870), vec2(0.34495938, 0.29387760),
vec2(-0.91588581, 0.45771432), vec2(-0.81544232, -0.87912464),
vec2(-0.38277543, 0.27676845), vec2(0.97484398, 0.75648379),
vec2(0.44323325, -0.97511554), vec2(0.53742981, -0.47373420),
vec2(-0.26496911, -0.41893023), vec2(0.79197514, 0.19090188),
vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590),
vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.14100790)
);
const vec2 poissonDisk8[8] = vec2[](
vec2( 0.1440, 0.7659), vec2(-0.5761, 0.4479),
vec2(-0.3220, -0.6058), vec2( 0.5693, -0.4048),
vec2(-0.1276, 0.1657), vec2(-0.0649, -0.0165),
vec2( 0.2773, -0.0305), vec2(-0.1134, -0.2122)
);
uniform int samples;
float random(vec3 seed) {
return fract(sin(dot(seed, vec3(12.9898,78.233,45.5432))) * 43758.5453);
}
float FindBlocker(vec2 uv,
float zReceiver,
vec2 texelSize,
float bias,
float lightSizeUV)
{
float avgDepth = 0.0;
int blockers = 0;
float searchRadius = lightSizeUV * 0.5;
for(int i = 0; i < samples; i++)
{
vec2 offset;
if (samples == 32) {
offset =
poissonDisk32[i]
* searchRadius
* texelSize;
} else if (samples == 16) {
offset =
poissonDisk16[i]
* searchRadius
* texelSize;
} else if (samples == 8) {
offset =
poissonDisk8[i]
* searchRadius
* texelSize;
} else {
offset =
poissonDisk32[i]
* searchRadius
* texelSize;
}
float depth =
texture(shadowMap, uv + offset).r;
if(depth < zReceiver - bias)
{
avgDepth += depth;
blockers++;
}
}
if(blockers == 0)
return -1.0;
return avgDepth / blockers;
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
{
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
projCoords.z < 0.0 || projCoords.z > 1.0) {
return 0.0;
}
float currentDepth = projCoords.z;
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
float shadow = 0.0;
float bias =
clamp(
0.001 * (1.0 - dot(norm, lightDir)),
0.0003,
0.003
);
if (shadowMode == 0) {
vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0;
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
//float radius = 0.7;
float radius = mix(1.0, 4.0, currentDepth);
for (int i = 0; i < samples; ++i) {
vec2 offset;
if (samples == 32) {
offset = rot * poissonDisk32[i] * radius * texelSize;
} else if (samples == 16) {
offset = rot * poissonDisk16[i] * radius * texelSize;
} else if (samples == 8) {
offset = rot * poissonDisk8[i] * radius * texelSize;
} else {
offset = rot * poissonDisk32[i] * radius * texelSize;
}
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
shadow /= float(samples);
} else if (shadowMode == 1) {
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
vec2 offset = vec2(x, y) * texelSize;
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
}
shadow /= 9.0;
} else if (shadowMode == 2) {
// pcf off
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
} else if (shadowMode == 3) {
float avgBlockerDepth =
FindBlocker(
projCoords.xy,
currentDepth,
texelSize,
bias,
lightSizeUV
);
if(avgBlockerDepth < 0.0)
{
return 0.0;
}
vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0;
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
/*
float penumbraRatio = (currentDepth - avgBlockerDepth);
float radius = clamp(
penumbraRatio * lightSizeUV,
minRadius,
maxRadius
);
*/
float radius =
mix(
minRadius,
maxRadius,
smoothstep(
0.0,
0.05,
currentDepth - avgBlockerDepth
)
);
for (int i = 0; i < samples; ++i) {
vec2 offset;
if (samples == 32) {
offset = rot * poissonDisk32[i] * radius * texelSize;
} else if (samples == 16) {
offset = rot * poissonDisk16[i] * radius * texelSize;
} else if (samples == 8) {
offset = rot * poissonDisk8[i] * radius * texelSize;
} else {
offset = rot * poissonDisk32[i] * radius * texelSize;
}
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
shadow /= float(samples);
} else {
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
}
return shadow;
}

View File

@@ -1,30 +1,11 @@
#version 460
in vec3 dir;
out vec4 frag_color;
uniform vec3 skyTop;
uniform vec3 skyBottom;
uniform vec3 sunDir;
uniform vec3 sunColor;
uniform float horizonSharpness;
uniform float cloudWhiteMix;
uniform float cloudThresholdLow;
uniform float cloudThresholdHigh;
uniform float time;
#include "compute_sky_color.glsl"
uniform vec3 color;
void main(void) {
vec3 sky = computeSkyColor(dir);
frag_color = vec4(color, 1.0);
frag_color = vec4(sky, 1.0);
}

View File

@@ -5,12 +5,6 @@ layout (location = 0) in vec3 vertices_pos;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
out vec3 dir;
void main(void) {
// Our skybox mesh uses [0,1] coordinates instead of the usual [-1,1].
// Shift to the cube center before normalizing to obtain the correct
// view direction for atmospheric calculations.
dir = normalize(vertices_pos - vec3(0.5));
gl_Position = proj_matrix * mv_matrix * vec4(vertices_pos, 1.0);
}

View File

@@ -1,111 +1,35 @@
#version 460
in vec2 TexCoord;
in vec3 rayDir;
out vec4 FragColor;
layout (binding = 0) uniform sampler2D u_sceneTexture;
layout (binding = 1) uniform sampler2D u_depthTexture;
layout (binding = 2) uniform sampler2D u_shadowMap;
uniform mat4 u_lightSpaceMatrix;
uniform sampler2D u_sceneTexture;
uniform float u_time;
uniform bool u_underwater;
uniform vec3 u_waterColor;
uniform float u_fogDensity;
uniform mat4 InverseViewProjection;
uniform vec3 cameraPos;
uniform vec3 sunDir;
uniform vec3 sunColor;
uniform float waterDensity;
#include "noise.glsl"
float getCausticValue(float x, float y, float z) {
float w = 8.0;
float strength = 4.0;
vec2 coord = vec2(x, y) * w + z * 0.5;
float n = fbm(coord);
float caustic = pow(n, 3.0) * strength;
return caustic;
}
float getShadow(vec3 worldPos) {
vec4 posLightSpace = u_lightSpaceMatrix * vec4(worldPos, 1.0);
vec3 projCoords = posLightSpace.xyz / posLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.z > 1.0) return 1.0;
float closestDepth = texture(u_shadowMap, projCoords.xy).r;
float currentDepth = projCoords.z;
return currentDepth - 0.005 > closestDepth ? 0.0 : 1.0;
}
void main() {
vec4 original = texture(u_sceneTexture, TexCoord);
if (!u_underwater) {
FragColor = original;
return;
}
float rawDepth = texture(u_depthTexture, TexCoord).r;
vec3 ndc = vec3(TexCoord * 2.0 - 1.0, rawDepth * 2.0 - 1.0);
vec4 worldPosH = InverseViewProjection * vec4(ndc, 1.0);
vec3 worldPos = worldPosH.xyz / worldPosH.w;
float sceneDistance = distance(cameraPos, worldPos);
vec2 distoredUV = TexCoord;
float strength = 0.003;
distoredUV.x += sin(TexCoord.y * 15.0 + u_time * 5.0) * strength;
distoredUV.y += cos(TexCoord.x * 15.0 + u_time * 4.3) * strength;
distoredUV = clamp(distoredUV, 0.001, 0.999);
vec4 distorted = texture(u_sceneTexture, distoredUV);
float rawCaustic = getCausticValue(TexCoord.x, TexCoord.y, u_time * 0.3);
float caustic = 0.5 + rawCaustic * 0.5;
vec3 causticLight = vec3(caustic * 0.9, caustic, caustic * 0.7);
vec4 distorted = texture(u_sceneTexture, distoredUV);
float caustic = 0.9 + 0.1 * sin(TexCoord.x * 20.0 + u_time) * cos(TexCoord.y * 20.0 + u_time * 1.2);
vec3 causticLight = vec3(caustic, caustic * 0.95, caustic * 0.9);
//vec3 causticLight = vec3(1.0);
float fogFactor = clamp(1.0 - (TexCoord.y * u_fogDensity * 10.0), 0.0, 1.0);
vec3 mixed = mix(u_waterColor, distorted.rgb * causticLight, fogFactor);
// Volume Scattering
vec3 rayOrigin = cameraPos;
vec3 rayDirection = normalize(rayDir);
float maxDist = 10.0; // Maximum visible distance
float stepSize = 0.4;
float phasePower = 8.0; // Beam Sharpness
vec3 scattering = vec3(0.0);
float transmittance = 1.0;
float cosTheta = dot(rayDirection, sunDir);
float phase = pow(max(cosTheta, 0.0), phasePower);
for (float t = 0.0; t < maxDist; t += stepSize) {
if (t > sceneDistance) break;
vec3 pos = rayOrigin + rayDirection * t;
float shadow = getShadow(pos);
float density = waterDensity;
vec3 absorption = vec3(0.3, 0.08, 0.02); // Absorption coefficient per meter
vec3 sunLightAtPos = sunColor * exp(-absorption * t);
scattering += density * phase * sunLightAtPos * transmittance * stepSize * shadow;
float extinction = waterDensity * 1.5; // Extinction coefficient, tunable
transmittance *= exp(-extinction * stepSize);
if (transmittance < 0.01) break;
}
FragColor.rgb = mixed + scattering;
FragColor.a = 1.0;
FragColor = vec4(mixed, 1.0);
}

View File

@@ -3,18 +3,9 @@
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 texCoord;
uniform mat4 InverseViewProjection;
uniform vec3 cameraPos;
out vec2 TexCoord;
out vec3 rayDir;
void main() {
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
TexCoord = texCoord;
vec4 clipPos = vec4(pos, 1.0, 1.0);
vec4 worldPosH = InverseViewProjection * clipPos;
vec3 worldPos = worldPosH.xyz / worldPosH.w;
vec3 RayDir = worldPos - cameraPos;
rayDir = normalize(RayDir);
gl_Position = clipPos;
}

View File

@@ -1,248 +0,0 @@
#version 460
layout (location = 0) out vec4 accum;
layout (location = 1) out float reveal;
in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in vec3 world_pos;
in float roughness;
flat in int tex_layer;
in float v_depth;
layout (binding = 0) uniform sampler2DArray samp;
uniform sampler2D sceneColorTex; // binding 1
uniform sampler2D sceneDepthTex; // binding 2
uniform mat4 proj_matrix;
uniform mat4 inv_proj_matrix;
uniform mat4 inv_view_matrix;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 ambientColor;
uniform vec3 sunlightDir;
uniform bool shader_on;
uniform float specularStrength;
uniform vec3 skyTop;
uniform vec3 skyBottom;
uniform vec3 sunColor;
uniform float horizonSharpness;
uniform float cloudWhiteMix;
uniform float cloudThresholdLow;
uniform float cloudThresholdHigh;
uniform float time;
uniform vec3 sunDir; // world!
uniform bool underwater;
uniform float refractStrength;
uniform bool enablePerturb;
uniform bool enableDepthFade;
#include "compute_sky_color.glsl"
float weight(float z, float a) {
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
return a * clamp(intermediate, 1e-2, 3e2);
}
// Reconstruct eye-space coordinates from screen UV and depth buffer value
vec3 reconstructViewPos(vec2 uv, float depth) {
vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 view = inv_proj_matrix * clip;
return view.xyz / view.w;
}
// Screen-space ray marching, origin/dir are in eye space
bool traceSSR(vec3 origin, vec3 dir, out vec2 hitUV) {
const int COARSE_STEPS = 32;
const float COARSE_STEP = 0.6;
const int REFINE_STEPS = 8;
const float THICKNESS = 0.3;
vec3 pos = origin;
vec3 prevPos = origin;
bool foundCoarse = false;
for (int i = 0; i < COARSE_STEPS; ++i) {
prevPos = pos;
pos += dir * COARSE_STEP;
vec4 clip = proj_matrix * vec4(pos, 1.0);
if (clip.w <= 0.0) return false;
vec3 ndc = clip.xyz / clip.w;
if (abs(ndc.x) > 1.0 || abs(ndc.y) > 1.0) return false;
vec2 uv = ndc.xy * 0.5 + 0.5;
float sceneDepth = texture(sceneDepthTex, uv).r;
vec3 scenePos = reconstructViewPos(uv, sceneDepth);
if (pos.z - scenePos.z < 0.0) {
foundCoarse = true;
break;
}
}
if (!foundCoarse) return false;
vec3 lo = prevPos;
vec3 hi = pos;
for (int i = 0; i < REFINE_STEPS; ++i) {
vec3 mid = (lo + hi) * 0.5;
vec4 clip = proj_matrix * vec4(mid, 1.0);
vec3 ndc = clip.xyz / clip.w;
vec2 uv = ndc.xy * 0.5 + 0.5;
float sceneDepth = texture(sceneDepthTex, uv).r;
vec3 scenePos = reconstructViewPos(uv, sceneDepth);
if (mid.z - scenePos.z < 0.0) {
hi = mid;
} else {
lo = mid;
}
}
vec4 finalClip = proj_matrix * vec4(hi, 1.0);
vec3 finalNdc = finalClip.xyz / finalClip.w;
vec2 finalUV = finalNdc.xy * 0.5 + 0.5;
float finalDepth = texture(sceneDepthTex, finalUV).r;
vec3 finalScenePos = reconstructViewPos(finalUV, finalDepth);
if (abs(hi.z - finalScenePos.z) > THICKNESS) return false;
hitUV = finalUV;
return true;
}
void main() {
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
if (!shader_on) {
vec4 color = objectColor;
float alpha = color.a;
if (alpha < 1e-4) discard;
float w = weight(v_depth, alpha);
accum = vec4(color.rgb * alpha * w, alpha * w);
reveal = alpha;
return;
}
// Normal perturbation
vec3 N;
if (enablePerturb) {
const float wave_speed_scale = 40.0;
vec2 waveUV1 = world_pos.xz * 8.0 + vec2(time * 0.05 * wave_speed_scale, time * 0.03 * wave_speed_scale);
vec2 waveUV2 = world_pos.xz * 13.0 + vec2(-time * 0.04 * wave_speed_scale, time * 0.06 * wave_speed_scale);
float wave1 = noise(waveUV1);
float wave2 = noise(waveUV2);
vec2 normalPerturb = vec2(wave1 - 0.5, wave2 - 0.5) * 0.1;
N = normalize(normal + vec3(normalPerturb.x, 0.0, normalPerturb.y));
} else {
N = normalize(normal);
}
vec3 V = normalize(-vert_pos);
vec3 reflectColor;
vec3 refractColor;
float fresnel;
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTex, 0));
// water depth
float sceneDepthRaw = texture(sceneDepthTex, screenUV).r;
vec3 sceneViewPos = reconstructViewPos(screenUV, sceneDepthRaw);
float waterDepth = vert_pos.z - sceneViewPos.z;
waterDepth = max(waterDepth, 0.0);
const float DEPTH_FADE_DISTANCE = 10;
float depthFactor = clamp(waterDepth / DEPTH_FADE_DISTANCE, 0.0, 1.0);
if (underwater) {
reflectColor = vec3(0.0);
refractColor = objectColor.rgb;
fresnel = 0.0;
} else {
vec3 R = reflect(-V, N);
vec3 origin = vert_pos + N * 0.05;
vec2 hitUV;
if (traceSSR(origin, R, hitUV)) {
reflectColor = texture(sceneColorTex, hitUV).rgb;
} else {
vec3 worldR = mat3(inv_view_matrix) * R;
reflectColor = computeSkyColor(worldR);
}
float effectiveRefractStrength = refractStrength * (1.0 - depthFactor * 0.5);
vec2 refractOffset = N.xz * effectiveRefractStrength;
vec2 refractUV = clamp(screenUV + refractOffset, vec2(0.001), vec2(0.999));
refractColor = texture(sceneColorTex, refractUV).rgb;
fresnel = pow(1.0 - max(dot(N, V), 0.0), 5.0);
fresnel = mix(0.02, 1.0, fresnel);
}
vec3 lightDir = normalize(-sunlightDir);
vec3 H = normalize(lightDir + V);
vec3 ambient = ambientStrength * ambientColor;
float diff = max(dot(N, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float r = clamp(roughness, 0.0, 1.0);
float shininess = mix(512.0, 4.0, r);
float ks = mix(0.8, 0.02, r);
float spec = 0.0;
if (diff > 0.0) {
spec = ks * pow(max(dot(N, H), 0.0), shininess);
}
vec3 specular = spec * sunlightColor * specularStrength;
vec3 tintedRefract;
if (enableDepthFade) {
vec3 shallowColor = vec3(0.4, 0.75, 0.7);
vec3 deepColor = vec3(0.0, 0.015, 0.045);
vec3 waterTint = mix(shallowColor, deepColor, depthFactor);
tintedRefract = mix(refractColor, refractColor * waterTint, depthFactor);
tintedRefract = mix(tintedRefract, objectColor.rgb, 0.4); // Forcefully blend 40% texture color, independent of depth
} else {
tintedRefract = mix(refractColor, objectColor.rgb, 0.4);
}
//vec3 baseWaterColor = (ambient + diffuse) * objectColor.rgb + specular;
vec3 baseWaterColor = (ambient + diffuse) * tintedRefract + specular;
vec3 finalColor = mix(baseWaterColor, reflectColor, fresnel);
float alpha = objectColor.a;
if (alpha < 1e-4) discard;
float w = weight(v_depth, alpha);
accum = vec4(finalColor * alpha * w, alpha * w);
reveal = alpha;
return;
}

View File

@@ -1,32 +0,0 @@
#version 460
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
layout (location = 3) in vec3 aNormal;
layout (location = 4) in float Roughness;
out vec2 tc;
out vec3 normal;
out vec3 vert_pos;
out vec3 world_pos;
flat out int tex_layer;
out float roughness;
out float v_depth;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;
void main(void) {
vec4 view_pos = mv_matrix * vec4(pos, 1.0);
world_pos = pos;
vert_pos = view_pos.xyz;
normal = mat3(norm_matrix) * aNormal;
roughness = Roughness;
tc = texCoord;
tex_layer = int(layer);
v_depth = -view_pos.z;
gl_Position = proj_matrix * view_pos;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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