浏览代码

Merge pull request #588 from EvgeniiG/master

Improve HLSL macros
/main
GitHub 7 年前
当前提交
c646275f
共有 6 个文件被更改,包括 118 次插入144 次删除
  1. 152
      ScriptableRenderPipeline/Core/ShaderLibrary/Common.hlsl
  2. 2
      ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl
  3. 2
      ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl
  4. 14
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  5. 2
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  6. 90
      ScriptableRenderPipeline/Core/ShaderLibrary/Macros.hlsl

152
ScriptableRenderPipeline/Core/ShaderLibrary/Common.hlsl


#endif
#include "API/Validate.hlsl"
#include "Macros.hlsl"
// Some shader compiler don't support to do multiple ## for concatenation inside the same macro, it require an indirection.
// This is the purpose of this macro
#define MERGE_NAME(X, Y) X##Y
// These define are use to abstract the way we sample into a cubemap array.
// Some platform don't support cubemap array so we fallback on 2D latlong
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURE2D_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLER2D
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURE2D_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURE2D_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, DirectionToLatLongCoordinate(coord3), index, lod)
#else
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURECUBE_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLERCUBE
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURECUBE_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURECUBE_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#endif
// ----------------------------------------------------------------------------
// Common intrinsic (general implementation of intrinsic available on some platform)
// ----------------------------------------------------------------------------

}
#ifndef INTRINSIC_WAVEREADFIRSTLANE
// Warning: for correctness, the value you pass to the function must be constant across the wave!
uint WaveReadFirstLane(uint scalarValue)
{
return scalarValue;
}
// Warning: for correctness, the argument must have the same value across the wave!
TEMPLATE_1_FLT(WaveReadFirstLane, scalarValue, return scalarValue)
TEMPLATE_1_INT(WaveReadFirstLane, scalarValue, return scalarValue)
int Mul24(int a, int b)
{
return a * b;
}
uint Mul24(uint a, uint b)
{
return a * b;
}
TEMPLATE_2_INT(Mul24, a, b, return a * b)
int Mad24(int a, int b, int c)
{
return a * b + c;
}
uint Mad24(uint a, uint b, uint c)
{
return a * b + c;
}
TEMPLATE_3_INT(Mad24, a, b, c, return a * b + c)
float Min3(float a, float b, float c)
{
return min(min(a, b), c);
}
float2 Min3(float2 a, float2 b, float2 c)
{
return min(min(a, b), c);
}
float3 Min3(float3 a, float3 b, float3 c)
{
return min(min(a, b), c);
}
float4 Min3(float4 a, float4 b, float4 c)
{
return min(min(a, b), c);
}
float Max3(float a, float b, float c)
{
return max(max(a, b), c);
}
float2 Max3(float2 a, float2 b, float2 c)
{
return max(max(a, b), c);
}
float3 Max3(float3 a, float3 b, float3 c)
{
return max(max(a, b), c);
}
float4 Max3(float4 a, float4 b, float4 c)
{
return max(max(a, b), c);
}
TEMPLATE_3_FLT(Min3, a, b, c, return min(min(a, b), c))
TEMPLATE_3_INT(Min3, a, b, c, return min(min(a, b), c))
TEMPLATE_3_FLT(Max3, a, b, c, return max(max(a, b), c))
TEMPLATE_3_INT(Max3, a, b, c, return max(max(a, b), c))
void Swap(inout float a, inout float b)
{
float t = a; a = b; b = t;
}
void Swap(inout float2 a, inout float2 b)
{
float2 t = a; a = b; b = t;
}
void Swap(inout float3 a, inout float3 b)
{
float3 t = a; a = b; b = t;
}
void Swap(inout float4 a, inout float4 b)
{
float4 t = a; a = b; b = t;
}
TEMPLATE_SWAP(Swap) // Define a Swap(a, b) function for all types
#define CUBEMAPFACE_POSITIVE_X 0
#define CUBEMAPFACE_NEGATIVE_X 1

#define HALF_PI 1.57079632679
#define INV_HALF_PI 0.636619772367
#define INFINITY asfloat(0x7F800000)
#define FLT_SMALL 0.0001
#define LOG2_E 1.44269504089
#define FLT_EPSILON 1.192092896e-07 // Smallest positive number, such that 1.0 + FLT_EPSILON != 1.0

float DegToRad(float deg)
{
return deg * PI / 180.0;
return deg * (PI / 180.0);
return rad * 180.0 / PI;
return rad * (180.0 / PI);
float Sqr(float x)
{
return x * x;
}
float3 Sqr(float3 x)
{
return x * x;
}
TEMPLATE_1_FLT(Sq, x, return x * x)
TEMPLATE_1_INT(Sq, x, return x * x)
// Input [0, 1] and output [0, PI/2]
// 9 VALU

// Using pow often result to a warning like this
// "pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them"
// PositivePow remove this warning when you know the value is positive and avoid inf/NAN.
float PositivePow(float base, float power)
{
return pow(max(abs(base), float(FLT_EPSILON)), power);
}
float2 PositivePow(float2 base, float2 power)
{
return pow(max(abs(base), float2(FLT_EPSILON, FLT_EPSILON)), power);
}
float3 PositivePow(float3 base, float3 power)
{
return pow(max(abs(base), float3(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}
float4 PositivePow(float4 base, float4 power)
{
return pow(max(abs(base), float4(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}
TEMPLATE_2_FLT(PositivePow, base, power, return pow(max(abs(base), FLT_EPSILON), power))
float3 FastSign(float x)
float FastSign(float x)
return saturate(x * FLT_MAX) * 2.0 - 1.0;
return saturate(x * FLT_MAX) * 2.0 - 1.0;
}
// Orthonormalizes the tangent frame using the Gram-Schmidt process.

2
ScriptableRenderPipeline/Core/ShaderLibrary/CommonLighting.hlsl


// ior is a value between 1.0 and 2.5
float IORToFresnel0(float ior)
{
return Sqr((ior - 1.0) / (ior + 1.0));
return Sq((ior - 1.0) / (ior + 1.0));
}
#endif // UNITY_COMMON_LIGHTING_INCLUDED

2
ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl


// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
float3 TransmittanceColorAtDistanceToAbsorption(float3 transmittanceColor, float atDistance)
{
return -log(transmittanceColor + 0.00001) / max(atDistance, 0.000001);
return -log(transmittanceColor + FLT_EPSILON) / max(atDistance, FLT_EPSILON);
}

14
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


float ieta = 1.0 / bsdfData.coatIOR; // inverse eta
preLightData.ieta = ieta;
preLightData.coatFresnel0 = Sqr(bsdfData.coatIOR - 1.0) / Sqr(bsdfData.coatIOR + 1.0);
preLightData.coatFresnel0 = Sq(bsdfData.coatIOR - 1.0) / Sq(bsdfData.coatIOR + 1.0);
// Clear coat IBL
preLightData.coatIblDirWS = reflect(-V, N);

// Update the roughness and the IBL miplevel
// Bottom layer is affected by upper layer BRDF, result can't be more sharp than input (it is to mimic what a path tracer will do)
float roughness = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness);
float shininess = Sqr(preLightData.ieta) * (2.0 / Sqr(roughness) - 2.0);
float shininess = Sq(preLightData.ieta) * (2.0 / Sq(roughness) - 2.0);
roughness = sqrt(2.0 / (shininess + 2.0));
preLightData.iblDirWS = GetSpecularDominantDir(N, iblR, roughness, NdotV);
preLightData.iblMipLevel = PerceptualRoughnessToMipmapLevel(RoughnessToPerceptualRoughness(roughness));

{
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer
float F = F_Schlick(preLightData.coatFresnel0, preLightData.coatNdotV);
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
F = Sq(-F * bsdfData.coatCoverage + 1.0);
F /= preLightData.ieta; //TODO: LaurentB why / ieta here and not for other lights ?
preLightData.ltcMagnitudeFresnel = F * bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;

float NdotL = saturate(dot(bsdfData.coatNormalWS, L));
float NdotV = preLightData.coatNdotV;
float LdotV = dot(L, V);
float invLenLV = rsqrt(max(2 * LdotV + 2, FLT_SMALL));
float invLenLV = rsqrt(max(2 * LdotV + 2, FLT_EPSILON));
float NdotH = saturate((NdotL + NdotV) * invLenLV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);

specularLighting += F * D_GGX(NdotH, 0.01) * NdotL * bsdfData.coatCoverage;
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
F = Sq(-F * bsdfData.coatCoverage + 1.0);
// Change the Light and View direction to account for IOR change.
// Update the half vector accordingly

float NdotL = saturate(dot(bsdfData.normalWS, L)); // Must have the same value without the clamp
float NdotV = preLightData.NdotV; // Get the unaltered (geometric) version
float LdotV = dot(L, V);
float invLenLV = rsqrt(max(2 * LdotV + 2, FLT_SMALL)); // invLenLV = rcp(length(L + V)) - caution about the case where V and L are opposite, it can happen, use max to avoid this
float invLenLV = rsqrt(max(2 * LdotV + 2, FLT_EPSILON)); // invLenLV = rcp(length(L + V)) - caution about the case where V and L are opposite, it can happen, use max to avoid this
float NdotH = saturate((NdotL + NdotV) * invLenLV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);

envLighting += F * preLD.rgb * bsdfData.coatCoverage;
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer.
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
F = Sq(-F * bsdfData.coatCoverage + 1.0);
}
float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, preLightData.iblMipLevel);

2
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


// Ambient occlusion is cosine weighted, thus use following equation. See slide 129
float cosAv = sqrt(1.0 - surfaceData.ambientOcclusion);
float roughness = max(PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness), 0.01); // Clamp to 0.01 to avoid edge cases
float cosAs = exp2(-3.32193 * Sqr(roughness));
float cosAs = exp2((-log(10.0)/log(2.0)) * Sq(roughness));
float cosB = dot(bentNormalWS, reflect(-V, surfaceData.normalWS));
return SphericalCapIntersectionSolidArea(cosAv, cosAs, cosB) / (TWO_PI * (1.0 - cosAs));

90
ScriptableRenderPipeline/Core/ShaderLibrary/Macros.hlsl


#ifndef UNITY_MACROS_INCLUDED
#define UNITY_MACROS_INCLUDED
// Some shader compiler don't support to do multiple ## for concatenation inside the same macro, it require an indirection.
// This is the purpose of this macro
#define MERGE_NAME(X, Y) X##Y
// These define are use to abstract the way we sample into a cubemap array.
// Some platform don't support cubemap array so we fallback on 2D latlong
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURE2D_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLER2D
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURE2D_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURE2D_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, DirectionToLatLongCoordinate(coord3), index, lod)
#else
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURECUBE_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLERCUBE
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURECUBE_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURECUBE_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#endif
#define TEMPLATE_1_FLT(FunctionName, Parameter1, FunctionBody) \
float FunctionName(float Parameter1) { FunctionBody; } \
float2 FunctionName(float2 Parameter1) { FunctionBody; } \
float3 FunctionName(float3 Parameter1) { FunctionBody; } \
float4 FunctionName(float4 Parameter1) { FunctionBody; }
#define TEMPLATE_1_INT(FunctionName, Parameter1, FunctionBody) \
int FunctionName(int Parameter1) { FunctionBody; } \
int2 FunctionName(int2 Parameter1) { FunctionBody; } \
int3 FunctionName(int3 Parameter1) { FunctionBody; } \
int4 FunctionName(int4 Parameter1) { FunctionBody; } \
uint FunctionName(uint Parameter1) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1) { FunctionBody; }
#define TEMPLATE_2_FLT(FunctionName, Parameter1, Parameter2, FunctionBody) \
float FunctionName(float Parameter1, float Parameter2) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2) { FunctionBody; }
#define TEMPLATE_2_INT(FunctionName, Parameter1, Parameter2, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2) { FunctionBody; } \
uint FunctionName(uint Parameter1, uint Parameter2) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1, uint2 Parameter2) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1, uint3 Parameter2) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1, uint4 Parameter2) { FunctionBody; }
#define TEMPLATE_3_FLT(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
float FunctionName(float Parameter1, float Parameter2, float Parameter3) { FunctionBody; } \
float2 FunctionName(float2 Parameter1, float2 Parameter2, float2 Parameter3) { FunctionBody; } \
float3 FunctionName(float3 Parameter1, float3 Parameter2, float3 Parameter3) { FunctionBody; } \
float4 FunctionName(float4 Parameter1, float4 Parameter2, float4 Parameter3) { FunctionBody; }
#define TEMPLATE_3_INT(FunctionName, Parameter1, Parameter2, Parameter3, FunctionBody) \
int FunctionName(int Parameter1, int Parameter2, int Parameter3) { FunctionBody; } \
int2 FunctionName(int2 Parameter1, int2 Parameter2, int2 Parameter3) { FunctionBody; } \
int3 FunctionName(int3 Parameter1, int3 Parameter2, int3 Parameter3) { FunctionBody; } \
int4 FunctionName(int4 Parameter1, int4 Parameter2, int4 Parameter3) { FunctionBody; } \
uint FunctionName(uint Parameter1, uint Parameter2, uint Parameter3) { FunctionBody; } \
uint2 FunctionName(uint2 Parameter1, uint2 Parameter2, uint2 Parameter3) { FunctionBody; } \
uint3 FunctionName(uint3 Parameter1, uint3 Parameter2, uint3 Parameter3) { FunctionBody; } \
uint4 FunctionName(uint4 Parameter1, uint4 Parameter2, uint4 Parameter3) { FunctionBody; }
#define TEMPLATE_SWAP(FunctionName) \
void FunctionName(inout float a, inout float b) { float t = a; a = b; b = t; } \
void FunctionName(inout float2 a, inout float2 b) { float2 t = a; a = b; b = t; } \
void FunctionName(inout float3 a, inout float3 b) { float3 t = a; a = b; b = t; } \
void FunctionName(inout float4 a, inout float4 b) { float4 t = a; a = b; b = t; } \
void FunctionName(inout int a, inout int b) { int t = a; a = b; b = t; } \
void FunctionName(inout int2 a, inout int2 b) { int2 t = a; a = b; b = t; } \
void FunctionName(inout int3 a, inout int3 b) { int3 t = a; a = b; b = t; } \
void FunctionName(inout int4 a, inout int4 b) { int4 t = a; a = b; b = t; } \
void FunctionName(inout uint a, inout uint b) { uint t = a; a = b; b = t; } \
void FunctionName(inout uint2 a, inout uint2 b) { uint2 t = a; a = b; b = t; } \
void FunctionName(inout uint3 a, inout uint3 b) { uint3 t = a; a = b; b = t; } \
void FunctionName(inout uint4 a, inout uint4 b) { uint4 t = a; a = b; b = t; } \
void FunctionName(inout bool a, inout bool b) { bool t = a; a = b; b = t; } \
void FunctionName(inout bool2 a, inout bool2 b) { bool2 t = a; a = b; b = t; } \
void FunctionName(inout bool3 a, inout bool3 b) { bool3 t = a; a = b; b = t; } \
void FunctionName(inout bool4 a, inout bool4 b) { bool4 t = a; a = b; b = t; }
#endif // UNITY_MACROS_INCLUDED
正在加载...
取消
保存