Загрузка данных
//--------------------------------------------------------------------------
// THIS FILE IS A PRIVATE PROPERTY OF EUCLID LABS STUDIO.
// THIS SHADER MAY NOT BE USED IN ANY PROJECTS
// WITHOUT THE EXPLICIT PERMISSION OF THE RIGHTS HOLDER. ANY USE OF THESE FILES
// IN YOUR PROJECTS REQUIRES PRIOR AGREEMENT WITH THE RIGHTS HOLDER.
// YOU CAN CONTACT US BY MAILING US ON EUCLIDLABSSTUDIO@GMAIL.COM.
//--------------------------------------------------------------------------
#include "Tools.fx"
#ifdef VOLUMETRIC_HQ
#define RAYMARCH_STEPS 4
#else
#define RAYMARCH_STEPS 2
#endif
float3 EyePos : EYE_POSITION;
uniform int Time;
uniform float4 LightPos;
uniform float3 LightColor;
uniform float3 LightDirection;
uniform float LightScattering;
uniform float ShadowIntensity;
uniform float NormalOffset = 0.05;
uniform float2 ShadowMapSize;
uniform int ShadowMapAddress = 3;
uniform float LightLength;
static const float2 InvShadowMapSize = 1.0 / ShadowMapSize;
static const float3 pLightColor = SRGBToLinear(LightColor);
uniform float4x4 LightViewProj;
uniform float4x4 LightViewProj0;
uniform float4x4 LightViewProj1;
uniform float4x4 LightViewProj2;
uniform float4x4 LightViewProj3;
uniform float4x4 LightViewProj4;
uniform float4x4 LightViewProj5;
uniform float4x4 InvViewProj;
uniform float4x4 ShadowsAdjust;
static const float4x4 SpotMatrix = mul(LightViewProj, ShadowsAdjust);
static const float4x4 LightMatrix[6] =
{
mul(LightViewProj0, ShadowsAdjust),
mul(LightViewProj1, ShadowsAdjust),
mul(LightViewProj2, ShadowsAdjust),
mul(LightViewProj3, ShadowsAdjust),
mul(LightViewProj4, ShadowsAdjust),
mul(LightViewProj5, ShadowsAdjust)
};
#include "PBR.fx"
#ifdef D3D11
texture2D tAlbedoMap : register(t0);
sampler AlbedoMap = sampler_state { AddressU = Clamp; AddressV = Clamp; Filter = MIN_MAG_MIP_POINT; };
texture2D tNormalMap : register(t1);
sampler NormalMap = sampler_state { AddressU = Clamp; AddressV = Clamp; Filter = MIN_MAG_MIP_POINT; };
texture2D tDepthMap : register(t2);
sampler DepthMap = sampler_state { AddressU = Clamp; AddressV = Clamp; Filter = MIN_MAG_MIP_POINT; };
textureCUBE tFaceSelectCubeMap : register(t3);
sampler FaceSelectCubeMap = sampler_state { AddressU = Clamp; AddressV = Clamp; AddressW = Clamp; Filter = MIN_MAG_MIP_POINT; };
texture2D tSpotMap : register(t4);
sampler SpotMap = sampler_state { Filter = MIN_MAG_MIP_LINEAR; AddressU = Border; AddressV = Border; BorderColor = float4(0.0, 0.0, 0.0, 0.0); };
Texture2D tShadowMap;
SamplerComparisonState ShadowMap = sampler_state { Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT; AddressU = ShadowMapAddress; AddressV = ShadowMapAddress; BorderColor = float4(1.0, 1.0, 1.0, 1.0); ComparisonFunc = LESS_EQUAL; };
#else
sampler AlbedoMap : register(s0) = sampler_state { AddressU = Clamp; AddressV = Clamp; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; };
sampler NormalMap : register(s1) = sampler_state { AddressU = Clamp; AddressV = Clamp; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; };
sampler DepthMap : register(s2) = sampler_state { AddressU = Clamp; AddressV = Clamp; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; };
samplerCUBE FaceSelectCubeMap : register(s3) = sampler_state { AddressU = Clamp; AddressV = Clamp; AddressW = Clamp; MinFilter = Point; MagFilter = Point; MipFilter = Point; };
sampler SpotMap : register(s4) = sampler_state { MinFilter = Linear; MagFilter = Linear; MipFilter = None; AddressU = Border; AddressV = Border; BorderColor = 0; };
texture tShadowMap;
sampler ShadowMap = sampler_state { Texture = <tShadowMap>;
MinFilter = Point; MagFilter = Linear;
MipFilter = Point; AddressU = ShadowMapAddress; AddressV = ShadowMapAddress; AddressW = ShadowMapAddress; BorderColor = 0xFFFFFFFF; };
#endif
struct PS_INPUT
{
float4 Pos : OUT_POSITION;
float4 ScreenPosition : TEXCOORD0;
float3 WorldPos : TEXCOORD1;
float3 Normal : TEXCOORD2;
};
PS_INPUT VertexProcess(VS_INPUT input)
{
PS_INPUT output;
output.Pos = mul(input.Pos, WorldViewProj);
output.ScreenPosition = output.Pos;
output.WorldPos = mul(input.Pos, World).xyz;
output.Normal = normalize(mul(input.Normal, World).xyz);
return output;
}
inline float4 ClampShadows(float4 ProjCoord, int face)
{
float padding = InvShadowMapSize.x;
float minX = (float)face / 6.0 + padding;
float maxX = ((float)face + 1.0) / 6.0 - padding;
#ifdef D3D11
ProjCoord.x = clamp(ProjCoord.x, minX, maxX);
#else
ProjCoord.x = clamp(ProjCoord.x, minX * ProjCoord.w, maxX * ProjCoord.w);
#endif
return ProjCoord;
}
inline float GetShadow(float4 ProjCoord, int face = 0, float smooth = 1.0)
{
#ifdef D3D11
ProjCoord.xyz /= ProjCoord.w;
float smoothCoeff = clamp(ProjCoord.z * smooth, 1.0, 3.0);
float2 offsets = InvShadowMapSize * smoothCoeff;
#else
float smoothCoeff = clamp(ProjCoord.z / ProjCoord.w * smooth, 1.0, 3.0);
float2 offsets = (InvShadowMapSize * ProjCoord.w) * smoothCoeff;
#endif
float sum = 0.0;
for (int x = -1; x <= 1; ++x)
{
for (int y = -1; y <= 1; ++y)
{
float2 offset = float2(x, y) * offsets;
float4 proj = float4(ProjCoord.xy + offset, ProjCoord.zw);
#if !defined(DIRLIGHT) && !defined(SPOTLIGHT)
proj = ClampShadows(proj, face);
#endif
sum += Sample2DShadow(ShadowMap, proj).r;
}
}
return lerp(sum / 9.0, 1.0, ShadowIntensity);
}
inline float GetPointShadow(float3 worldPos)
{
#ifdef SHADOWS
int face = clamp((int)(255.0f * SampleCubeLOD(FaceSelectCubeMap, float4(worldPos - LightPos.xyz, 0.0)).r), 0, 5);
float4 ProjCoord = mul(float4(worldPos, 1.0), LightMatrix[face]);
ProjCoord.x = ((ProjCoord.x / ProjCoord.w + face) / 6.0) * ProjCoord.w;
return GetShadow(ProjCoord, face);
#else
return 1.0;
#endif
}
inline float GetDirShadow(float3 worldPos)
{
#ifdef SHADOWS
return GetShadow(mul(float4(worldPos, 1.0), SpotMatrix), 0, 0.0f);
#else
return 1.0;
#endif
}
inline float GetSpotShadow(float3 worldPos)
{
#ifdef SHADOWS
return GetShadow(mul(float4(worldPos, 1.0), SpotMatrix));
#else
return 1.0;
#endif
}
inline float GetShadowRay(float4 ProjCoord)
{
#ifdef D3D11
ProjCoord.xyz /= ProjCoord.w;
#endif
return Sample2DShadow(ShadowMap, ProjCoord).r;
}
inline float GetPointShadowRay(float3 worldPos)
{
#ifdef SHADOWS
int face = 255 * SampleCubeLOD(FaceSelectCubeMap, float4(worldPos - LightPos.xyz, 0.0)).r;
float4 ProjCoord = mul(float4(worldPos, 1.0), LightMatrix[face]);
ProjCoord.x = ((ProjCoord.x / ProjCoord.w + face) / 6.0) * ProjCoord.w;
return GetShadowRay(ProjCoord);
#else
return 1.0;
#endif
}
inline void GetGBuffer(float4 ScreenPosition, out float2 TexCoords, out float3 worldPos, out float3 diffuse, out float3 normal, out float roughness, out float metallic)
{
TexCoords = GetScreenTexCoords(ScreenPosition) + halfPixel;
float4 Albedo = Sample2DLod0(AlbedoMap, TexCoords);
float4 Normals = Sample2DLod0(NormalMap, TexCoords);
worldPos = GetWorldPosition(TexCoords, Sample2DLod0(DepthMap, TexCoords).r, InvViewProj);
metallic = Normals.a;
roughness = length(Normals.xyz);
normal = normalize(Normals.xyz);
diffuse = Albedo.rgb;
}
inline float CalculateAttenuation(float3 lightVec, out float3 lightDir)
{
float distSqr = dot(lightVec, lightVec);
float len = sqrt(distSqr);
lightDir = lightVec / len;
float radiusSqr = 1.0 / max(LightPos.w * LightPos.w, 0.0001);
float attenuation = 1.0 / (distSqr + 1.0);
float windowing = pow(saturate(1.0 - pow(distSqr / radiusSqr, 2)), 2);
return attenuation * windowing;
}
inline void GetLighting(float3 worldPos, float3 normal, out float light, inout float3 lightVec, out float3 worldPosN)
{
#ifndef DIRLIGHT
float3 lightDir;
lightVec = LightPos.xyz - worldPos;
light = CalculateAttenuation(lightVec, lightDir);
#else
lightVec = LightDirection;
float3 lightDir = LightDirection;
light = 1.0;
#endif
#ifdef SHADOWS
#ifndef DIRLIGHT
float cosAngle = saturate(1.0 - dot(normal, normalize(LightPos.xyz - worldPos)));
#else
float cosAngle = saturate(1.0 - dot(normal, lightDir));
#endif
worldPosN = worldPos + (cosAngle * NormalOffset * normal);
#else
worldPosN = 0.0f;
#endif
}
inline float3 CalculateScattering(float3 volumePos, float3 volumeNormal, float3 worldPos, float3 eyeDir)
{
const float3 volumeDir = normalize(volumePos - EyePos);
const float AttenPow = 1-pow(1.0f-saturate(dot(volumeDir, volumeNormal)),1);
return float4(pLightColor, 1) * saturate(GetScattering(EyePos, eyeDir, LightPos.xyz) * LightScattering * 0.001 * AttenPow);
}
inline float3 RaymarchLight(float3 volumePos, float3 volumeNormal, float3 worldPos, float2 iScreenPos)
{
float3 rayVec = worldPos - EyePos;
#ifdef VOLUMETRIC
float3 accumulated = 0.0f;
#ifdef SHADOWS
float rayLength = length(rayVec);
float3 rayDirection = rayVec / rayLength;
float stepSize = rayLength / RAYMARCH_STEPS;
float3 step = rayDirection * stepSize;
float3 currentposition = EyePos + step * DITHER_PATTERN[clamp(int(iScreenPos.x * ScreenSize.x) % 4, 0, 3)][clamp(int(iScreenPos.y * ScreenSize.y) % 4, 0, 3)];
#if defined(DIRLIGHT) || defined(SPOTLIGHT)
float4 projCoord = mul(float4(currentposition, 1.0), SpotMatrix);
float4 projStep = mul(float4(step, 0.0), SpotMatrix);
#endif
for (int i = 0; i < RAYMARCH_STEPS; ++i)
{
float3 lightDir;
float3 intensity;
float shadow;
#if defined(DIRLIGHT)
lightDir = LightDirection;
shadow = GetShadowRay(projCoord);
intensity = 1.0f;
#elif defined(SPOTLIGHT)
float3 spotColor = projCoord.w > 0.0 ? Sample2DProjLod0(SpotMap, projCoord).rgb * GetShadowRay(projCoord) : 0.0;
intensity = CalculateAttenuation(LightPos.xyz - currentposition, lightDir) * spotColor;
shadow = 1;
#else
intensity = CalculateAttenuation(LightPos.xyz - currentposition, lightDir);
shadow = GetPointShadowRay(currentposition);
#endif
float dust = DustNoise(currentposition * 3.0, Time * 0.00035);
dust = dust * dust * dust * 2.5;
float scatteringDot = dot(rayDirection, lightDir);
float scattering = max(ComputeScattering(0.8f, 7.0f, scatteringDot), 0.25) * 0.3;
accumulated += intensity * shadow * (1.0 + dust) * scattering;
currentposition += step;
#if defined(DIRLIGHT) || defined(SPOTLIGHT)
projCoord += projStep;
#endif
}
accumulated *= stepSize * pLightColor * LightScattering * 0.1;
#endif
return lerp(accumulated, CalculateScattering(volumePos, volumeNormal, worldPos, rayVec), ShadowIntensity);
#else
return CalculateScattering(volumePos, volumeNormal, worldPos, rayVec);
#endif
}
inline float3 GetVolumetricWorldPos(float3 sceneWorldPos, float3 volumeWorldPos)
{
float3 rayDir = sceneWorldPos - EyePos;
float sceneDist = length(rayDir);
float volumeDist = length(volumeWorldPos - EyePos);
return EyePos + rayDir * saturate(volumeDist / (sceneDist + 0.0001));
}
// ================================================================================== LIGHTING
struct LightOutput
{
float4 Color : OUTPUT(0);
#ifdef SCATTERING
float4 Volume : OUTPUT(1);
#endif
};
LightOutput ProcessLight(PS_INPUT input)
{
float3 diffuse, normal;
float3 worldPos, lightVec, worldPosN, color;
float diff, roughness, metallic;
float2 texCoords;
GetGBuffer(input.ScreenPosition, texCoords, worldPos, diffuse, normal, roughness, metallic);
GetLighting(worldPos, normal, diff, lightVec, worldPosN);
#if defined(DIRLIGHT)
diff *= GetDirShadow(worldPosN);
color = pLightColor;
#elif defined(SPOTLIGHT)
float4 spotPos = mul(float4(worldPos, 1.0), SpotMatrix);
color = spotPos.w > 0.0 ? pLightColor * Sample2DProjLod0(SpotMap, spotPos).rgb * GetSpotShadow(worldPosN) : 0.0;
#else
diff *= GetPointShadow(worldPosN);
color = pLightColor;
#endif
const float3 eyeVector = normalize(EyePos - worldPos);
float3 minReflectance = 0.04;
float3 F0 = lerp(minReflectance, max(minReflectance, diffuse), metallic);
float3 light = CalculatePBRLight(lightVec, color, eyeVector, normal, diffuse * (1.0 - metallic), F0, roughness, LightLength, LightDirection);
LightOutput lighting;
lighting.Color = float4(light * diff, 1.0f);
#ifdef SCATTERING
float3 raymarchWorldPos = GetVolumetricWorldPos(worldPos, input.WorldPos); // Fix raymarch on non rendered
lighting.Volume = float4(RaymarchLight(input.WorldPos, input.Normal, raymarchWorldPos, texCoords), 1.0f);
#endif
return lighting;
}
#ifdef D3D11
DepthStencilState DepthState
{
DepthEnable = FALSE;
DepthWriteMask = ZERO;
DepthFunc = LESS_EQUAL;
};
RasterizerState RasterState
{
CullMode = FRONT;
};
#endif
technique Main
{
pass Light
{
Vertex(VertexProcess);
Pixel(ProcessLight);
#ifdef D3D11
SetDepthStencilState(DepthState, 0);
#ifndef DIRLIGHT
SetRasterizerState(RasterState);
#endif
#else
CullMode = CW;
ZWriteEnable = false;
Lighting = false;
#endif
}
}