Unity_1lab/1 laba/Assets/furniture/BK_AlchemistHouse/Resources/Shaders/VolumetricLight.shader
lapich_valya ba035efa87 models
добавила модели, текстуры стен, пола
2025-09-18 12:50:59 +03:00

650 lines
19 KiB
GLSL

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'unity_World2Shadow' with 'unity_WorldToShadow'
// Copyright(c) 2016, Michal Skalsky
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Shader "Sandbox/VolumetricLight"
{
Properties
{
[HideInInspector]_MainTex ("Texture", 2D) = "white" {}
[HideInInspector]_ZTest ("ZTest", Float) = 0
[HideInInspector]_LightColor("_LightColor", Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
CGINCLUDE
#if defined(SHADOWS_DEPTH) || defined(SHADOWS_CUBE)
#define SHADOWS_NATIVE
#endif
#include "UnityCG.cginc"
#include "UnityDeferredLibrary.cginc"
sampler3D _NoiseTexture;
sampler2D _DitherTexture;
float4 _FrustumCorners[4];
struct appdata
{
float4 vertex : POSITION;
};
float4x4 _WorldViewProj;
float4x4 _MyLightMatrix0;
float4x4 _MyWorld2Shadow;
float3 _CameraForward;
// x: scattering coef, y: extinction coef, z: range w: skybox extinction coef
float4 _VolumetricLight;
// x: 1 - g^2, y: 1 + g^2, z: 2*g, w: 1/4pi
float4 _MieG;
// x: scale, y: intensity, z: intensity offset
float4 _NoiseData;
// x: x velocity, y: z velocity
float4 _NoiseVelocity;
// x: ground level, y: height scale, z: unused, w: unused
float4 _HeightFog;
//float4 _LightDir;
float _MaxRayLength;
int _SampleCount;
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 wpos : TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
o.pos = mul(_WorldViewProj, v.vertex);
o.uv = ComputeScreenPos(o.pos);
o.wpos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
//-----------------------------------------------------------------------------------------
// GetCascadeWeights_SplitSpheres
//-----------------------------------------------------------------------------------------
inline fixed4 GetCascadeWeights_SplitSpheres(float3 wpos)
{
float3 fromCenter0 = wpos.xyz - unity_ShadowSplitSpheres[0].xyz;
float3 fromCenter1 = wpos.xyz - unity_ShadowSplitSpheres[1].xyz;
float3 fromCenter2 = wpos.xyz - unity_ShadowSplitSpheres[2].xyz;
float3 fromCenter3 = wpos.xyz - unity_ShadowSplitSpheres[3].xyz;
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
fixed4 weights = float4(distances2 < unity_ShadowSplitSqRadii);
weights.yzw = saturate(weights.yzw - weights.xyz);
return weights;
}
//-----------------------------------------------------------------------------------------
// GetCascadeShadowCoord
//-----------------------------------------------------------------------------------------
inline float4 GetCascadeShadowCoord(float4 wpos, fixed4 cascadeWeights)
{
float3 sc0 = mul(unity_WorldToShadow[0], wpos).xyz;
float3 sc1 = mul(unity_WorldToShadow[1], wpos).xyz;
float3 sc2 = mul(unity_WorldToShadow[2], wpos).xyz;
float3 sc3 = mul(unity_WorldToShadow[3], wpos).xyz;
float4 shadowMapCoordinate = float4(sc0 * cascadeWeights[0] + sc1 * cascadeWeights[1] + sc2 * cascadeWeights[2] + sc3 * cascadeWeights[3], 1);
#if defined(UNITY_REVERSED_Z)
float noCascadeWeights = 1 - dot(cascadeWeights, float4(1, 1, 1, 1));
shadowMapCoordinate.z += noCascadeWeights;
#endif
return shadowMapCoordinate;
}
UNITY_DECLARE_SHADOWMAP(_CascadeShadowMapTexture);
//-----------------------------------------------------------------------------------------
// GetLightAttenuation
//-----------------------------------------------------------------------------------------
float GetLightAttenuation(float3 wpos)
{
float atten = 0;
#if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
atten = 1;
#if defined (SHADOWS_DEPTH)
// sample cascade shadow map
float4 cascadeWeights = GetCascadeWeights_SplitSpheres(wpos);
bool inside = dot(cascadeWeights, float4(1, 1, 1, 1)) < 4;
float4 samplePos = GetCascadeShadowCoord(float4(wpos, 1), cascadeWeights);
atten = inside ? UNITY_SAMPLE_SHADOW(_CascadeShadowMapTexture, samplePos.xyz) : 1.0f;
atten = _LightShadowData.r + atten * (1 - _LightShadowData.r);
//atten = inside ? tex2Dproj(_ShadowMapTexture, float4((samplePos).xyz, 1)).r : 1.0f;
#endif
#if defined (DIRECTIONAL_COOKIE)
// NOT IMPLEMENTED
#endif
#elif defined (SPOT)
float3 tolight = _LightPos.xyz - wpos;
half3 lightDir = normalize(tolight);
float4 uvCookie = mul(_MyLightMatrix0, float4(wpos, 1));
// negative bias because http://aras-p.info/blog/2010/01/07/screenspace-vs-mip-mapping/
atten = tex2Dbias(_LightTexture0, float4(uvCookie.xy / uvCookie.w, 0, -8)).w;
atten *= uvCookie.w < 0;
float att = dot(tolight, tolight) * _LightPos.w;
atten *= tex2D(_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL;
#if defined(SHADOWS_DEPTH)
float4 shadowCoord = mul(_MyWorld2Shadow, float4(wpos, 1));
atten *= saturate(UnitySampleShadowmap(shadowCoord));
#endif
#elif defined (POINT) || defined (POINT_COOKIE)
float3 tolight = wpos - _LightPos.xyz;
half3 lightDir = -normalize(tolight);
float att = dot(tolight, tolight) * _LightPos.w;
atten = tex2D(_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL;
atten *= UnityDeferredComputeShadow(tolight, 0, float2(0, 0));
#if defined (POINT_COOKIE)
atten *= texCUBEbias(_LightTexture0, float4(mul(_MyLightMatrix0, half4(wpos, 1)).xyz, -8)).w;
#endif //POINT_COOKIE
#endif
return atten;
}
//-----------------------------------------------------------------------------------------
// ApplyHeightFog
//-----------------------------------------------------------------------------------------
void ApplyHeightFog(float3 wpos, inout float density)
{
#ifdef HEIGHT_FOG
density *= exp(-(wpos.y + _HeightFog.x) * _HeightFog.y);
#endif
}
//-----------------------------------------------------------------------------------------
// GetDensity
//-----------------------------------------------------------------------------------------
float GetDensity(float3 wpos)
{
float density = 1;
#ifdef NOISE
float noise = tex3D(_NoiseTexture, frac(wpos * _NoiseData.x + float3(_Time.y * _NoiseVelocity.x, 0, _Time.y * _NoiseVelocity.y)));
noise = saturate(noise - _NoiseData.z) * _NoiseData.y;
density = saturate(noise);
#endif
ApplyHeightFog(wpos, density);
return density;
}
//-----------------------------------------------------------------------------------------
// MieScattering
//-----------------------------------------------------------------------------------------
float MieScattering(float cosAngle, float4 g)
{
return g.w * (g.x / (pow(g.y - g.z * cosAngle, 1.5)));
}
//-----------------------------------------------------------------------------------------
// RayMarch
//-----------------------------------------------------------------------------------------
float4 RayMarch(float2 screenPos, float3 rayStart, float3 rayDir, float rayLength)
{
#ifdef DITHER_4_4
float2 interleavedPos = (fmod(floor(screenPos.xy), 4.0));
float offset = tex2D(_DitherTexture, interleavedPos / 4.0 + float2(0.5 / 4.0, 0.5 / 4.0)).w;
#else
float2 interleavedPos = (fmod(floor(screenPos.xy), 8.0));
float offset = tex2D(_DitherTexture, interleavedPos / 8.0 + float2(0.5 / 8.0, 0.5 / 8.0)).w;
#endif
int stepCount = _SampleCount;
float stepSize = rayLength / stepCount;
float3 step = rayDir * stepSize;
float3 currentPosition = rayStart + step * offset;
float4 vlight = 0;
float cosAngle;
#if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
float extinction = 0;
cosAngle = dot(_LightDir.xyz, -rayDir);
#else
// we don't know about density between camera and light's volume, assume 0.5
float extinction = length(_WorldSpaceCameraPos - currentPosition) * _VolumetricLight.y * 0.5;
#endif
[loop]
for (int i = 0; i < stepCount; ++i)
{
float atten = GetLightAttenuation(currentPosition);
float density = GetDensity(currentPosition);
float scattering = _VolumetricLight.x * stepSize * density;
extinction += _VolumetricLight.y * stepSize * density;// +scattering;
float4 light = atten * scattering * exp(-extinction);
//#if PHASE_FUNCTOIN
#if !defined (DIRECTIONAL) && !defined (DIRECTIONAL_COOKIE)
// phase functino for spot and point lights
float3 tolight = normalize(currentPosition - _LightPos.xyz);
cosAngle = dot(tolight, -rayDir);
light *= MieScattering(cosAngle, _MieG);
#endif
//#endif
vlight += light;
currentPosition += step;
}
#if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
// apply phase function for dir light
vlight *= MieScattering(cosAngle, _MieG);
#endif
// apply light's color
vlight *= _LightColor;
vlight = max(0, vlight);
#if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) // use "proper" out-scattering/absorption for dir light
vlight.w = exp(-extinction);
#else
vlight.w = 0;
#endif
return vlight;
}
//-----------------------------------------------------------------------------------------
// RayConeIntersect
//-----------------------------------------------------------------------------------------
float2 RayConeIntersect(in float3 f3ConeApex, in float3 f3ConeAxis, in float fCosAngle, in float3 f3RayStart, in float3 f3RayDir)
{
float inf = 10000;
f3RayStart -= f3ConeApex;
float a = dot(f3RayDir, f3ConeAxis);
float b = dot(f3RayDir, f3RayDir);
float c = dot(f3RayStart, f3ConeAxis);
float d = dot(f3RayStart, f3RayDir);
float e = dot(f3RayStart, f3RayStart);
fCosAngle *= fCosAngle;
float A = a*a - b*fCosAngle;
float B = 2 * (c*a - d*fCosAngle);
float C = c*c - e*fCosAngle;
float D = B*B - 4 * A*C;
if (D > 0)
{
D = sqrt(D);
float2 t = (-B + sign(A)*float2(-D, +D)) / (2 * A);
bool2 b2IsCorrect = c + a * t > 0 && t > 0;
t = t * b2IsCorrect + !b2IsCorrect * (inf);
return t;
}
else // no intersection
return inf;
}
//-----------------------------------------------------------------------------------------
// RayPlaneIntersect
//-----------------------------------------------------------------------------------------
float RayPlaneIntersect(in float3 planeNormal, in float planeD, in float3 rayOrigin, in float3 rayDir)
{
float NdotD = dot(planeNormal, rayDir);
float NdotO = dot(planeNormal, rayOrigin);
float t = -(NdotO + planeD) / NdotD;
if (t < 0)
t = 100000;
return t;
}
ENDCG
// pass 0 - point light, camera inside
Pass
{
ZTest Off
Cull Front
ZWrite Off
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment fragPointInside
#pragma target 4.0
#define UNITY_HDR_ON
#pragma shader_feature HEIGHT_FOG
#pragma shader_feature NOISE
#pragma shader_feature SHADOWS_CUBE
#pragma shader_feature POINT_COOKIE
#pragma shader_feature POINT
#ifdef SHADOWS_DEPTH
#define SHADOWS_NATIVE
#endif
fixed4 fragPointInside(v2f i) : SV_Target
{
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float3 rayStart = _WorldSpaceCameraPos;
float3 rayEnd = i.wpos;
float3 rayDir = (rayEnd - rayStart);
float rayLength = length(rayDir);
rayDir /= rayLength;
float linearDepth = LinearEyeDepth(depth);
float projectedDepth = linearDepth / dot(_CameraForward, rayDir);
rayLength = min(rayLength, projectedDepth);
return RayMarch(i.pos.xy, rayStart, rayDir, rayLength);
}
ENDCG
}
// pass 1 - spot light, camera inside
Pass
{
ZTest Off
Cull Front
ZWrite Off
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment fragPointInside
#pragma target 4.0
#define UNITY_HDR_ON
#pragma shader_feature HEIGHT_FOG
#pragma shader_feature NOISE
#pragma shader_feature SHADOWS_DEPTH
#pragma shader_feature SPOT
#ifdef SHADOWS_DEPTH
#define SHADOWS_NATIVE
#endif
fixed4 fragPointInside(v2f i) : SV_Target
{
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float3 rayStart = _WorldSpaceCameraPos;
float3 rayEnd = i.wpos;
float3 rayDir = (rayEnd - rayStart);
float rayLength = length(rayDir);
rayDir /= rayLength;
float linearDepth = LinearEyeDepth(depth);
float projectedDepth = linearDepth / dot(_CameraForward, rayDir);
rayLength = min(rayLength, projectedDepth);
return RayMarch(i.pos.xy, rayStart, rayDir, rayLength);
}
ENDCG
}
// pass 2 - point light, camera outside
Pass
{
//ZTest Off
ZTest [_ZTest]
Cull Back
ZWrite Off
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment fragPointOutside
#pragma target 4.0
#define UNITY_HDR_ON
#pragma shader_feature HEIGHT_FOG
#pragma shader_feature SHADOWS_CUBE
#pragma shader_feature NOISE
//#pragma multi_compile POINT POINT_COOKIE
#pragma shader_feature POINT_COOKIE
#pragma shader_feature POINT
fixed4 fragPointOutside(v2f i) : SV_Target
{
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float3 rayStart = _WorldSpaceCameraPos;
float3 rayEnd = i.wpos;
float3 rayDir = (rayEnd - rayStart);
float rayLength = length(rayDir);
rayDir /= rayLength;
float3 lightToCamera = _WorldSpaceCameraPos - _LightPos;
float b = dot(rayDir, lightToCamera);
float c = dot(lightToCamera, lightToCamera) - (_VolumetricLight.z * _VolumetricLight.z);
float d = sqrt((b*b) - c);
float start = -b - d;
float end = -b + d;
float linearDepth = LinearEyeDepth(depth);
float projectedDepth = linearDepth / dot(_CameraForward, rayDir);
end = min(end, projectedDepth);
rayStart = rayStart + rayDir * start;
rayLength = end - start;
return RayMarch(i.pos.xy, rayStart, rayDir, rayLength);
}
ENDCG
}
// pass 3 - spot light, camera outside
Pass
{
//ZTest Off
ZTest[_ZTest]
Cull Back
ZWrite Off
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment fragSpotOutside
#pragma target 4.0
#define UNITY_HDR_ON
#pragma shader_feature HEIGHT_FOG
#pragma shader_feature SHADOWS_DEPTH
#pragma shader_feature NOISE
#pragma shader_feature SPOT
#ifdef SHADOWS_DEPTH
#define SHADOWS_NATIVE
#endif
float _CosAngle;
float4 _ConeAxis;
float4 _ConeApex;
float _PlaneD;
fixed4 fragSpotOutside(v2f i) : SV_Target
{
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float3 rayStart = _WorldSpaceCameraPos;
float3 rayEnd = i.wpos;
float3 rayDir = (rayEnd - rayStart);
float rayLength = length(rayDir);
rayDir /= rayLength;
// inside cone
float3 r1 = rayEnd + rayDir * 0.001;
// plane intersection
float planeCoord = RayPlaneIntersect(_ConeAxis, _PlaneD, r1, rayDir);
// ray cone intersection
float2 lineCoords = RayConeIntersect(_ConeApex, _ConeAxis, _CosAngle, r1, rayDir);
float linearDepth = LinearEyeDepth(depth);
float projectedDepth = linearDepth / dot(_CameraForward, rayDir);
float z = (projectedDepth - rayLength);
rayLength = min(planeCoord, min(lineCoords.x, lineCoords.y));
rayLength = min(rayLength, z);
return RayMarch(i.pos.xy, rayEnd, rayDir, rayLength);
}
ENDCG
}
// pass 4 - directional light
Pass
{
ZTest Off
Cull Off
ZWrite Off
Blend One One, One Zero
CGPROGRAM
#pragma vertex vertDir
#pragma fragment fragDir
#pragma target 4.0
#define UNITY_HDR_ON
#pragma shader_feature HEIGHT_FOG
#pragma shader_feature NOISE
#pragma shader_feature SHADOWS_DEPTH
#pragma shader_feature DIRECTIONAL_COOKIE
#pragma shader_feature DIRECTIONAL
#ifdef SHADOWS_DEPTH
#define SHADOWS_NATIVE
#endif
struct VSInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
uint vertexId : SV_VertexID;
};
struct PSInput
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 wpos : TEXCOORD1;
};
PSInput vertDir(VSInput i)
{
PSInput o;
o.pos = UnityObjectToClipPos(i.vertex);
o.uv = i.uv;
// SV_VertexId doesn't work on OpenGL for some reason -> reconstruct id from uv
//o.wpos = _FrustumCorners[i.vertexId];
o.wpos = _FrustumCorners[i.uv.x + i.uv.y*2];
return o;
}
fixed4 fragDir(PSInput i) : SV_Target
{
float2 uv = i.uv.xy;
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float linearDepth = Linear01Depth(depth);
float3 wpos = i.wpos;
float3 rayStart = _WorldSpaceCameraPos;
float3 rayDir = wpos - _WorldSpaceCameraPos;
rayDir *= linearDepth;
float rayLength = length(rayDir);
rayDir /= rayLength;
rayLength = min(rayLength, _MaxRayLength);
float4 color = RayMarch(i.pos.xy, rayStart, rayDir, rayLength);
if (linearDepth > 0.999999)
{
color.w = lerp(color.w, 1, _VolumetricLight.w);
}
return color;
}
ENDCG
}
}
}