Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 98 additions & 38 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ jobs:
set -e
pkgs="${{ matrix.prefix }}-SDL2 ${{ matrix.prefix }}-openal ${{ matrix.prefix }}-freetype ${{ matrix.prefix }}-lua ${{ matrix.prefix }}-openssl ${{ matrix.prefix }}-curl ${{ matrix.prefix }}-bullet"
for attempt in 1 2 3 4 5; do
pacman -S --needed --noconfirm $pkgs && exit 0
# Refresh db + avoid spurious timeouts on congested mirrors (curl stack under pacman).
pacman -Sy --noconfirm || true
pacman -S --needed --noconfirm --disable-download-timeout $pkgs && exit 0
echo "pacman attempt $attempt failed, retrying in $((attempt * 20))s..."
sleep $((attempt * 20))
done
Expand Down Expand Up @@ -752,7 +754,16 @@ jobs:

steps:
- name: Install tools
run: brew install coreutils sdl2 openal-soft cmake ninja freetype lua molten-vk bullet pkgconf
run: |
set -e
for attempt in 1 2 3 4; do
if brew install coreutils sdl2 openal-soft cmake ninja freetype lua molten-vk bullet pkgconf; then
exit 0
fi
echo "brew install attempt $attempt failed, retrying in $((attempt * 20))s..."
sleep $((attempt * 20))
done
exit 1

- uses: actions/checkout@v4

Expand Down Expand Up @@ -877,13 +888,22 @@ jobs:

- name: Install NDK
run: |
sdkmanager --install "ndk;27.0.12077973" "cmake;3.22.1"
set -e
yes | sdkmanager --licenses >/dev/null 2>&1 || true
for attempt in 1 2 3 4 5; do
if sdkmanager --install "ndk;27.0.12077973" "cmake;3.22.1"; then
exit 0
fi
echo "sdkmanager attempt $attempt failed, retrying in $((attempt * 15))s..."
sleep $((attempt * 15))
done
exit 1

- name: Cache Android third-party downloads (Lua, FetchContent)
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.ci-android-deps
key: android-deps-${{ matrix.abi }}-ossl-3.0.15-lua-5.4.7-ft-${{ hashFiles('CMakeLists.txt') }}
key: android-deps-${{ matrix.abi }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'android/**', '.github/workflows/build.yml') }}
restore-keys: |
android-deps-${{ matrix.abi }}-

Expand All @@ -908,38 +928,60 @@ jobs:

mkdir -p build-android-${{ matrix.btype }}-${{ matrix.abi }}
mkdir -p "${GITHUB_WORKSPACE}/.ci-android-deps"
cmake -S .. -B build-android-${{ matrix.btype }}-${{ matrix.abi }} \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" \
-DANDROID_ABI="$ANDROID_ABI" \
-DANDROID_PLATFORM=android-26 \
-DANDROID_STL=c++_shared \
-DANDROID_DEPS_CACHE="${GITHUB_WORKSPACE}/.ci-android-deps" \
-DCMAKE_BUILD_TYPE=${{ matrix.btype }} \
-DBUILD_SERVER=OFF \
-DUSE_VULKAN=ON \
-DUSE_RENDERER_DLOPEN=OFF \
-DRENDERER_DEFAULT=vulkan \
-DSKIP_IDPAK_CHECK=ON \
-DSKIP_SHADER_REGEN=ON \
-DUSE_SDL=OFF \
-DUSE_OPENAL=OFF \
-DUSE_CURL=ON \
-DUSE_LUA=ON \
-DUSE_DUKTAPE=ON \
-DUSE_FFMPEG=ON \
-DUSE_DAV1D=ON \
-DUSE_VPX=ON \
-DUSE_THEORA=ON \
-DUSE_FLUX=ON \
-DUSE_RECAST_NAV=ON \
-DUSE_BULLET_PHYSICS=ON \
-DBUILD_FREETYPE=ON \
-DUSE_DTLS=ON \
-DENABLE_FORTIFY_SOURCE=OFF \
-DENABLE_ASAN=OFF \
-DCI_BUILD=OFF \
-Wno-dev
cmake --build build-android-${{ matrix.btype }}-${{ matrix.abi }} -j$(nproc)
for attempt in 1 2 3; do
if cmake -S .. -B build-android-${{ matrix.btype }}-${{ matrix.abi }} \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" \
-DANDROID_ABI="$ANDROID_ABI" \
-DANDROID_PLATFORM=android-26 \
-DANDROID_STL=c++_shared \
-DANDROID_DEPS_CACHE="${GITHUB_WORKSPACE}/.ci-android-deps" \
-DCMAKE_BUILD_TYPE=${{ matrix.btype }} \
-DBUILD_SERVER=OFF \
-DUSE_VULKAN=ON \
-DUSE_RENDERER_DLOPEN=OFF \
-DRENDERER_DEFAULT=vulkan \
-DSKIP_IDPAK_CHECK=ON \
-DSKIP_SHADER_REGEN=ON \
-DUSE_SDL=OFF \
-DUSE_OPENAL=OFF \
-DUSE_CURL=ON \
-DUSE_LUA=ON \
-DUSE_DUKTAPE=ON \
-DUSE_FFMPEG=ON \
-DUSE_DAV1D=ON \
-DUSE_VPX=ON \
-DUSE_THEORA=ON \
-DUSE_FLUX=ON \
-DUSE_RECAST_NAV=ON \
-DUSE_BULLET_PHYSICS=ON \
-DBUILD_FREETYPE=ON \
-DUSE_DTLS=ON \
-DENABLE_FORTIFY_SOURCE=OFF \
-DENABLE_ASAN=OFF \
-DCI_BUILD=OFF \
-Wno-dev; then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "cmake configure failed after 3 attempts"
exit 1
fi
echo "cmake configure attempt $attempt failed, cleaning build dir and retrying in $((attempt * 20))s..."
rm -rf "build-android-${{ matrix.btype }}-${{ matrix.abi }}"
mkdir -p "build-android-${{ matrix.btype }}-${{ matrix.abi }}"
sleep $((attempt * 20))
done
for attempt in 1 2 3; do
if cmake --build build-android-${{ matrix.btype }}-${{ matrix.abi }} -j$(nproc); then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "cmake --build failed after 3 attempts"
exit 1
fi
echo "cmake --build attempt $attempt failed, retrying in $((attempt * 25))s..."
sleep $((attempt * 25))
done

mkdir -p ../bin
find build-android-${{ matrix.btype }}-${{ matrix.abi }} -maxdepth 2 \
Expand Down Expand Up @@ -973,8 +1015,16 @@ jobs:

- name: Install NDK, CMake (match app/build.gradle), SDK platform 35
run: |
set -e
yes | sdkmanager --licenses >/dev/null 2>&1 || true
sdkmanager --install "ndk;27.0.12077973" "cmake;3.31.6" "platforms;android-35" "build-tools;35.0.0"
for attempt in 1 2 3 4 5; do
if sdkmanager --install "ndk;27.0.12077973" "cmake;3.31.6" "platforms;android-35" "build-tools;35.0.0"; then
exit 0
fi
echo "sdkmanager attempt $attempt failed, retrying in $((attempt * 15))s..."
sleep $((attempt * 15))
done
exit 1

- name: Cache Android third-party downloads
uses: actions/cache@v4
Expand All @@ -996,7 +1046,17 @@ jobs:
chmod +x ./gradlew
SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME}}"
echo "sdk.dir=${SDK_ROOT}" > local.properties
./gradlew assembleDebug --no-daemon -PandroidDepsCache="${ANDROID_DEPS_CACHE}"
for attempt in 1 2 3; do
if ./gradlew assembleDebug --no-daemon -PandroidDepsCache="${ANDROID_DEPS_CACHE}"; then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "gradlew assembleDebug failed after 3 attempts"
exit 1
fi
echo "gradlew attempt $attempt failed, retrying in $((attempt * 30))s..."
sleep $((attempt * 30))
done
ls -la app/build/outputs/apk/debug/

- uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion docs/RENDERERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The Vulkan 1.4 renderer is the primary rendering backend, built as a shared libr
- Spherical harmonics for diffuse irradiance
- Multi-scatter energy compensation
- **Glint NDF**: Procedural microfacet NDF for specular glints (replaces GGX D term on low-roughness surfaces). Cvars: `r_glint`, `r_glintMode`, `r_glintDensity`, `r_glintMicrofacetRoughness`, `r_glintPixelFilterSize`, `r_glintSampleBudget`, `r_glintMaxLodClamp`, `r_glintRoughnessLo`, `r_glintRoughnessHi`, `r_glintDMax`. Debug modes 5–8 via `r_pbr_debug`.
- **Parallax Occlusion Mapping (POM)**: When a **normal map** and **packed ORM/physical map** (metalness/roughness workflow, `physical_texture_set == 0`) are both bound, the fragment shader ray-marches height from the physical map’s **occlusion (R)** channel to displace UVs for normal/ORM/detail/emissive/subsurface/anisotropy sampling and direct lighting self-shadowing. Disabled on lightmapped multi-UV PBR paths. Shader keywords `parallaxDepth` (height scale, stored in `normalScale[3]`) and `parallaxBias` still apply. Cvars: `r_pom`, `r_pomSteps`, `r_pomScale`, `r_pomShadow`, `r_pomShadowSteps`. Startup prints a one-line POM summary when PBR initializes.
- **Parallax Occlusion Mapping (POM)**: With `r_pom` on, height is ray-marched from **either** the packed ORM/physical map’s **occlusion (R)** channel (when a metalness/roughness physical map is bound) **or** the **normal map alpha** when the stage uses `normalHeightMap` (decouples height from AO). Base UVs (`texcoord0`) are displaced for normal/ORM/detail/emissive/subsurface/anisotropy sampling; lightmaps still sample their own UV set. Shader keywords `parallaxDepth` (height scale, stored in `normalScale[3]`) and `parallaxBias` still apply. Cvars: `r_pom`, `r_pomSteps`, `r_pomScale`, `r_pomShadow`, `r_pomShadowSteps`. Startup prints a one-line POM summary when PBR initializes.
- See [PBR_TEXTURES.md](PBR_TEXTURES.md) for texture naming conventions

### Volumetric Fog
Expand Down
27 changes: 17 additions & 10 deletions src/renderers/vulkan/shaders/glsl/gen_frag.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ layout(set = 0, binding = 0) uniform UBO {
vec4 pbrGlintFlags;
vec4 pbrDebugMode; // x: debug mode selector
vec4 pbrShCoeffs[9];
vec4 pbrParallaxParams; // x=scale, y=shadow str, z=shadow steps (float), w=unused
vec4 pbrParallaxParams; // x=scale, y=shadow str, z=shadow steps (float), w=unused (reserved)
#endif
//#endif
};
Expand Down Expand Up @@ -191,9 +191,10 @@ layout (constant_id = 32) const float lightmap_scale = 1.0; // HDR lightmap int
layout (constant_id = 33) const int lightmap_srgb_decode = 0; // 1: sRGB->linear when BSP lightmaps are gamma-encoded
layout (constant_id = 34) const int detail_texture_set = -1; // 0: detail map active
layout (constant_id = 35) const float detail_scale = 4.0; // tiling frequency for detail UV
layout (constant_id = 36) const int pom_enabled = 0;
layout (constant_id = 37) const int pom_max_steps = 16;
layout (constant_id = 38) const float parallax_bias_shader = 0.0;
layout (constant_id = 36) const int pom_height_source = 0; // 0: ORM R (physical map), 1: normal map alpha (normalHeightMap)
layout (constant_id = 37) const int pom_enabled = 0;
layout (constant_id = 38) const int pom_max_steps = 16;
layout (constant_id = 39) const float parallax_bias_shader = 0.0;

vec3 lightmapDecode( vec3 c ) {
/* sRGB to linear: use when BSP lightmaps are gamma-encoded (q3map2 -gamma, etc.) */
Expand Down Expand Up @@ -225,8 +226,13 @@ vec3 sampleLightmap( void ) {
return texture( texture0, uv ).rgb;
}

float SamplePhysicalHeight( vec2 uv )
float SampleParallaxHeight( vec2 uv )
{
if ( pom_height_source == 1 ) {
if ( normal_texture_set < 0 )
return 0.0;
return clamp( texture( normal_texture, uv ).a, 0.0, 1.0 );
}
if ( physical_texture_set != 0 )
return 0.0;
return clamp( texture( physical_texture, uv ).r, 0.0, 1.0 );
Expand All @@ -242,7 +248,7 @@ vec2 ParallaxOcclusionMap( vec2 uv, vec3 viewDirTS, float heightScale, int maxSt
vec2 deltaUV = heightScale * vd.xy / ( dz * float( maxSteps ) );
float layerDepth = 1.0 / float( maxSteps );
float curLayerDepth = 0.0;
float curH = SamplePhysicalHeight( uv );
float curH = SampleParallaxHeight( uv );
float prevH = curH;
vec2 prevUV = uv;
int i;
Expand All @@ -253,7 +259,7 @@ vec2 ParallaxOcclusionMap( vec2 uv, vec3 viewDirTS, float heightScale, int maxSt
prevH = curH;
uv -= deltaUV;
curLayerDepth += layerDepth;
curH = SamplePhysicalHeight( uv );
curH = SampleParallaxHeight( uv );
}
vec2 p0 = prevUV;
vec2 p1 = uv;
Expand All @@ -271,15 +277,15 @@ float ParallaxSoftShadow( vec2 uv, vec3 lightDirTS, float heightScale, int shado
vec3 ld = normalize( lightDirTS );
if ( ld.z <= 0.001 )
return 1.0;
float h0 = SamplePhysicalHeight( uv );
float h0 = SampleParallaxHeight( uv );
float dz = max( ld.z, 0.05 );
vec2 delta = heightScale * ld.xy / ( dz * float( shadowSteps ) );
float sh = 1.0;
float rayH = h0;
int s;
for ( s = 1; s < shadowSteps; s++ ) {
vec2 suv = uv + delta * float( s );
float surf = SamplePhysicalHeight( suv );
float surf = SampleParallaxHeight( suv );
if ( surf + 0.005 > rayH ) {
sh *= clamp( 1.0 - ( surf - rayH ) * 8.0, 0.0, 1.0 );
}
Expand Down Expand Up @@ -1035,7 +1041,8 @@ void main() {

vec2 pbrSurfUV = frag_tex_coord0;
float pomSelfShadow = 1.0;
if ( pom_enabled != 0 && physical_texture_set == 0 && normal_texture_set >= 0 ) {
if ( pom_enabled != 0 && normal_texture_set >= 0 &&
( pom_height_source == 1 || physical_texture_set == 0 ) ) {
float hScale = normalScale_w * max( pbrParallaxParams.x, 0.0001 );
vec3 Tn = normalize( var_Tangent.xyz );
vec3 Bn = normalize( cross( var_Normal.xyz, Tn ) * var_Tangent.w );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
glslang_validator_path=/usr/bin/glslangValidator
glslang_validator_version=Glslang Version: 11:15.1.0
generated_at=2026-04-10T05:30:09Z
shader_data_sha256=336beb23b88d7c95043146e6d4c3ef6afb2a3d320ee42643bb73399844850326
generated_at=2026-04-10T05:44:33Z
shader_data_sha256=5cc9f441027dc76a95cd2a1665cd13b8d7541d572d249983c1a085420b95a76c
shader_binding_sha256=a9b2b467297fb83d4232cf30c4a2abc434e151f7aa54d57fe54f67c01ac17706
Loading
Loading