浏览代码

Merge pull request #824 from EvgeniiG/master

Store the tangent vector in 11 bits
/main
GitHub 7 年前
当前提交
3fc9fef0
共有 7 个文件被更改,包括 93 次插入77 次删除
  1. 12
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl
  2. 9
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl
  3. 2
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/GeometricTools.hlsl
  4. 39
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Packing.hlsl
  5. 68
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  6. 32
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/QuaternionMath.hlsl
  7. 8
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/QuaternionMath.hlsl.meta

12
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl


// PositivePow remove this warning when you know the value is positive and avoid inf/NAN.
TEMPLATE_2_REAL(PositivePow, base, power, return pow(max(abs(base), FLT_EPS), power))
// Computes (FastSign(s) * x) using 2x VALU.
// Composes a floating point value with the magnitude of 'x' and the sign of 's'.
float FastMulBySignOf(float s, float x, bool ignoreNegZero = true)
float CopySign(float x, float s, bool ignoreNegZero = true)
return (s >= 0) ? x : -x;
return (s >= 0) ? abs(x) : -abs(x);
return asfloat(signBit ^ asuint(x));
return asfloat(BitFieldInsert(negZero, signBit, asuint(x)));
return (s >= 0) ? x : -x;
return (s >= 0) ? abs(x) : -abs(x);
#endif
}

// Note that the sign() function in HLSL implements signum, which returns 0 for 0.
float FastSign(float s, bool ignoreNegZero = true)
{
return FastMulBySignOf(s, 1.0, ignoreNegZero);
return CopySign(1.0, s, ignoreNegZero);
}
// Orthonormalizes the tangent frame using the Gram-Schmidt process.

9
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl


return N;
}
// Generates an orthonormal right-handed basis from a unit vector.
// Ref: http://marc-b-reynolds.github.io/quaternions/2016/07/06/Orthonormal.html
// Generates an orthonormal (row-major) basis from a unit vector. TODO: make it column-major.
// The resulting rotation matrix has the determinant of +1.
// Ref: 'ortho_basis_pixar_r2' from http://marc-b-reynolds.github.io/quaternions/2016/07/06/Orthonormal.html
real3x3 GetLocalFrame(real3 localZ)
{
real x = localZ.x;

real3 localX = real3(c * x * a - 1, sz * b, c);
real3 localY = real3(b, y * ya - sz, y);
// Note: due to the quaternion formulation, the generated frame is rotated by 180 degrees,
// s.t. if localZ = {0, 0, 1}, then localX = {-1, 0, 0} and localY = {0, -1, 0}.
// Generates an orthonormal (row-major) basis from a unit vector. TODO: make it column-major.
// The resulting rotation matrix has the determinant of +1.
real3x3 GetLocalFrame(real3 localZ, real3 localX)
{
real3 localY = cross(localZ, localX);

2
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/GeometricTools.hlsl


bool SolveQuadraticEquation(float a, float b, float c, out float2 roots)
{
float d = b * b - 4 * a * c;
float q = -0.5 * (b + FastMulBySignOf(b, sqrt(d)));
float q = -0.5 * (b + CopySign(sqrt(d), b));
roots = float2(q / a, c / q);
return (d >= 0);

39
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Packing.hlsl


return normalize(n * 2.0 - 1.0);
}
// Ref: http://www.vis.uni-stuttgart.de/~engelhts/paper/vmvOctaMaps.pdf
// Encode with Oct, this function work with any size of output
// return real between [-1, 1]
real2 PackNormalOctRectEncode(real3 n)
{
// Perform planar projection.
real3 p = n * rcp(dot(abs(n), 1.0));
// Unfold the octahedron.
real r = 1 - p.x + p.y;
real g = p.x + p.y;
// Left side of the 2:1 rectangle for the negative hemisphere, right otherwise.
// We also correct the aspect ratio from 2:1 to 1:1.
real s = CopySign(0.5, p.z);
return real2(s * r, g);
}
real3 UnpackNormalOctRectEncode(real2 f)
{
real r = f.r;
real g = f.g;
real s = FastSign(r);
// Solve for {x, y, z} given {r, g}.
real x = 0.5 * g + 0.5 - s * r;
real y = g - x;
real z = s * max(1.0 - abs(x) - abs(y), FLT_EPS); // Clamping is absolutely crucial for numerical stability
real3 p = real3(x, y, z);
return normalize(p);
}
real2 PackNormalOctEncode(real3 n)
real2 PackNormalOctQuadEncode(real3 n)
{
//real l1norm = dot(abs(n), 1.0);
//real2 res0 = n.xy * (1.0 / l1norm);

return n.xy + (n.xy >= 0.0 ? t : -t);
}
real3 UnpackNormalOctEncode(real2 f)
real3 UnpackNormalOctQuadEncode(real2 f)
{
real3 n = real3(f.x, f.y, 1.0 - abs(f.x) - abs(f.y));

68
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


}
// Assume bsdfData.normalWS is init
void FillMaterialAnisotropy(float anisotropy, float3 tangentWS, inout BSDFData bsdfData)
void FillMaterialAnisotropy(float anisotropy, float3 tangentWS, float3 bitangentWS, inout BSDFData bsdfData)
bsdfData.anisotropy = anisotropy;
bsdfData.tangentWS = tangentWS;
bsdfData.bitangentWS = cross(bsdfData.normalWS, bsdfData.tangentWS);
bsdfData.anisotropy = anisotropy;
bsdfData.tangentWS = tangentWS;
bsdfData.bitangentWS = bitangentWS;
}
void FillMaterialIridescence(float thicknessIrid, inout BSDFData bsdfData)

if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_ANISOTROPY))
{
FillMaterialAnisotropy(surfaceData.anisotropy, surfaceData.tangentWS, bsdfData);
FillMaterialAnisotropy(surfaceData.anisotropy, surfaceData.tangentWS, cross(surfaceData.normalWS, surfaceData.tangentWS), bsdfData);
}
if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_IRIDESCENCE))

// We store perceptualRoughness instead of roughness because it save a sqrt ALU when decoding
// (as we want both perceptualRoughness and roughness for the lighting due to Disney Diffuse model)
// Encode normal on 20bit with oct compression + 2bit of sign
float2 octNormalWS = PackNormalOctEncode(surfaceData.normalWS);
float2 octNormalWS = PackNormalOctRectEncode(surfaceData.normalWS);
// Store octNormalSign on two bits with perceptualRoughness
outGBuffer1 = float4(abs(octNormalWS), PackFloatInt10bit(PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness), octNormalSign, 4.0), 0.0);
outGBuffer1 = float4(PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness), abs(octNormalWS), PackInt(octNormalSign, 2));
// RT2 - 8:8:8:8
// mettalic will be store on 4 bit and store special value when not used

}
else if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_ANISOTROPY))
{
// Encode tangent on 16bit with oct compression
float2 octTangentWS = PackNormalOctEncode(surfaceData.tangentWS);
outGBuffer2.rgb = float3(octTangentWS * 0.5 + 0.5, surfaceData.anisotropy * 0.5 + 0.5);
// Reconstruct the default tangent frame.
float3x3 frame = GetLocalFrame(surfaceData.normalWS);
// Compute the rotation angle of the actual tangent frame with respect to the default one.
float sinFrame = dot(surfaceData.tangentWS, frame[1]);
float cosFrame = dot(surfaceData.tangentWS, frame[0]);
uint storeSin = abs(sinFrame) < abs(cosFrame) ? 4 : 0;
uint quadrant = ((sinFrame < 0) ? 1 : 0) | ((cosFrame < 0) ? 2 : 0);
outGBuffer2.rgb = float3(min(abs(sinFrame), abs(cosFrame)) * sqrt(2), PackByte(storeSin | quadrant), surfaceData.anisotropy * 0.5 + 0.5);
}
else if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_IRIDESCENCE))
{

// Start decompressing GBuffer
float3 baseColor = inGBuffer0.rgb;
bsdfData.specularOcclusion = inGBuffer0.a;
bsdfData.specularOcclusion = inGBuffer0.a;
bsdfData.perceptualRoughness = inGBuffer1.r;
int octNormalSign;
UnpackFloatInt10bit(inGBuffer1.b, 4.0, bsdfData.perceptualRoughness, octNormalSign);
inGBuffer1.r = (octNormalSign & 1) ? -inGBuffer1.r : inGBuffer1.r;
inGBuffer1.g = (octNormalSign & 2) ? -inGBuffer1.g : inGBuffer1.g;
float2 octNormalWS = inGBuffer1.gb;
uint octNormalSign = UnpackInt(inGBuffer1.a, 2);
bsdfData.normalWS = UnpackNormalOctEncode(float2(inGBuffer1.r, inGBuffer1.g));
octNormalWS.x = (octNormalSign & 1) ? -octNormalWS.x : octNormalWS.x;
octNormalWS.y = (octNormalSign & 2) ? -octNormalWS.y : octNormalWS.y;
bsdfData.normalWS = UnpackNormalOctRectEncode(octNormalWS);
// metallic15 is range [0..12] if metallic data is needed
bool pixelHasNoMetallic = HasFeatureFlag(pixelFeatureFlags, MATERIALFEATUREFLAGS_LIT_SPECULAR_COLOR | MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING | MATERIALFEATUREFLAGS_LIT_TRANSMISSION);

// Note that it mean that when we have the worse case, we always use Anisotropy and shader like deferred.shader are always the worst case (but only used for debugging)
if (HasFeatureFlag(tileFeatureFlags, MATERIALFEATUREFLAGS_LIT_ANISOTROPY))
{
float anisotropy;
float3 tangentWS;
float anisotropy = 0;
float3x3 frame = GetLocalFrame(bsdfData.normalWS);
tangentWS = UnpackNormalOctEncode(inGBuffer2.rg * 2.0 - 1.0);
}
else
{
anisotropy = 0.0;
tangentWS = GetLocalFrame(bsdfData.normalWS)[0];
// Get the rotation angle of the actual tangent frame with respect to the default one.
uint quadrant = UnpackByte(inGBuffer2.g);
uint storeSin = UnpackByte(inGBuffer2.g) & 4;
float absVal0 = inGBuffer2.r * rsqrt(2);
float absVal1 = sqrt(1 - absVal0 * absVal0);
float sinFrame = storeSin ? absVal0 : absVal1;
float cosFrame = storeSin ? absVal1 : absVal0;
sinFrame = (quadrant & 1) ? -sinFrame : sinFrame;
cosFrame = (quadrant & 2) ? -cosFrame : cosFrame;
// Rotate the reconstructed tangent around the normal.
frame[0] = sinFrame * frame[1] + cosFrame * frame[0];
frame[1] = cross(frame[2], frame[0]);
FillMaterialAnisotropy(anisotropy, tangentWS, bsdfData);
FillMaterialAnisotropy(anisotropy, frame[0], frame[1], bsdfData);
}
if (HasFeatureFlag(pixelFeatureFlags, MATERIALFEATUREFLAGS_LIT_IRIDESCENCE))

32
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/QuaternionMath.hlsl


#ifndef UNITY_QUATERNIONMATH_INCLUDED
#define UNITY_QUATERNIONMATH_INCLUDED
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
real4 TangentSpaceToQuat(real3 tagent, real3 bitangent, real3 normal)
{
real4 quat;
quat.x = normal.y - bitangent.z;
quat.y = tangent.z - normal.x;
quat.z = bitangent.x - tangent.y;
quat.w = 1.0 + tangent.x + bitangent.y + normal.z;
return normalize(quat);
}
void QuatToTangentSpace(real4 quaterion, out real3 tangent, out real3 bitangent, out real3 normal)
{
tangent = real3(1.0, 0.0, 0.0)
+ real3(-2.0, 2.0, 2.0) * quat.y * quat.yxw
+ real3(-2.0, -2.0, 2.0) * quat.z * quaternion.zwx;
bitangent = real3(0.0, 1.0, 0.0)
+ real3(2.0, -2.0, 2.0) * quat.z * quat.wzy
+ real3(2.0, -2.0, -2.0) * quat.x * quaternion.yxw;
normal = real3(0.0, 0.0, 1.0)
+ real3(2.0, 2.0, -2.0) * quat.x * quat.zwx
+ real3(-2.0, 2.0, -2.0) * quat.y * quaternion.wzy;
}
#endif // UNITY_QUATERNIONMATH_INCLUDED

8
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/QuaternionMath.hlsl.meta


fileFormatVersion: 2
guid: 28991169f6e68314ab20d6a0e4aeccec
timeCreated: 1472140530
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存