Untitled

 avatar
unknown
c_cpp
a year ago
4.4 kB
6
Indexable
Shader "Planet/Atmosphere"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
			#include "../Include/Math.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
				float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
				float3 viewVector : TEXCOORD1;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;

				float3 viewVector = mul(unity_CameraInvProjection, float4(v.uv.xy * 2 - 1, 0, -1));
				o.viewVector = mul(unity_CameraToWorld, float4(viewVector, 0));
                return o;
            }

            sampler2D _MainTex;
			sampler2D _CameraDepthTexture;

			float3 planetCenter, dirToSun, scatteringCoefficients;
			float planetRadius, atmosphereRadius, densityFallofff, intensity;
			int numOpticalDepthPoints, numInScatteringPoints;

			//Returns density value between 0 and 1
			float densityAtPoint(float3 densitySamplePoint)
			{
				float heightAboveSurface = length(densitySamplePoint - planetCenter) - planetRadius;
				float height01 = heightAboveSurface / (atmosphereRadius - planetRadius);
				float localDensity = exp(-height01 * densityFallofff) * (1 - height01);
				return localDensity;
			}

			float opticalDepth(float3 rayOrigin, float3 rayDir, float rayLength)
			{
				float3 densitySamplePoint = rayOrigin;
				float stepSize = rayLength / (numOpticalDepthPoints - 1);
				float opticalDepth = 0;

				if (stepSize > 0)
				for (int i = 0; i < numOpticalDepthPoints; i++) {
					float localDensity = densityAtPoint(densitySamplePoint);
					opticalDepth += localDensity * stepSize;
					densitySamplePoint += rayDir * stepSize;
				}

				return opticalDepth;
			}

			float3 calculateLight(float3 rayOrigin, float3 rayDir, float rayLength, float3 originalCol)
			{
				float3 inScatterPoint = rayOrigin;
				float stepSize = rayLength / (numInScatteringPoints - 1);
				float3 inScatteredLight = 0;
				float viewRayOpticalDepth = 0;
				float sunRayOpticalDepth = 0;

				for (int i = 0; i < numInScatteringPoints; i++)
				{
					float sunRayLength = raySphere(planetCenter, atmosphereRadius, inScatterPoint, dirToSun).y;
					sunRayOpticalDepth = opticalDepth(inScatterPoint, dirToSun, sunRayLength);
					viewRayOpticalDepth = opticalDepth(inScatterPoint, -rayDir, stepSize * i);
					float3 transmittance = exp(-(sunRayOpticalDepth + viewRayOpticalDepth) * scatteringCoefficients);
					float localDensity = densityAtPoint(inScatterPoint);

					inScatteredLight += localDensity * transmittance;// * scatteringCoefficients * stepSize; 
					inScatterPoint += rayDir * stepSize;
				}

				inScatteredLight *= scatteringCoefficients * intensity * stepSize;
				float originalColTransmittance = exp(-(viewRayOpticalDepth + sunRayOpticalDepth));
				return originalCol * exp(originalColTransmittance) + inScatteredLight;
			}

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 originalCol = tex2D(_MainTex, i.uv);
				float sceneDepthNonLinear = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
				float sceneDepth = LinearEyeDepth(sceneDepthNonLinear) * length(i.viewVector);

				float3 rayOrigin = _WorldSpaceCameraPos;
				float3 rayDir = normalize(i.viewVector);

				float2 hitInfo = raySphere(planetCenter, atmosphereRadius, rayOrigin, rayDir);
				float dstToAtmosphere = hitInfo.x;
				float dstThroughAtmosphere = min(hitInfo.y, sceneDepth - dstToAtmosphere);

				if (dstThroughAtmosphere > 0)
				{
					float3 pointInAtmosphere = rayOrigin + rayDir * dstToAtmosphere;
					float3 light = calculateLight(pointInAtmosphere, rayDir, dstThroughAtmosphere, originalCol);
					return float4(light,0);
				}
				
				//return dstThroughAtmosphere / (atmosphereRadius * 2);// * float4(rayDir.rgb * 0.5 + 0.5, 0);
				return originalCol;
            }
            ENDCG
        }
    }
}
Editor is loading...
Leave a Comment