Files
UnrealEngine/Engine/Shaders/Private/SpecularProfile.usf
2025-05-18 13:04:45 +08:00

130 lines
4.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Common.ush"
#include "/Engine/Shared/SubstrateDefinitions.h"
#include "SpecularProfileCommon.ush"
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef SHADER_COPY
int2 SourceResolution;
uint SourceMipCount;
int2 TargetResolution;
uint TargetIndex;
SamplerState SourceSampler;
Texture2D<float4> SourceTexture;
RWTexture2DArray<float4> TargetTexture;
Buffer<float4> ViewColorBuffer;
Buffer<float4> LightColorBuffer;
[numthreads(8, 8, 1)]
void MainCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
const uint2 PixelPos = DispatchThreadId.xy;
if (all(PixelPos < uint2(TargetResolution)))
{
const float2 TexCoord = float2(PixelPos + 0.5f) / float2(TargetResolution);
#if PERMUTATION_PROCEDURAL
{
const float3 C0 = ViewColorBuffer[PixelPos.x].xyz;
const float3 C1 = LightColorBuffer[PixelPos.y].xyz;
TargetTexture[uint3(PixelPos,TargetIndex * SUBSTRATE_SPECULAR_PROFILE_ENTRY_COUNT + SUBSTRATE_SPECULAR_PROFILE_ENTRY_LIGHT)] = float4(C0 * C1, 1);
}
#else
{
const float SourceMip = clamp(log2(SourceResolution.x) - log2(TargetResolution.x), 0.f, SourceMipCount-1);
const float4 Value = SourceTexture.SampleLevel(SourceSampler, TexCoord, SourceMip);
TargetTexture[uint3(PixelPos,TargetIndex * SUBSTRATE_SPECULAR_PROFILE_ENTRY_COUNT + SUBSTRATE_SPECULAR_PROFILE_ENTRY_LIGHT)] = Value;
}
#endif
}
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef SHADER_CONVOLVE
#include "MonteCarlo.ush"
#include "BRDF.ush"
uint SampleCount;
int2 Resolution;
uint ProfileCount;
#if PERMUTATION_READ_WRITE_ON_ARRAY == 0
Texture2DArray<float4> SourceTexture;
#endif
RWTexture2DArray<float4> TargetTexture;
StructuredBuffer<float> ProfileSignBuffer;
float3 EvaluateSpecularProfile(float NoV, float NoL, float VoH, float NoH, float SpecularProfileId)
{
const float3 ProfileCoord = GetSpecularProfileCoord(SpecularProfileId, NoV, NoL, VoH, NoH);
uint3 FetchCoord = uint3(ProfileCoord.xy * (Resolution - 1), ProfileCoord.z);
FetchCoord.x = clamp(FetchCoord.x, 0u, uint(Resolution.x - 1));
FetchCoord.y = clamp(FetchCoord.y, 0u, uint(Resolution.y - 1));
#if PERMUTATION_READ_WRITE_ON_ARRAY
return TargetTexture[FetchCoord].xyz;
#else
return SourceTexture[FetchCoord].xyz;
#endif
}
float3 Convolve(float3 V, float3 N, float Roughness, float SpecularProfileId)
{
float3 OutValue = 0;
float OutWeight = 0;
LOOP
for (uint SampleIt = 0; SampleIt < SampleCount; ++SampleIt)
{
const float2 E = Hammersley(SampleIt, SampleCount, 0);
const float4 HAndPDF = ImportanceSampleVisibleGGX(E, Pow2(Roughness), V);
const float3 H = HAndPDF.xyz;
const float PDF = HAndPDF.w;
// Sample generation
const float3 L = 2 * dot(V, H) * H - V;
if (L.z > 0)
{
const float NoV = saturate(dot(N, V));
const float NoL = saturate(dot(N, L));
const float NoH = saturate(dot(N, H));
const float VoH = saturate(dot(V, H));
if (PDF > 0)
{
const float3 Value = EvaluateSpecularProfile(NoV, NoL, VoH, NoH, SpecularProfileId);
OutValue += Value;
OutWeight+= 1;
}
}
}
OutValue /= max(0.001f, OutWeight);
return OutValue;
}
[numthreads(8, 8, 1)]
void MainCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
const uint2 PixelPos = DispatchThreadId.xy;
const uint ProfileIndex = DispatchThreadId.z;
if (all(PixelPos < uint2(Resolution)) && ProfileIndex < ProfileCount)
{
const float NoV = (PixelPos.x+0.5f) / float(Resolution.x);
const float Roughness = max(PixelPos.y / float(Resolution.y-1), 0.02f);
const float SpecularProfileId = ProfileSignBuffer[ProfileIndex] * ProfileIndex; // The sign encodes the parameterization (NoV / NoH)
const float3 N = float3(0, 0, 1);
const float3 V = float3(sqrt(1-NoV*NoV), 0, NoV);
const float3 ConvolvedColor = Convolve(V, N, Roughness, SpecularProfileId);
const uint3 OutCoord = uint3(PixelPos, ProfileIndex * SUBSTRATE_SPECULAR_PROFILE_ENTRY_COUNT + SUBSTRATE_SPECULAR_PROFILE_ENTRY_ENV);
TargetTexture[OutCoord] = float4(ConvolvedColor, 1);
}
}
#endif