浏览代码

HDRenderPipeline: Some rename and cleanup + add few surface gradient define case

Apply WorldToTangent name even with surface gradient
/Branch_Batching2
Sebastien Lagarde 7 年前
当前提交
f1b63cc8
共有 7 个文件被更改,包括 104 次插入106 次删除
  1. 37
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  2. 37
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl
  3. 12
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/MaterialUtilities.hlsl
  4. 19
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl
  5. 77
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/VaryingMesh.hlsl
  6. 20
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl
  7. 8
      Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl

37
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


#ifdef _DOUBLESIDED_ON
// _DoubleSidedConstants is float3(-1, -1, -1) in flip mode and float3(1, 1, -1) in mirror mode
float flipSign = input.isFrontFace ? 1.0 : _DoubleSidedConstants.x; // TOCHECK : GetOddNegativeScale() is not necessary here as it is apply for tangent space creation.
#ifdef SURFACE_GRADIENT
input.vtxNormalWS = flipSign * input.vtxNormalWS;
input.mikktsBino = flipSign * input.mikktsBino;
// TOCHECK: seems that we don't need to invert any genBasisTB(), sign cancel. Which is expected as we deal with surface gradient.
#else
#ifdef SURFACE_GRADIENT
// TOCHECK: seems that we don't need to invert any genBasisTB(), sign cancel. Which is expected as we deal with surface gradient.
#endif
#endif
}

{
ppdParam.uv = layerTexCoord.base.uv;
#ifdef SURFACE_GRADIENT
// The TBN is not normalize, normalize it to do per pixel displacement
float3x3 worldToTangent = input.worldToTangent;
worldToTangent[1] = normalize(worldToTangent[1]);
worldToTangent[2] = normalize(worldToTangent[2]);
#else
float3x3 worldToTangent = input.worldToTangent;
#endif
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, input.worldToTangent);
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, worldToTangent);
int numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);

ppdParam.uv[2] = layerTexCoord.base2.uv;
ppdParam.uv[3] = layerTexCoord.base3.uv;
#ifdef SURFACE_GRADIENT
// The TBN is not normalize, normalize it to do per pixel displacement
float3x3 worldToTangent = input.worldToTangent;
worldToTangent[1] = normalize(worldToTangent[1]);
worldToTangent[2] = normalize(worldToTangent[2]);
#else
float3x3 worldToTangent = input.worldToTangent;
#endif
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, input.worldToTangent);
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, worldToTangent);
int numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);

surfaceData.perceptualSmoothness = SURFACEDATA_BLEND_SCALAR(surfaceData, perceptualSmoothness, weights);
surfaceData.ambientOcclusion = SURFACEDATA_BLEND_SCALAR(surfaceData, ambientOcclusion, weights);
surfaceData.metallic = SURFACEDATA_BLEND_SCALAR(surfaceData, metallic, weights);
// Init other unused parameter
#ifdef SURFACE_GRADIENT
surfaceData.tangentWS = normalize(input.worldToTangent[0].xyz); // The tangent is not normalize in worldToTangent when using surface gradient
#else
#endif
// Init other parameters
surfaceData.materialId = 0;
surfaceData.anisotropy = 0;
surfaceData.specular = 0.04;

37
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl


// /We need to decompress the normal ourselve here as UnpackNormalRGB will return a surface gradient
float3 normalOS = SAMPLE_TEXTURE2D_BIAS(layerTex, SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv, bias).xyz * 2.0 - 1.0;
// normalize(normalOS) // TO CHECK: surfgradFromPerturbedNormal doesn't require normalOS to be normalize, to check
normalTS = surfgradFromPerturbedNormal(input.vtxNormalWS, normalOS);
normalTS = surfgradFromPerturbedNormal(input.worldToTangent[2], normalOS);
normalTS *= ADD_IDX(_NormalScale);
#else
float3 normalOS = UnpackNormalRGB(SAMPLE_TEXTURE2D_BIAS(layerTex, SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv, bias), 1.0);

// /We need to decompress the normal ourselve here as UnpackNormalRGB will return a surface gradient
float3 normalOS = SAMPLE_TEXTURE2D(layerTex, SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv).xyz * 2.0 - 1.0;
// normalize(normalOS) // TO CHECK: surfgradFromPerturbedNormal doesn't require normalOS to be normalize, to check
normalTS = surfgradFromPerturbedNormal(input.vtxNormalWS, normalOS);
normalTS = surfgradFromPerturbedNormal(input.worldToTangent[2], normalOS);
normalTS *= ADD_IDX(_NormalScale);
#else
float3 normalOS = UnpackNormalRGB(SAMPLE_TEXTURE2D(layerTex, SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv), 1.0);

// TODO: think about using BC5
#ifdef _TANGENTMAP
#ifdef _NORMALMAP_TANGENT_SPACE_IDX // Normal and tangent use same space
float3 tangentTS = SAMPLE_LAYER_NORMALMAP(ADD_IDX(_TangentMap), ADD_ZERO_IDX(sampler_TangentMap), ADD_IDX(layerTexCoord.base), 1.0);
#ifdef _NORMALMAP_TANGENT_SPACE_IDX // Normal and tangent use same space
float3 tangentTS = SAMPLE_LAYER_NORMALMAP(_TangentMap, sampler_TangentMap, layerTexCoord.base, 1.0);
#else // Object space
float3 tangentOS = SAMPLE_LAYER_NORMALMAP_RGB(ADD_IDX(_TangentMap), ADD_ZERO_IDX(sampler_TangentMap), ADD_IDX(layerTexCoord.base), 1.0).rgb;
#else // Object space
// Note: There is no such a thing like triplanar with object space normal, so we call directly 2D function
float3 tangentOS = UnpackNormalRGB(SAMPLE_TEXTURE2D(_TangentMap, sampler_TangentMap, layerTexCoord.base.uv), 1.0);
#endif
#endif
#ifdef SURFACE_GRADIENT
surfaceData.tangentWS = normalize(input.worldToTangent[0].xyz); // The tangent is not normalize in worldToTangent when using surface gradient
#else
#endif
// TODO: Is there anything todo regarding flip normal but for the tangent ?
surfaceData.anisotropy = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_AnisotropyMap), ADD_ZERO_IDX(sampler_AnisotropyMap), ADD_IDX(layerTexCoord.base)).b;
surfaceData.anisotropy = SAMPLE_LAYER_TEXTURE2D(_AnisotropyMap, sampler_AnisotropyMap, layerTexCoord.base).b;
#else
surfaceData.anisotropy = 1.0;
#endif

surfaceData.subsurfaceProfile = _SubsurfaceProfile;
#ifdef _SUBSURFACE_RADIUS_MAP
surfaceData.subsurfaceRadius = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_SubsurfaceRadiusMap), ADD_ZERO_IDX(sampler_SubsurfaceRadiusMap), ADD_IDX(layerTexCoord.base)).r * _SubsurfaceRadius;
surfaceData.subsurfaceRadius = SAMPLE_LAYER_TEXTURE2D(_SubsurfaceRadiusMap, sampler_SubsurfaceRadiusMap, layerTexCoord.base).r * _SubsurfaceRadius;
surfaceData.thickness = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_ThicknessMap), ADD_ZERO_IDX(sampler_ThicknessMap), ADD_IDX(layerTexCoord.base)).r;
surfaceData.thickness = SAMPLE_LAYER_TEXTURE2D(_ThicknessMap, sampler_ThicknessMap, layerTexCoord.base).r;
#else
surfaceData.thickness = _Thickness;
#endif

// Layered shader only support materialId 0
surfaceData.materialId = 0;
surfaceData.tangentWS = input.worldToTangent[0].xyz;
surfaceData.anisotropy = 0;
surfaceData.specular = 0.04;
// All these parameters are ignore as they are re-setup outside of the layers function
surfaceData.tangentWS = float3(0.0, 0.0, 0.0);
surfaceData.anisotropy = 0.0;
surfaceData.specular = 0.0;
surfaceData.subsurfaceRadius = 1.0;
surfaceData.subsurfaceRadius = 0.0;
surfaceData.coatPerceptualSmoothness = 1.0;
surfaceData.coatPerceptualSmoothness = 0.0;
surfaceData.specularColor = float3(0.0, 0.0, 0.0);
#endif // #if !defined(LAYERED_LIT_SHADER)

12
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/MaterialUtilities.hlsl


}
// This function convert the tangent space normal/tangent to world space and orthonormalize it + apply a correction of the normal if it is not pointing towards the near plane
void GetNormalAndTangentWS(FragInputs input, float3 V, float3 normalTS, inout float3 normalWS, inout float3 tangentWS, bool twoSided = false)
void GetNormalAndTangentWS(FragInputs input, float3 V, float3 normalTS, inout float3 normalWS, inout float3 tangentWS, bool wantNegativeNormal = false)
normalWS = resolveNormalFromSurfaceGradient(input.vtxNormalWS, normalTS);
normalWS = resolveNormalFromSurfaceGradient(input.worldToTangent[2], normalTS);
// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting
// This will potentially reduce the length of the normal at edges of geometry.
GetShiftedNdotV(normalWS, V, twoSided);
GetShiftedNdotV(normalWS, V, wantNegativeNormal);
// This is use with anisotropic material
tangentWS = normalize(tangentWS - dot(tangentWS, normalWS));
}

19
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl


float2 texCoord3;
float4 color; // vertex color
#ifdef SURFACE_GRADIENT
// Various tangent space for all UVSet
// used for vertex level tangent space only (support on UV set 0 only)
float3 vtxNormalWS;
float3 mikktsTang;
float3 mikktsBino;
// Use for the 3 other UVSet;
float3 vT1, vB1;
float3 vT2, vB2;
float3 vT3, vB3;
#else
float3 worldToTangent[3]; // These 3 vectors are normalized (no need for the material to normalize) and these are only for UVSet 0
#endif
// When using worldToTangent with surface gradient, it doesn't normalize the tangent/bitangent vector (We instead use exact same scale as applied to interpolated vertex normal to avoid breaking compliance).
// this mean that any usage of worldToTangent[1] or worldToTangent[2] outside of the context of normal map (like for POM) must normalize the TBN (TCHECK if this make any difference ?)
// When not using surface gradient, each vector of worldToTangent are normalize (TODO: Maybe they should not even in case of no surface gradient ? Ask Morten)
float3x3 worldToTangent;
// For two sided lighting
bool isFrontFace;

FragInputs output;
ZERO_INITIALIZE(FragInputs, output);
// Init to some default value to make the computer quiet (else it output "divide by zero" warning even if value is not used).
output.worldToTangent[0] = float3(0.0, 0.0, 1.0);
output.worldToTangent[2] = float3(0.0, 0.0, 1.0);

77
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/VaryingMesh.hlsl


output.positionWS.xyz = input.interpolators0.xyz;
#endif
#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
float4 tangentWS = float4(input.interpolators2.xyz, input.interpolators2.w > 0.0 ? 1.0 : -1.0);
// TODO: We should be able to not make distinction between the two path, but it mean material need to be aware to normalize the TBN when required, like for example for POM.
// For now do some test by keeping code consistent with previous visual.
#ifdef SURFACE_GRADIENT
// Normalize normalWS vector but keep the renormFactor to apply it to bitangent and tangent
float renormFactor = 1.0 / length(input.interpolators1);
float3 normalWS = renormFactor * input.interpolators1;
// no normalizes is mandatory for tangentWS
// bitangent on the fly option in xnormal to reduce vertex shader outputs.
float3x3 worldToTangent = CreateWorldToTangent(normalWS, tangentWS.xyz, tangentWS.w);
output.worldToTangent[0] = worldToTangent[0];
// prepare for surfgrad formulation without breaking compliance (use exact same scale as applied to interpolated vertex normal to avoid breaking compliance).
output.worldToTangent[1] = worldToTangent[1] * renormFactor;
output.worldToTangent[2] = worldToTangent[2] * renormFactor;
#else
// TODO: Check if we must do like for surface gradient (i.e not normalize ?) For now, for consistency with previous code we normalize
// Normalize after the interpolation
float3 normalWS = normalize(input.interpolators1);
tangentWS.xyz = normalize(tangentWS.xyz);
// bitangent on the fly option in xnormal to reduce vertex shader outputs.
float3x3 worldToTangent = CreateWorldToTangent(normalWS, tangentWS.xyz, tangentWS.w);
output.worldToTangent[0] = worldToTangent[0];
output.worldToTangent[1] = worldToTangent[1];
output.worldToTangent[2] = worldToTangent[2];
#endif
#endif // VARYINGS_NEED_TANGENT_TO_WORLD
#ifdef VARYINGS_NEED_TEXCOORD0
output.texCoord0 = input.interpolators3.xy;
#endif

#if defined(VARYINGS_NEED_CULLFACE) && SHADER_STAGE_FRAGMENT
output.isFrontFace = IS_FRONT_VFACE(input.cullFace, true, false);
#endif
#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
#ifdef SURFACE_GRADIENT
// Caution: We assume that tangent space are always use in a context where positionWS is availble.
// Which is true in our framework. When positionWS is 0 it mean we are in a deffered or compute pass which don't use our tangent space (so code will be remove by the compiler)
// TODO: We should use relative camera position here - This will be automatic when we will move to camera relative space.
float3 dPdx = ddx_fine(output.positionWS.xyz);
float3 dPdy = ddy_fine(output.positionWS.xyz);
float renormFactor = 1.0 / length(input.interpolators1);
float3 nrmVertexNormal = renormFactor * input.interpolators1;
float3 sigmaX = dPdx - dot(dPdx, nrmVertexNormal) * nrmVertexNormal;
float3 sigmaY = dPdy - dot(dPdy, nrmVertexNormal) * nrmVertexNormal;
//float flip_sign = dot(sigmaY, cross(nrmVertexNormal, sigmaX) ) ? -1 : 1;
float flipSign = dot(dPdy, cross(nrmVertexNormal, dPdx)) < 0 ? -1 : 1; // gives same as the commented out line above
output.vtxNormalWS = nrmVertexNormal;
// mikkts for conventional vertex level tspace (no normalizes is mandatory)
output.mikktsTang = input.interpolators2.xyz;
// bitangent on the fly option in xnormal to reduce vertex shader outputs. Also described in https://wiki.blender.org/index.php/Dev:Shading/Tangent_Space_Normal_Maps
output.mikktsBino = (input.interpolators2.w > 0.0 ? 1.0 : -1.0) * GetOddNegativeScale() * cross(input.interpolators1, input.interpolators2.xyz); // TODO: use CreateWorldToTangent instead once we clean code
// prepare for surfgrad formulation without breaking compliance (use exact same scale as applied to interpolated vertex normal to avoid breaking compliance).
output.mikktsTang *= renormFactor;
output.mikktsBino *= renormFactor;
#ifdef VARYINGS_NEED_TEXCOORD1
genBasisTB(nrmVertexNormal, sigmaX, sigmaY, flipSign, output.vT1, output.vB1, output.texCoord1);
#endif
#ifdef VARYINGS_NEED_TEXCOORD2
genBasisTB(nrmVertexNormal, sigmaX, sigmaY, flipSign, output.vT2, output.vB2, output.texCoord2);
#endif
#ifdef VARYINGS_NEED_TEXCOORD3
genBasisTB(nrmVertexNormal, sigmaX, sigmaY, flipSign, output.vT3, output.vB3, output.texCoord3);
#endif
#else
// Normalize the normal/tangent after interpolation
float3 normalWS = normalize(input.interpolators1);
float4 tangentWS = float4(normalize(input.interpolators2.xyz), input.interpolators2.w > 0.0 ? 1.0 : -1.0);
float3x3 worldToTangent = CreateWorldToTangent(normalWS, tangentWS.xyz, tangentWS.w);
output.worldToTangent[0] = worldToTangent[0];
output.worldToTangent[1] = worldToTangent[1];
output.worldToTangent[2] = worldToTangent[2];
#endif // SURFACE_GRADIENT
#endif
return output;

20
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl


return normalize(V);
}
float3x3 CreateWorldToTangent(float3 normal, float3 tangent, float tangentSign)
float3x3 CreateWorldToTangent(float3 normal, float3 tangent, float flipSign)
float sgn = tangentSign * GetOddNegativeScale();
float sgn = flipSign * GetOddNegativeScale();
float3 TransformTangentToWorld(float3 dirTS, float3 worldToTangent[3])
float3 TransformTangentToWorld(float3 dirTS, float3x3 worldToTangent)
return mul(dirTS, float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz));
return mul(dirTS, worldToTangent);
float3 TransformWorldToTangent(float3 dirWS, float3 worldToTangent[3])
float3 TransformWorldToTangent(float3 dirWS, float3x3 worldToTangent)
return mul(float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz), dirWS);
return mul(worldToTangent, dirWS);
float3 TransformTangentToObject(float3 dirTS, float3 worldToTangent[3])
float3 TransformTangentToObject(float3 dirTS, float3x3 worldToTangent)
float3 normalWS = mul(dirTS, float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz));
float3 normalWS = mul(dirTS, worldToTangent);
float3 TransformObjectToTangent(float3 dirOS, float3 worldToTangent[3])
float3 TransformObjectToTangent(float3 dirOS, float3x3 worldToTangent)
return mul(float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz), mul((float3x3)unity_ObjectToWorld, dirOS));
return mul(worldToTangent, mul((float3x3)unity_ObjectToWorld, dirOS));
}
#endif // UNITY_SHADER_VARIABLES_INCLUDED

8
Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl


// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting
// This will potentially reduce the length of the normal at edges of geometry.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting, they can use wantNegativeNormal
// This will potentially reduce the length of the normal at edges of geometry.
float GetShiftedNdotV(inout float3 N, float3 V, bool wantNegativeNormal)
if (!twoSided && NdotV < limit)
if (!wantNegativeNormal && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;

正在加载...
取消
保存