196 lines
6.6 KiB
HLSL

#ifndef BEAUTIFY_PPSSF_FX
#define BEAUTIFY_PPSSF_FX
// Copyright 2020-2021 Kronnect - All Rights Reserved.
#include "BeautifyCommon.hlsl"
TEXTURE2D_X(_MainTex);
TEXTURE2D(_FlareTex);
TEXTURE2D(_OcclusionTex);
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
float4 _SunPos;
float3 _SunDir;
float4 _SunData; // x = sunIntensity, y = disk size, z = ray difraction, w = ray difraction amount
float4 _SunCoronaRays1; // x = length, y = streaks, z = spread, w = angle offset
float4 _SunCoronaRays2; // x = length, y = streaks, z = spread, w = angle offset
float4 _SunGhosts1; // x = reserved, y = size, 2 = pos offset, 3 = brightness
float4 _SunGhosts2; // x = reserved, y = size, 2 = pos offset, 3 = brightness
float4 _SunGhosts3; // x = reserved, y = size, 2 = pos offset, 3 = brightness
float4 _SunGhosts4; // x = reserved, y = size, 2 = pos offset, 3 = brightness
float3 _SunHalo; // x = offset, y = amplitude, z = intensity
float4 _SunTint;
float _SunFlaresAspectRatio;
float _SunOcclusionThreshold;
#define SUN_TINT_COLOR _SunTint.rgb
#define OCCLUSION_SPEED _SunTint.a
#define OCCLUSION_THRESHOLD _SunOcclusionThreshold
struct VaryingsSF {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float2 sunPos : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
VaryingsSF VertSF(AttributesSimple input) {
VaryingsSF output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = input.positionOS;
output.positionCS.y *= _ProjectionParams.x * _FlipY;
output.uv = input.uv.xy;
float4 clipPos = TransformWorldToHClip(_WorldSpaceCameraPos.xyz - _SunDir.xyz * 1000.0);
float2 sunPos = float2(clipPos.x, clipPos.y * _ProjectionParams.x) * 0.5 / clipPos.w + 0.5;
output.sunPos = sunPos;
return output;
}
void rotate(inout float2 uv, float ang) {
float2 sico;
sincos(ang, sico.x, sico.y);
float2 cosi = float2(sico.y, -sico.x);
uv = float2(dot(cosi, uv), dot(sico, uv));
}
float3 sunflare(VaryingsSF input) {
// general params
float2 uv = input.uv;
float2 sunPos = input.sunPos;
#if BEAUTIFY_SF_OCCLUSION_SIMPLE
float depth = BEAUTIFY_GET_SCENE_DEPTH_01(sunPos);
if (depth < 1.0) return 0;
const float occlusion = 1.0;
#elif BEAUTIFY_SF_OCCLUSION_SMOOTH
float occlusion = SAMPLE_TEXTURE2D(_OcclusionTex, sampler_LinearRepeat, float2(0,0)).r;
if (occlusion <= 0.02) return 0.0.xxx;
#else
const float occlusion = 1.0;
#endif
float2 grd = uv - sunPos;
float aspectRatio = _SunFlaresAspectRatio;
grd.y *= aspectRatio;
float len = length(grd);
// sun disk
float s0 = pow( 1.0 + saturate(_SunData.y - len), 75) - 1.0;
// corona rays
float gang = _SunPos.w; //atan2(0.5 - sunPos.y, sunPos.x - 0.5);
float ang = atan2(grd.y, grd.x) + gang;
float ray1 = _SunCoronaRays1.z + abs(_SunCoronaRays1.x * cos(_SunCoronaRays1.w + ang * _SunCoronaRays1.y)); // design
ray1 *= pow( 1.0 + len, 1.0/_SunCoronaRays1.x);
s0 += 1.0 / ray1;
float ray2 = _SunCoronaRays2.z + abs(_SunCoronaRays2.x * sin(_SunCoronaRays2.w + ang * _SunCoronaRays2.y)); // design
ray2 *= pow( 1.0 + len, 1.0/_SunCoronaRays2.x);
s0 += 1.0 / ray2;
s0 *= _SunData.x;
float3 flare = s0.xxx;
#if BEAUTIFY_SF_USE_GHOSTS // defined(UNITY_SINGLE_PASS_STEREO) && !defined(UNITY_STEREO_INSTANCING_ENABLED) && !defined(UNITY_STEREO_MULTIVIEW_ENABLED)
// ghosts circular (not compatible with XR due to how projection works)
float2 ghost1Pos = 1.0 - sunPos;
grd = uv - ghost1Pos + (ghost1Pos - 0.5) * _SunGhosts1.z;
grd.y *= aspectRatio;
float g0 = saturate(_SunGhosts1.y / length(grd));
g0 = pow(g0, 12);
flare += g0 * _SunGhosts1.w / len;
float2 ghost2Pos = 1.0 - sunPos;
grd = uv - ghost2Pos + (ghost2Pos - 0.5) * _SunGhosts2.z;
grd.y *= aspectRatio;
g0 = saturate(_SunGhosts2.y / length(grd));
g0 = pow(g0, 12);
flare += g0 * _SunGhosts2.w / len;
float2 ghost3Pos = 1.0 - sunPos;
grd = uv - ghost3Pos + (ghost3Pos - 0.5) * _SunGhosts3.z;
grd.y *= aspectRatio;
g0 = saturate(_SunGhosts3.y / length(grd));
g0 = pow(g0, 12);
flare += g0 * _SunGhosts3.w / len;
float2 ghost4Pos = 1.0 - sunPos;
grd = uv - ghost4Pos + (ghost4Pos - 0.5) * _SunGhosts4.z;
grd.y *= aspectRatio;
g0 = saturate(_SunGhosts4.y / length(grd));
g0 = pow(g0, 12);
flare += g0 * _SunGhosts4.w / len;
#endif
// light rays
float2 uv2 = uv - sunPos;
float clen = length(uv2);
rotate(uv2, gang);
uv2.x *= aspectRatio;
uv2.x *= 0.1;
uv2 /= len;
float lr = saturate(SAMPLE_TEXTURE2D(_FlareTex, sampler_LinearRepeat, uv2 + _SunPos.zz).r - _SunData.w);
float3 rays = lr * sin(float3(len, len + 0.1, len + 0.2) * 3.1415927);
float atten = pow(1.0 + clen, 13.0);
rays *= _SunData.z / atten;
flare += rays;
// halo
float hlen = clamp( (len - _SunHalo.x) * _SunHalo.y, 0, 3.1415927);
float3 halo = pow(sin(float3(hlen, hlen + 0.1, hlen + 0.2)), 12.0.xxx);
halo *= _SunHalo.z / atten;
flare += halo;
return max(0, flare * SUN_TINT_COLOR * occlusion);
}
float4 FragSF (VaryingsSF i) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
//i.uv = UnityStereoTransformScreenSpaceTex(i.uv);
return float4(sunflare(i), 1.0);
}
float4 FragSFAdditive (VaryingsSF i) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 stereoUV = UnityStereoTransformScreenSpaceTex(i.uv);
float4 p = SAMPLE_TEXTURE2D_X(_MainTex, sampler_LinearClamp, stereoUV);
return p + float4(sunflare(i), 1.0);
}
float GetDepth(float2 sunPos, float2 offset) {
float2 pos = saturate(sunPos + offset * _MainTex_TexelSize.xy);
return BEAUTIFY_GET_SCENE_DEPTH_01(pos);
}
float OcclusionTest(float2 sunPos) {
float depth1 = GetDepth(sunPos, float2(-1, -1));
float depth2 = GetDepth(sunPos, float2( 1, 1));
float depth3 = GetDepth(sunPos, float2( 3, 3));
float depth4 = GetDepth(sunPos, float2(-3, -3));
float occlusion = (depth1 + depth2 + depth3 + depth4) * 0.25;
occlusion *= step(OCCLUSION_THRESHOLD, occlusion);
return occlusion;
}
float4 FragSFOcclusion (VaryingsSF input) : SV_Target {
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float occlusion = OcclusionTest(input.sunPos);
#if BEAUTIFY_SF_OCCLUSION_INIT
return float4(occlusion, occlusion, occlusion, 1.0);
#else
return float4(occlusion, occlusion, occlusion, unity_DeltaTime.x * OCCLUSION_SPEED);
#endif
}
#endif