diff options
| author | yum <yum.food.vr@gmail.com> | 2026-03-30 19:04:05 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-03-30 19:04:05 -0700 |
| commit | ec217afada3913129d6ca038b1bf8539a4adb9c0 (patch) | |
| tree | 3de7a2b20c138169367b720f0b47b42a2a7ecfca | |
| parent | c7c1f7733eac8d28faed999ee0dc4796d16a6ade (diff) | |
Add burley tiling AO; make LUTS gradient editable
| -rwxr-xr-x | 3ner.shader | 12 | ||||
| -rw-r--r-- | burley.cginc | 172 | ||||
| -rwxr-xr-x | features.cginc | 1 | ||||
| -rwxr-xr-x | globals.cginc | 5 | ||||
| -rwxr-xr-x | lighting.cginc | 16 | ||||
| -rwxr-xr-x | pbr.cginc | 157 |
6 files changed, 206 insertions, 157 deletions
diff --git a/3ner.shader b/3ner.shader index 63e8118..4ec5b47 100755 --- a/3ner.shader +++ b/3ner.shader @@ -696,11 +696,19 @@ Shader "yum_food/3ner" _Burley_Tiling_Maintex("Base color", 2D) = "white" {} _Burley_Tiling_Maintex_LUT("Base color LUT", 2D) = "white" {} + //ifex _Burley_Tiling_Ambient_Occlusion_Enabled==0 + [HideInInspector] m_start_Burley_Tiling_Ambient_Occlusion("Ambient Occlusion", Float) = 0 + [ThryToggle(_BURLEY_TILING_AMBIENT_OCCLUSION)] _Burley_Tiling_Ambient_Occlusion_Enabled("Enable", Float) = 0 + _Burley_Tiling_Ambient_Occlusion_Map("Texture", 2D) = "white" {} + [Gradient] _Burley_Tiling_Ambient_Occlusion_Map_LUT("LUT", 2D) = "white" {} + [HideInInspector] m_end_Burley_Tiling_Ambient_Occlusion("Ambient Occlusion", Float) = 0 + //endex + //ifex _Burley_Tiling_Smoothness_Enabled==0 [HideInInspector] m_start_Burley_Tiling_Smoothness("Smoothness", Float) = 0 [ThryToggle(_BURLEY_TILING_SMOOTHNESS)] _Burley_Tiling_Smoothness_Enabled("Enable", Float) = 0 _Burley_Tiling_Smoothness_Map("Texture", 2D) = "white" {} - _Burley_Tiling_Smoothness_Map_LUT("LUT", 2D) = "white" {} + [Gradient] _Burley_Tiling_Smoothness_Map_LUT("LUT", 2D) = "white" {} //ifex _Burley_Tiling_Smoothness_Invert_Enabled==0 [HideInInspector] m_start_Burley_Tiling_Smoothness_Invert("Invert", Float) = 0 @@ -723,7 +731,7 @@ Shader "yum_food/3ner" [HideInInspector] m_start_Burley_Tiling_Heightmap("Heightmap", Float) = 0 [ThryToggle(_BURLEY_TILING_HEIGHTMAP)] _Burley_Tiling_Heightmap_Enabled("Enable", Float) = 0 _Burley_Tiling_Heightmap("Texture", 2D) = "gray" {} - _Burley_Tiling_Heightmap_LUT("LUT", 2D) = "white" {} + [Gradient] _Burley_Tiling_Heightmap_LUT("LUT", 2D) = "white" {} [HideInInspector] m_end_Burley_Tiling_Heightmap("Heightmap", Float) = 0 //endex diff --git a/burley.cginc b/burley.cginc new file mode 100644 index 0000000..ac225d7 --- /dev/null +++ b/burley.cginc @@ -0,0 +1,172 @@ +#ifndef __BURLEY_INC +#define __BURLEY_INC + +#include "data.cginc" +#include "math.cginc" + +#if defined(_BURLEY_TILING) +float2 burley_tri_to_cart(float2 tri_coord) { + return float2( + tri_coord.x + tri_coord.y * 0.5f, + tri_coord.y * SQRT_3_OVER_2); +} + +float3 burley_apply_blend_gamma(float3 weights, float gamma) { + weights = pow(weights, gamma); + return weights / (weights.x + weights.y + weights.z); +} + +// Equation 4 (first half). +float3 burley_soft_clipping_lower_half(float3 x_hat, float w_hat) { + float linear_start = 0.25f * (2.0f - w_hat); + float3 linear_value = (x_hat - 0.5f) / w_hat + 0.5f; + float3 linear_mask = step(float3(linear_start, linear_start, linear_start), x_hat); + + if (w_hat >= TWO_OVER_THREE) { + float3 t = x_hat / (2.0f - w_hat); + float3 quadratic = 8.0f * (1.0f / w_hat - 1.0f) * t * t + (3.0f - 2.0f / w_hat) * t; + return lerp(quadratic, linear_value, linear_mask); + } + + float quadratic_start = 0.25f * (2.0f - 3.0f * w_hat); + float3 d = (x_hat - quadratic_start) / w_hat; + float3 quadratic = d * d; + float3 quadratic_mask = step(float3(quadratic_start, quadratic_start, quadratic_start), x_hat); + float3 result = quadratic * quadratic_mask; + return lerp(result, linear_value, linear_mask); +} + +// Equation 4. +float3 burley_soft_clipping_contrast(float3 x_hat, float w_hat) { + float3 upper_mask = step(0.5f, x_hat); + float3 lower_x = min(x_hat, 1.0f - x_hat); + float3 lower_y = burley_soft_clipping_lower_half(lower_x, w_hat); + return lerp(lower_y, 1.0f - lower_y, upper_mask); +} + +float3 burley_apply_soft_clipping(float3 gaussian_color, float3 weights) { + float w_hat = sqrt(dot(weights, weights)); + return burley_soft_clipping_contrast(gaussian_color, w_hat); +} + +float3 burley_degaussianize(texture2D lut, float3 gaussian_color, bool decode_srgb = true) { + float2 uv_r = float2(gaussian_color.r, 0.5f); + float2 uv_g = float2(gaussian_color.g, 0.5f); + float2 uv_b = float2(gaussian_color.b, 0.5f); + float lut_r = lut.Sample(linear_clamp_s, uv_r).r; + float lut_g = lut.Sample(linear_clamp_s, uv_g).g; + float lut_b = lut.Sample(linear_clamp_s, uv_b).b; + float3 restored = float3(lut_r, lut_g, lut_b); + return decode_srgb ? srgb_to_linear(restored) : restored; +} + +struct BurleyPatchTransform { + float2 uv; + float2 dx; + float2 dy; + float2x2 uv_to_patch; +}; + +BurleyPatchTransform burley_make_patch_transform(float2 uv, float2 uv_dx, float2 uv_dy, + float2 tri_vertex, float input_scale) { + float3 cube_id = float3(tri_vertex.x, tri_vertex.y, -tri_vertex.x - tri_vertex.y); + float3 tile_rand3 = hash33_fast(cube_id); + float2 vertex_uv = burley_tri_to_cart(tri_vertex); + // Map the unit-radius hex support to the unit square so arbitrary rotation + // stays within bounds. + float2 local_uv = (uv - vertex_uv) * 0.5f; + // Apply input scaling. + local_uv *= input_scale; + float2 sample_dx = uv_dx * (0.5f * input_scale); + float2 sample_dy = uv_dy * (0.5f * input_scale); + // Rotate. + float theta = hash31_ff(tile_rand3) * TAU; + float2x2 rot = float2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); + local_uv = mul(rot, local_uv); + sample_dx = mul(rot, sample_dx); + sample_dy = mul(rot, sample_dy); + // Apply randomized offset, staying within bounds. + // The scaled-and-rotated footprint is bounded by [-Input_Scale / 2, Input_Scale / 2], + // so we can offset by [(1 - Input_Scale) / 2]. + float2 random_offset = (tile_rand3.yz * 2.0f - 1.0f) * (0.5f * (1.0f - input_scale)); + local_uv += random_offset; + // Finally, remap onto [0, 1]. + local_uv += 0.5f; + + BurleyPatchTransform patch; + patch.uv = local_uv; + patch.dx = sample_dx; + patch.dy = sample_dy; + patch.uv_to_patch = rot * (0.5f * input_scale); + return patch; +} + +float4 burley_sample_patch(texture2D tex, BurleyPatchTransform patch) { + return tex.SampleGrad( + aniso4_trilinear_repeat_s, patch.uv, patch.dx, patch.dy); +} + +struct BurleyTilingContext { + BurleyPatchTransform patch_0; + BurleyPatchTransform patch_1; + BurleyPatchTransform patch_2; + float3 weights; + float2 base_uv; + float uv_scale; +}; + +static BurleyTilingContext _burley_ctx; + +void burley_tiling_setup(float2 base_uv) { + _burley_ctx.base_uv = base_uv; + float2 uv = base_uv - 0.5; + // Scale so that any rotation remains within [0, 1] bounds. + uv *= TWO_OVER_SQRT_3; + uv /= _Burley_Tiling_Output_Scale; + _burley_ctx.uv_scale = TWO_OVER_SQRT_3 / _Burley_Tiling_Output_Scale; + float3 hex_coord = cart_to_hex(uv); + float2 tri_coord = hex_coord.yz; + float2 tri_cell = floor(tri_coord); + float2 tri_frac = tri_coord - tri_cell; + float2 vertex_0; + float2 vertex_1; + float2 vertex_2; + float3 baryc; + if (tri_frac.x + tri_frac.y < 1.0f) { + vertex_0 = tri_cell; + vertex_1 = tri_cell + float2(1.0f, 0.0f); + vertex_2 = tri_cell + float2(0.0f, 1.0f); + baryc = float3(1.0f - (tri_frac.x + tri_frac.y), tri_frac.x, tri_frac.y); + } else { + vertex_0 = tri_cell + 1.0f; + vertex_1 = tri_cell + float2(0.0f, 1.0f); + vertex_2 = tri_cell + float2(1.0f, 0.0f); + baryc = float3(tri_frac.x + tri_frac.y - 1.0f, 1.0f - tri_frac.x, 1.0f - tri_frac.y); + } + + float input_scale = _Burley_Tiling_Input_Scale; + _burley_ctx.weights = burley_apply_blend_gamma(baryc, _Burley_Tiling_Blend_Gamma); + float2 uv_dx = ddx(uv); + float2 uv_dy = ddy(uv); + _burley_ctx.patch_0 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_0, input_scale); + _burley_ctx.patch_1 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_1, input_scale); + _burley_ctx.patch_2 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_2, input_scale); +} +#endif // _BURLEY_TILING + +#if defined(_BURLEY_TILING_HEIGHTMAP) || defined(_BURLEY_TILING_AMBIENT_OCCLUSION) +float burley_sample_scalar(texture2D tex, texture2D lut) { + float4 patch_0 = burley_sample_patch(tex, _burley_ctx.patch_0); + float4 patch_1 = burley_sample_patch(tex, _burley_ctx.patch_1); + float4 patch_2 = burley_sample_patch(tex, _burley_ctx.patch_2); + float4 gaussian_blend = patch_0 * _burley_ctx.weights.x + + patch_1 * _burley_ctx.weights.y + + patch_2 * _burley_ctx.weights.z; + return burley_degaussianize( + lut, + burley_apply_soft_clipping(gaussian_blend.rgb, _burley_ctx.weights), + false).r; +} +#endif // _BURLEY_TILING_HEIGHTMAP || _BURLEY_TILING_AMBIENT_OCCLUSION + +#endif // __BURLEY_INC diff --git a/features.cginc b/features.cginc index 312af41..1d3d1d1 100755 --- a/features.cginc +++ b/features.cginc @@ -242,6 +242,7 @@ //ifex _Burley_Tiling_Enabled==0 #pragma shader_feature_local _BURLEY_TILING +#pragma shader_feature_local _BURLEY_TILING_AMBIENT_OCCLUSION #pragma shader_feature_local _BURLEY_TILING_HEIGHTMAP #pragma shader_feature_local _BURLEY_TILING_SMOOTHNESS #pragma shader_feature_local _BURLEY_TILING_SMOOTHNESS_INVERT diff --git a/globals.cginc b/globals.cginc index a475083..cd676d1 100755 --- a/globals.cginc +++ b/globals.cginc @@ -630,6 +630,11 @@ texture2D _Burley_Tiling_Maintex; texture2D _Burley_Tiling_Maintex_LUT; #endif // _BURLEY_TILING +#if defined(_BURLEY_TILING_AMBIENT_OCCLUSION) +texture2D _Burley_Tiling_Ambient_Occlusion_Map; +texture2D _Burley_Tiling_Ambient_Occlusion_Map_LUT; +#endif // _BURLEY_TILING_AMBIENT_OCCLUSION + #if defined(_BURLEY_TILING_SMOOTHNESS) texture2D _Burley_Tiling_Smoothness_Map; texture2D _Burley_Tiling_Smoothness_Map_LUT; diff --git a/lighting.cginc b/lighting.cginc index c1073d1..f4d210c 100755 --- a/lighting.cginc +++ b/lighting.cginc @@ -7,11 +7,12 @@ #include "UnityLightingCommon.cginc" #include "UnityStandardCoreMinimal.cginc" +#include "burley.cginc" +#include "data.cginc" #include "features.cginc" #include "filamented.cginc" #include "interpolators.cginc" #include "LightVolumes.cginc" -#include "pbr.cginc" #include "glitter.cginc" #include "poi.cginc" @@ -178,7 +179,14 @@ float4 getIndirectDiffuse(v2f i, Pbr pbr, inout LightData light) { float getAO(v2f i) { float ao = 1; -#if defined(_AMBIENT_OCCLUSION) +#if defined(_BURLEY_TILING) && defined(_BURLEY_TILING_AMBIENT_OCCLUSION) + ao = saturate(lerp( + 1.0, + burley_sample_scalar( + _Burley_Tiling_Ambient_Occlusion_Map, + _Burley_Tiling_Ambient_Occlusion_Map_LUT), + _OcclusionStrength)); +#elif defined(_AMBIENT_OCCLUSION) ao = saturate(lerp(1.0, _OcclusionMap.Sample(bilinear_repeat_s, i.uv01.xy).r, _OcclusionStrength)); #endif return ao; @@ -211,12 +219,15 @@ float getSpecularAO(v2f i, Pbr pbr, LightData data, float3 reflect_dir) { void GetLighting(v2f i, Pbr pbr, out LightData data) { data = (LightData) 0; + data.common.ao = 1.0f; + data.common.spec_ao = 1.0f; float3 view_dir = normalize(i.eyeVec.xyz); data.common.V = -view_dir; data.common.N = pbr.normal; data.common.NoV = max(1e-4, dot(pbr.normal, data.common.V)); + data.common.ao = getAO(i); #if defined(_CLEARCOAT) data.common.NoV_cc = max(1e-4, dot(pbr.cc_normal, data.common.V)); #endif @@ -274,7 +285,6 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { pbr.normal, data.common.V, data.direct.H, glitter_indirect_dir); #endif - data.common.ao = getAO(i); data.common.spec_ao = getSpecularAO(i, pbr, data, reflect_dir); #if defined(_CLEARCOAT) @@ -3,162 +3,13 @@ #include "data.cginc" #include "decal.cginc" +#include "burley.cginc" #include "filamented.cginc" #include "instancing.cginc" #include "interpolators.cginc" #include "letter_grid.cginc" #include "texture_utils.cginc" -#if defined(_BURLEY_TILING) -float2 burley_tri_to_cart(float2 tri_coord) { - return float2( - tri_coord.x + tri_coord.y * 0.5f, - tri_coord.y * SQRT_3_OVER_2); -} - -float3 burley_apply_blend_gamma(float3 weights, float gamma) { - weights = pow(weights, gamma); - return weights / (weights.x + weights.y + weights.z); -} - -// Equation 4 (first half). -float3 burley_soft_clipping_lower_half(float3 x_hat, float w_hat) { - float linear_start = 0.25f * (2.0f - w_hat); - float3 linear_value = (x_hat - 0.5f) / w_hat + 0.5f; - float3 linear_mask = step(float3(linear_start, linear_start, linear_start), x_hat); - - if (w_hat >= TWO_OVER_THREE) { - float3 t = x_hat / (2.0f - w_hat); - float3 quadratic = 8.0f * (1.0f / w_hat - 1.0f) * t * t + (3.0f - 2.0f / w_hat) * t; - return lerp(quadratic, linear_value, linear_mask); - } - - float quadratic_start = 0.25f * (2.0f - 3.0f * w_hat); - float3 d = (x_hat - quadratic_start) / w_hat; - float3 quadratic = d * d; - float3 quadratic_mask = step(float3(quadratic_start, quadratic_start, quadratic_start), x_hat); - float3 result = quadratic * quadratic_mask; - return lerp(result, linear_value, linear_mask); -} - -// Equation 4. -float3 burley_soft_clipping_contrast(float3 x_hat, float w_hat) { - float3 upper_mask = step(0.5f, x_hat); - float3 lower_x = min(x_hat, 1.0f - x_hat); - float3 lower_y = burley_soft_clipping_lower_half(lower_x, w_hat); - return lerp(lower_y, 1.0f - lower_y, upper_mask); -} - -float3 burley_apply_soft_clipping(float3 gaussian_color, float3 weights) { - float w_hat = sqrt(dot(weights, weights)); - return burley_soft_clipping_contrast(gaussian_color, w_hat); -} - -float3 burley_degaussianize(texture2D lut, float3 gaussian_color, bool decode_srgb = true) { - float2 uv_r = float2(gaussian_color.r, 0.5f); - float2 uv_g = float2(gaussian_color.g, 0.5f); - float2 uv_b = float2(gaussian_color.b, 0.5f); - float lut_r = lut.Sample(linear_clamp_s, uv_r).r; - float lut_g = lut.Sample(linear_clamp_s, uv_g).g; - float lut_b = lut.Sample(linear_clamp_s, uv_b).b; - float3 restored = float3(lut_r, lut_g, lut_b); - return decode_srgb ? srgb_to_linear(restored) : restored; -} - -struct BurleyPatchTransform { - float2 uv; - float2 dx; - float2 dy; - float2x2 uv_to_patch; -}; - -BurleyPatchTransform burley_make_patch_transform(float2 uv, float2 uv_dx, float2 uv_dy, - float2 tri_vertex, float input_scale) { - float3 cube_id = float3(tri_vertex.x, tri_vertex.y, -tri_vertex.x - tri_vertex.y); - float3 tile_rand3 = hash33_fast(cube_id); - float2 vertex_uv = burley_tri_to_cart(tri_vertex); - // Map the unit-radius hex support to the unit square so arbitrary rotation - // stays within bounds. - float2 local_uv = (uv - vertex_uv) * 0.5f; - // Apply input scaling. - local_uv *= input_scale; - float2 sample_dx = uv_dx * (0.5f * input_scale); - float2 sample_dy = uv_dy * (0.5f * input_scale); - // Rotate. - float theta = hash31_ff(tile_rand3) * TAU; - float2x2 rot = float2x2(cos(theta), -sin(theta), sin(theta), cos(theta)); - local_uv = mul(rot, local_uv); - sample_dx = mul(rot, sample_dx); - sample_dy = mul(rot, sample_dy); - // Apply randomized offset, staying within bounds. - // The scaled-and-rotated footprint is bounded by [-Input_Scale / 2, Input_Scale / 2], - // so we can offset by [(1 - Input_Scale) / 2]. - float2 random_offset = (tile_rand3.yz * 2.0f - 1.0f) * (0.5f * (1.0f - input_scale)); - local_uv += random_offset; - // Finally, remap onto [0, 1]. - local_uv += 0.5f; - - BurleyPatchTransform patch; - patch.uv = local_uv; - patch.dx = sample_dx; - patch.dy = sample_dy; - patch.uv_to_patch = rot * (0.5f * input_scale); - return patch; -} - -float4 burley_sample_patch(texture2D tex, BurleyPatchTransform patch) { - return tex.SampleGrad( - aniso4_trilinear_repeat_s, patch.uv, patch.dx, patch.dy); -} - -struct BurleyTilingContext { - BurleyPatchTransform patch_0; - BurleyPatchTransform patch_1; - BurleyPatchTransform patch_2; - float3 weights; - float2 base_uv; - float uv_scale; -}; - -static BurleyTilingContext _burley_ctx; - -void burley_tiling_setup(float2 base_uv) { - _burley_ctx.base_uv = base_uv; - float2 uv = base_uv - 0.5; - // Scale so that any rotation remains within [0, 1] bounds. - uv *= TWO_OVER_SQRT_3; - uv /= _Burley_Tiling_Output_Scale; - _burley_ctx.uv_scale = TWO_OVER_SQRT_3 / _Burley_Tiling_Output_Scale; - float3 hex_coord = cart_to_hex(uv); - float2 tri_coord = hex_coord.yz; - float2 tri_cell = floor(tri_coord); - float2 tri_frac = tri_coord - tri_cell; - float2 vertex_0; - float2 vertex_1; - float2 vertex_2; - float3 baryc; - if (tri_frac.x + tri_frac.y < 1.0f) { - vertex_0 = tri_cell; - vertex_1 = tri_cell + float2(1.0f, 0.0f); - vertex_2 = tri_cell + float2(0.0f, 1.0f); - baryc = float3(1.0f - (tri_frac.x + tri_frac.y), tri_frac.x, tri_frac.y); - } else { - vertex_0 = tri_cell + 1.0f; - vertex_1 = tri_cell + float2(0.0f, 1.0f); - vertex_2 = tri_cell + float2(1.0f, 0.0f); - baryc = float3(tri_frac.x + tri_frac.y - 1.0f, 1.0f - tri_frac.x, 1.0f - tri_frac.y); - } - - float input_scale = _Burley_Tiling_Input_Scale; - _burley_ctx.weights = burley_apply_blend_gamma(baryc, _Burley_Tiling_Blend_Gamma); - float2 uv_dx = ddx(uv); - float2 uv_dy = ddy(uv); - _burley_ctx.patch_0 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_0, input_scale); - _burley_ctx.patch_1 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_1, input_scale); - _burley_ctx.patch_2 = burley_make_patch_transform(uv, uv_dx, uv_dy, vertex_2, input_scale); -} -#endif // _BURLEY_TILING - #if defined(_PARALLAX_HEIGHTMAP_TEXTURE) || defined(_BURLEY_TILING_HEIGHTMAP) float heightmap_sample(float2 uv) { #if defined(_BURLEY_TILING_HEIGHTMAP) @@ -173,8 +24,10 @@ float heightmap_sample(float2 uv) { _burley_ctx.patch_2.uv + mul(_burley_ctx.patch_2.uv_to_patch, delta), _burley_ctx.patch_2.dx, _burley_ctx.patch_2.dy); float4 blend = s0 * _burley_ctx.weights.x + s1 * _burley_ctx.weights.y + s2 * _burley_ctx.weights.z; - return burley_degaussianize(_Burley_Tiling_Heightmap_LUT, - burley_apply_soft_clipping(blend.rgb, _burley_ctx.weights), false).r; + return burley_degaussianize( + _Burley_Tiling_Heightmap_LUT, + burley_apply_soft_clipping(blend.rgb, _burley_ctx.weights), + false).r; #elif defined(_PARALLAX_HEIGHTMAP_TEXTURE) return _Parallax_Heightmap.Sample(linear_repeat_s, uv * _Parallax_Heightmap_ST.xy + _Parallax_Heightmap_ST.zw).r; #endif |
