升级6.4.升级水,升级天气

This commit is contained in:
2026-04-05 00:26:54 +08:00
parent 63bc9b5536
commit 5f7cbfb713
635 changed files with 34718 additions and 22567 deletions

View File

@@ -8,6 +8,36 @@
m_UtilityNameSpace
// NOTE: We have to roll our own bilinear filter in Compute shaders when
// reading from a RWTexture. The documentation below explains how SRV
// and UAV mappings of the same texture cannot exist at the same time.
// https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/sm5-object-rwtexture2d
float4 SampleBilinear(const RWTexture2DArray<float4> i_Texture, const float2 i_UV, const uint i_Slice, const float i_Resolution)
{
// Make relative to pixel centers.
const float2 center = i_UV * i_Resolution - 0.5;
// Compute integral (bottom left) and fractional parts
// Prevent overflow from possible negative cast to unsigned.
const uint maximum = (uint)i_Resolution - 1;
const uint2 integral = max((float2)0.0, floor(center));
const uint2 opposite = uint2(min(integral.x + 1, maximum), min(integral.y + 1, maximum));
const float2 fractional = frac(center);
// Clamp from below and above (desired?).
const float4 bl = i_Texture[uint3(integral, i_Slice)];
const float4 br = i_Texture[uint3(uint2(opposite.x, integral.y), i_Slice)];
const float4 tl = i_Texture[uint3(uint2(integral.x, opposite.y), i_Slice)];
const float4 tr = i_Texture[uint3(opposite, i_Slice)];
return lerp
(
lerp(bl, br, fractional.x),
lerp(tl, tr, fractional.x),
fractional.y
);
}
// Taken from:
// https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1
//
@@ -66,6 +96,67 @@ float4 SampleTextureCatmullRom(in Texture2D<float4> tex, in SamplerState linearS
return result;
}
float4 CubicWeights(const float f)
{
const float f2 = f * f;
const float f3 = f2 * f;
// CatmullRom (a = -0.5)
return float4
(
-0.5 * f3 + f2 - 0.5 * f,
1.5 * f3 - 2.5 * f2 + 1.0,
-1.5 * f3 + 2.0 * f2 + 0.5 * f,
0.5 * f3 - 0.5 * f2
);
}
float4 SampleBicubicRepeat
(
const Texture2DArray<float4> i_Texture,
const float2 i_UV,
const uint2 i_Size,
const uint i_Slice
)
{
// Convert to texel space (centered at pixel centers).
const float2 samplePosition = i_UV * (float2)i_Size - 0.5;
const int2 texelPosition = (int2)floor(samplePosition);
const float2 f = samplePosition - (float2)texelPosition;
// Precompute weights.
const float4 wx = CubicWeights(f.x);
const float4 wy = CubicWeights(f.y);
const uint2 size = i_Size - 1;
const uint4 x = uint4
(
(texelPosition.x - 1) & size.x,
(texelPosition.x + 0) & size.x,
(texelPosition.x + 1) & size.x,
(texelPosition.x + 2) & size.x
);
// Horizontal pass.
float4 row[4];
[unroll]
for (int j = -1; j <= 2; ++j)
{
const int y = (texelPosition.y + j) & size.y;
const float4 t0 = i_Texture[uint3(x.x, y, i_Slice)];
const float4 t1 = i_Texture[uint3(x.y, y, i_Slice)];
const float4 t2 = i_Texture[uint3(x.z, y, i_Slice)];
const float4 t3 = i_Texture[uint3(x.w, y, i_Slice)];
row[j + 1] = t0 * wx.x + t1 * wx.y + t2 * wx.z + t3 * wx.w;
}
// Vertical pass.
return row[0] * wy.x + row[1] * wy.y + row[2] * wy.z + row[3] * wy.w;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Filtering

View File

@@ -43,6 +43,16 @@ float2 WorldNormalToScreenDirection(const float3 i_PositionWS, const float3 i_No
return direction;
}
float3 SafeComputeWorldSpacePosition(float2 positionNDC, float deviceDepth, float4x4 invViewProjMatrix)
{
float4 positionCS = ComputeClipSpacePosition(positionNDC, deviceDepth);
float4 hpositionWS = mul(invViewProjMatrix, positionCS);
// w is sometimes zero when using oblique projection.
// Zero is better than NaN.
return hpositionWS.w > 0.0 ? hpositionWS.xyz / hpositionWS.w : 0.0;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Helpers

View File

@@ -26,6 +26,15 @@
#define SHADERPASS_MOTION_VECTORS (22)
//
// Motion Vector Pass Fix
//
#if SHADERPASS == SHADERPASS_MOTION_VECTORS
#undef VARYINGS_NEED_NORMAL_WS
#endif
//
// Deferred Fix
//
@@ -86,6 +95,9 @@
// Transparent Objects Receives Shadows
//
// WebGPU does not like the binding.
#ifndef SHADER_API_WEBGPU
#if _SURFACE_TYPE_TRANSPARENT
#if _TRANSPARENT_RECEIVES_SHADOWS
#if SHADERPASS == SHADERPASS_FORWARD || SHADERPASS == SHADERPASS_FORWARD_ADD
@@ -108,4 +120,6 @@ float4 _ShadowMapTexture_TexelSize;
#endif
#endif
#endif // SHADER_API_WEBGPU
#endif // d_WaveHarmonic_Utility_ShaderGraphDefines

View File

@@ -21,39 +21,155 @@
#define CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
#endif // FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
#if UNITY_VERSION >= 60000000
#if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON)
#if _ALPHATEST_ON
#if !USE_CLUSTER_LIGHT_LOOP
// If not clustered and additional light shadows and XR, the shading model
// completely breaks. It is like shadow attenuation is NaN or some obscure
// compiler issue. For 2022.3, it is broken for forward+ only, but cannot be fixed.
#define d_ShadowMaskBroken 1
#else
#if _RECEIVE_SHADOWS_OFF
// Right eye broken rendering similar to above.
#define d_AdditionalLightsBroken 1
#endif
#endif
#endif
#endif
#endif
#endif // CREST_URP
#if CREST_HDRP
#if CREST_HDRP_FORWARD_PASS
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#if UNITY_VERSION < 202310
#define GetMeshRenderingLayerMask GetMeshRenderingLightLayer
#endif // UNITY_VERSION
#if d_Crest_AdditionalLights
#if d_Crest_WaterSurface
// Causes rendering issues at a distance with foreground objects.
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#define LIGHTLOOP_DISABLE_TILE_AND_CLUSTER 1
#define d_Crest_LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#endif // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
m_CrestNameSpace
// Adapted from: com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl
half3 GetPunctualLights(float3 i_PositionWS, float2 i_PositionSS, const float4 i_ScreenPosition, const half3 i_Normal)
{
half3 color = 0.0;
BuiltinData builtinData;
ZERO_INITIALIZE(BuiltinData, builtinData);
LightLoopContext context;
context.sampleReflection = 0;
context.shadowContext = InitShadowContext();
context.contactShadow = 0;
context.contactShadowFade = 0.0;
context.shadowValue = 1;
#if UNITY_VERSION < 60000000
context.splineVisibility = -1;
#endif
#ifdef APPLY_FOG_ON_SKY_REFLECTIONS
context.positionWS = i_PositionWS;
#endif
float3 positionWS = GetCameraRelativePositionWS(i_PositionWS);
ApplyCameraRelativeXR(positionWS);
PositionInputs posInput;
ZERO_INITIALIZE(PositionInputs, posInput);
posInput.tileCoord = uint2(i_PositionSS) / GetTileSize();
posInput.positionWS = positionWS;
posInput.positionSS = i_PositionSS;
posInput.positionNDC = i_ScreenPosition.xy / i_ScreenPosition.w;
const uint renderingLayers = GetMeshRenderingLayerMask();
uint lightCount, lightStart;
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, lightStart, lightCount);
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
lightCount = _PunctualLightCount;
lightStart = 0;
#endif
bool fastPath = false;
#if SCALARIZE_LIGHT_LOOP
uint lightStartLane0;
fastPath = IsFastPath(lightStart, lightStartLane0);
if (fastPath)
{
lightStart = lightStartLane0;
}
#endif
// Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed.
// For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register),
// v_ are variables that might have different value for each thread in the wave (meant for vector registers).
// This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent.
// Note that the above is valid only if wave intriniscs are supported.
uint v_lightListOffset = 0;
uint v_lightIdx = lightStart;
#if NEED_TO_CHECK_HELPER_LANE
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
// sure it will not happen.
bool isHelperLane = WaveIsHelperLane();
while (!isHelperLane && v_lightListOffset < lightCount)
#else
while (v_lightListOffset < lightCount)
#endif
{
v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
#if SCALARIZE_LIGHT_LOOP
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
#else
uint s_lightIdx = v_lightIdx;
#endif
if (s_lightIdx == -1)
{
break;
}
LightData s_light = FetchLight(s_lightIdx);
// If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
// end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
if (s_lightIdx >= v_lightIdx)
{
v_lightListOffset++;
if (IsMatchingLightLayer(s_light.lightLayers, renderingLayers))
{
float3 L; float4 distances; // {d, d^2, 1/d, d_proj}
GetPunctualLightVectors(positionWS, s_light, L, distances);
// Is it worth evaluating the light?
if (s_light.lightDimmer > 0)
{
float4 lightColor = EvaluateLight_Punctual(context, posInput, s_light, L, distances);
lightColor.rgb *= lightColor.a * max(k_Crest_AdditionalLightLerp, dot(i_Normal, L)); // Composite
SHADOW_TYPE shadow = EvaluateShadow_Punctual(context, posInput, s_light, builtinData, i_Normal, L, distances);
lightColor.rgb *= ComputeShadowColor(shadow, s_light.shadowTint, s_light.penumbraTint);
color += lightColor.rgb;
}
}
}
}
return color;
}
m_CrestNameSpaceEnd
#ifdef d_Crest_LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#undef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
#endif
#endif // d_Crest_WaterSurface
#endif // d_Crest_AdditionalLights
#if UNITY_VERSION < 60000000
#if PROBE_VOLUMES_L1
// URP sets this to zero.
#define AMBIENT_PROBE_BUFFER 1
#endif // PROBE_VOLUMES_L1
#endif // UNITY_VERSION
#endif // CREST_HDRP
#endif // CREST_HDRP_FORWARD_PASS
m_CrestNameSpace
@@ -64,13 +180,19 @@ void PrimaryLight
out half3 o_Direction
)
{
#if CREST_HDRP
// We could get the main light the same way we get the main light shadows,
// but most of the data would be missing (including below horizon
// attenuation) which would require re-running the light loop which is expensive.
o_Direction = g_Crest_PrimaryLightDirection;
o_Color = g_Crest_PrimaryLightIntensity;
#elif CREST_URP
o_Direction = half3(0.0, 1.0, 0.0);
o_Color = 0.0;
#ifndef d_IsAdditionalLight
if (g_Crest_PrimaryLightFallback)
{
o_Direction = g_Crest_PrimaryLightDirection;
o_Color = g_Crest_PrimaryLightIntensity;
return;
}
#endif
#if CREST_URP
// Actual light data from the pipeline.
Light light = GetMainLight();
o_Direction = light.direction;
@@ -78,7 +200,10 @@ void PrimaryLight
#elif CREST_BIRP
#ifndef USING_DIRECTIONAL_LIGHT
// Yes. This function wants the world position of the surface.
o_Direction = normalize(UnityWorldSpaceLightDir(i_PositionWS));
o_Direction = UnityWorldSpaceLightDir(i_PositionWS);
// Prevents divide by zero.
if (all(o_Direction == 0)) o_Direction = half3(0.0, 1.0, 0.0);
o_Direction = normalize(o_Direction);
#else
o_Direction = _WorldSpaceLightPos0.xyz;
// Prevents divide by zero.
@@ -100,7 +225,7 @@ half3 AmbientLight(const half3 i_AmbientLight)
half3 ambient = i_AmbientLight;
#ifndef SHADERGRAPH_PREVIEW
#if CREST_HDRP
#if CREST_HDRP_FORWARD_PASS
// Allows control of baked lighting through volume framework.
// We could create a BuiltinData struct which would have rendering layers on it, but it seems more complicated.
ambient *= GetIndirectDiffuseMultiplier(GetMeshRenderingLayerMask());
@@ -123,7 +248,9 @@ half3 AmbientLight()
return AmbientLight(ambient);
}
half3 AdditionalLighting(const float3 i_PositionWS, const float4 i_ScreenPosition, const float2 i_StaticLightMapUV)
#if d_Crest_AdditionalLights
#if d_Crest_WaterSurface
half3 AdditionalLighting(const float3 i_PositionWS, const float4 i_ScreenPosition, const float2 i_StaticLightMapUV, const float2 i_PositionSS, const half3 i_Normal)
{
half3 color = 0.0;
@@ -153,19 +280,11 @@ LIGHT_LOOP_BEGIN(pixelLightCount)
// Includes shadows and cookies.
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#if d_ShadowMaskBroken
light.shadowAttenuation = 1.0;
#endif
#if d_AdditionalLightsBroken
light.color = 0.0;
#endif
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
color += light.color * (light.distanceAttenuation * light.shadowAttenuation);
color += light.color * max(k_Crest_AdditionalLightLerp, dot(i_Normal, light.direction)) * (light.distanceAttenuation * light.shadowAttenuation);
}
LIGHT_LOOP_END
@@ -188,11 +307,16 @@ LIGHT_LOOP_END
#endif // _ADDITIONAL_LIGHTS
#endif // CREST_URP
// HDRP todo.
#if CREST_HDRP_FORWARD_PASS
color = GetPunctualLights(i_PositionWS, i_PositionSS, i_ScreenPosition, i_Normal);
#endif
// BIRP has additional lights as additional passes. Handled elsewhere.
return color;
}
#endif // d_Crest_WaterSurface
#endif // d_Crest_AdditionalLights
m_CrestNameSpaceEnd

View File

@@ -0,0 +1,67 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Adapted from:
// https://pastebin.com/sDrnzYxB
// License:
// CC0 Creative Commons License
// "Yes by all means use it how you wish. I'm sharing it as CC0."
// https://www.reddit.com/r/Unity3D/comments/dhr5g2/comment/f3rz6rc/
#ifndef d_WaveHarmonic_Utility_Stochastic
#define d_WaveHarmonic_Utility_Stochastic
m_UtilityNameSpace
float2 Hash2D2D(const float2 s)
{
// Magic numbers.
return frac(sin(fmod(float2(dot(s, float2(127.1, 311.7)), dot(s, float2(269.5, 183.3))), PI)) * 43758.5453);
}
float4 SampleStochastic(const Texture2D i_Texture, const SamplerState i_Sampler, const float2 i_UV)
{
// UV transformed into triangular grid space with UV scaled by approximation of 2 * sqrt(3)
const float2 skewUV = mul(float2x2(1.0, 0.0, -0.57735027, 1.15470054), i_UV * 3.464);
// Vertex IDs and barycentric coords
const float2 id = float2(floor(skewUV));
float3 barry = float3(frac(skewUV), 0.0);
barry.z = 1.0 - barry.x - barry.y;
// Triangle vertices and blend weights.
// BW_vx[0...2].xyz = triangle verts
// BW_vx[3].xy = blend weights (z is unused)
const float4x3 BW_vx =
(
(barry.z > 0)
? float4x3
(
float3(id, 0),
float3(id + float2(0, 1), 0),
float3(id + float2(1, 0), 0),
barry.zyx
)
: float4x3
(
float3(id + float2(1, 1), 0),
float3(id + float2(1, 0), 0),
float3(id + float2(0, 1), 0),
float3(-barry.z, 1.0 - barry.y, 1.0 - barry.x)
)
);
// Calculate derivatives to avoid triangular grid artifacts.
const float2 dx = ddx(i_UV);
const float2 dy = ddy(i_UV);
// Blend samples with calculated weights.
return SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[0].xy), dx, dy) * BW_vx[3].x +
SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[1].xy), dx, dy) * BW_vx[3].y +
SAMPLE_TEXTURE2D_GRAD(i_Texture, i_Sampler, i_UV + Hash2D2D(BW_vx[2].xy), dx, dy) * BW_vx[3].z;
}
m_UtilityNameSpaceEnd
#endif // d_WaveHarmonic_Utility_Stochastic

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 90b04c86b94da4f6890d04a7b7fa5226
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: