浏览代码

- Added the possibility for material layers to inherit from the base layer normal map.

- Changed the way normal are handled in Lit/LayeredLit shader so that we could properly implement the point above (namely, GetSurfaceData now returns the tangent space normal instead of world space directly, this allows to blend them correctly for layered shader).
/main
Julien Ignace 8 年前
当前提交
9613bb46
共有 8 个文件被更改,包括 126 次插入73 次删除
  1. 30
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs
  2. 65
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitData.hlsl
  3. 3
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitProperties.hlsl
  4. 37
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitSurfaceData.hlsl
  5. 16
      Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl
  6. 2
      Assets/TestScenes/HDTest/LayeredLitTest.unity
  7. 35
      Assets/TestScenes/HDTest/LayeredLitTest/Material/Layered_HeightBased.mat
  8. 11
      Assets/TestScenes/HDTest/LayeredLitTest/Material/Lit_White.mat

30
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs


{
public readonly GUIContent[] layerLabels =
{
new GUIContent("Layer 0"),
new GUIContent("Base Layer"),
};
public readonly GUIStyle[] layerLabelColors =
{
new GUIStyle(EditorStyles.label),
new GUIStyle(EditorStyles.label),
new GUIStyle(EditorStyles.label),
new GUIStyle(EditorStyles.label)
};
public readonly GUIContent materialLayerText = new GUIContent("Material");

public readonly GUIContent UVBaseText = new GUIContent("Base UV Mapping", "Base UV Mapping mode of the layer.");
public readonly GUIContent UVDetailText = new GUIContent("Detail UV Mapping", "Detail UV Mapping mode of the layer.");
public readonly GUIContent useHeightBasedBlendText = new GUIContent("Use Height Based Blend", "Layer will be blended with the underlying layer based on the height.");
public readonly GUIContent heightOffsetText = new GUIContent("HeightOffset", "Height offset from the previous layer.");
public readonly GUIContent heightOffsetText = new GUIContent("Height Offset", "Height offset from the previous layer.");
public readonly GUIContent inheritBaseLayerText = new GUIContent("Inherit Base Layer Normal", "Inherit the normal from the base layer.");
public StylesLayer()
{
layerLabelColors[1].normal.textColor = Color.red;
layerLabelColors[2].normal.textColor = Color.green;
layerLabelColors[3].normal.textColor = Color.blue;
}
}
static StylesLayer s_Styles = null;

MaterialProperty useHeightBasedBlend = null;
const string kHeightOffset = "_HeightOffset";
MaterialProperty[] heightOffset = new MaterialProperty[kMaxLayerCount-1];
const string kInheritBaseLayer = "_InheritBaseLayer";
MaterialProperty[] inheritBaseLayer = new MaterialProperty[kMaxLayerCount - 1];
const string kHeightFactor = "_HeightFactor";
MaterialProperty[] heightFactor = new MaterialProperty[kMaxLayerCount-1];
const string kBlendSize = "_BlendSize";

if(i != 0)
{
inheritBaseLayer[i - 1] = FindProperty(string.Format("{0}{1}", kInheritBaseLayer, i), props);
heightOffset[i-1] = FindProperty(string.Format("{0}{1}", kHeightOffset, i), props);
heightFactor[i-1] = FindProperty(string.Format("{0}{1}", kHeightFactor, i), props);
blendSize[i-1] = FindProperty(string.Format("{0}{1}", kBlendSize, i), props);

Material material = m_MaterialEditor.target as Material;
EditorGUILayout.LabelField(styles.layerLabels[layerIndex]);
EditorGUILayout.LabelField(styles.layerLabels[layerIndex], styles.layerLabelColors[layerIndex]);
EditorGUI.indentLevel++;

{
int heightParamIndex = layerIndex - 1;
m_MaterialEditor.ShaderProperty(inheritBaseLayer[heightParamIndex], styles.inheritBaseLayerText);
m_MaterialEditor.ShaderProperty(heightOffset[heightParamIndex], styles.heightOffsetText);
m_MaterialEditor.ShaderProperty(heightFactor[heightParamIndex], styles.heightFactorText);
m_MaterialEditor.ShaderProperty(blendSize[heightParamIndex], styles.blendSizeText);

EditorGUI.indentLevel--;
if(layerIndex == 0)
EditorGUILayout.Space();
return result;
}

65
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitData.hlsl


ApplyDepthOffsetAttribute(depthOffset, input);
#endif
float alpha = GetSurfaceData(input, layerTexCoord, surfaceData);
float3 normalTS;
float alpha = GetSurfaceData(input, layerTexCoord, surfaceData, normalTS);
surfaceData.normalWS = TransformTangentToWorld(normalTS, input.tangentToWorld);
}
#else

outWeights[0] = left;
}
float3 BlendLayeredColor(float3 rgb0, float3 rgb1, float3 rgb2, float3 rgb3, float weight[4])
float3 BlendLayeredFloat3(float3 x0, float3 x1, float3 x2, float3 x3, float weight[4])
result = rgb0 * weight[0] + rgb1 * weight[1];
result = x0 * weight[0] + x1 * weight[1];
result += (rgb2 * weight[2]);
result += (x2 * weight[2]);
result += rgb3 * weight[3];
result += x3 * weight[3];
float3 BlendLayeredNormal(float3 normal0, float3 normal1, float3 normal2, float3 normal3, float weight[4])
{
float3 result = float3(0.0, 0.0, 0.0);
result = normal0 * weight[0] + normal1 * weight[1];
#if _LAYER_COUNT >= 3
result += normal2 * weight[2];
#endif
#if _LAYER_COUNT >= 4
result += normal3 * weight[3];
#endif
return normalize(result);
}
float BlendLayeredScalar(float x0, float x1, float x2, float x3, float weight[4])
{
float result = 0.0;

}
#define SURFACEDATA_BLEND_COLOR(surfaceData, name, mask) BlendLayeredColor(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define SURFACEDATA_BLEND_NORMAL(surfaceData, name, mask) BlendLayeredNormal(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define SURFACEDATA_BLEND_COLOR(surfaceData, name, mask) BlendLayeredFloat3(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define SURFACEDATA_BLEND_SCALAR(surfaceData, name, mask) BlendLayeredScalar(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define PROP_BLEND_SCALAR(name, mask) BlendLayeredScalar(name##0, name##1, name##2, name##3, mask);

SurfaceData surfaceData1;
SurfaceData surfaceData2;
SurfaceData surfaceData3;
float alpha0 = GetSurfaceData0(input, layerTexCoord, surfaceData0);
float alpha1 = GetSurfaceData1(input, layerTexCoord, surfaceData1);
float alpha2 = GetSurfaceData2(input, layerTexCoord, surfaceData2);
float alpha3 = GetSurfaceData3(input, layerTexCoord, surfaceData3);
float3 normalTS0;
float3 normalTS1;
float3 normalTS2;
float3 normalTS3;
float alpha0 = GetSurfaceData0(input, layerTexCoord, surfaceData0, normalTS0);
float alpha1 = GetSurfaceData1(input, layerTexCoord, surfaceData1, normalTS1);
float alpha2 = GetSurfaceData2(input, layerTexCoord, surfaceData2, normalTS2);
float alpha3 = GetSurfaceData3(input, layerTexCoord, surfaceData3, normalTS3);
// Mask Values : Layer 1, 2, 3 are r, g, b
float3 maskValues = SAMPLE_TEXTURE2D(_LayerMaskMap, sampler_LayerMaskMap, input.texCoord0).rgb;

surfaceData.baseColor = SURFACEDATA_BLEND_COLOR(surfaceData, baseColor, weights);
surfaceData.specularOcclusion = SURFACEDATA_BLEND_SCALAR(surfaceData, specularOcclusion, weights);
// Note: for normal map (in tangent space) it is possible to have better performance
// by blending in tangent space then transform to world and apply flip.
// Sadly this require a specific path (without taking into account that there is detail normal map)
// mean it add an extra cost of maintenance. We chose to not do this optimization in favor
// of simpler code and in the future will rely on shader graph to create optimize code.
surfaceData.normalWS = SURFACEDATA_BLEND_NORMAL(surfaceData, normalWS, weights);
float3 normalTS;
#if defined(_HEIGHT_BASED_BLEND)
float _InheritBaseLayer0 = 1.0f; // Default value for lerp when all weights but base layer are zero.
// Compute the combined inheritance factor of layers 1,2 and 3
float inheritFactor = PROP_BLEND_SCALAR(_InheritBaseLayer, weights);
float3 vertexNormalTS = float3(0.0, 0.0, 1.0);
// The idea here is to lerp toward vertex normal. This way when we don't want to inherit, we will combine layer 1/2/3 normal with a vertex normal which is neutral.
float3 baseLayerNormalTS = normalize(lerp(vertexNormalTS, normalTS0, inheritFactor));
// Blend layer 1/2/3 normals before combining to the base layer. Again we need to have a neutral value for base layer (vertex normal) in case all weights are zero.
float3 layersNormalTS = BlendLayeredFloat3(vertexNormalTS, normalTS1, normalTS2, normalTS3, weights);
normalTS = BlendNormal(baseLayerNormalTS, layersNormalTS);
#else
normalTS = BlendLayeredFloat3(normalTS0, normalTS1, normalTS2, normalTS3, weights);
#endif
surfaceData.normalWS = TransformTangentToWorld(normalTS, input.tangentToWorld);
// Init other unused parameter
surfaceData.materialId = 0;

3
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitProperties.hlsl


float _BlendSize2;
float _BlendSize3;
float _VertexColorHeightFactor;
float _InheritBaseLayer1;
float _InheritBaseLayer2;
float _InheritBaseLayer3;
float3 _EmissiveColor;
TEXTURE2D(_EmissiveColorMap);

37
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/LitSurfaceData.hlsl


}
// Return opacity
float ADD_IDX(GetSurfaceData)(FragInputs input, LayerTexCoord layerTexCoord, out SurfaceData surfaceData)
float ADD_IDX(GetSurfaceData)(FragInputs input, LayerTexCoord layerTexCoord, out SurfaceData surfaceData, out float3 normalTS)
{
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
float alpha = ADD_IDX(_BaseColor).a;

//surfaceData.specularOcclusion *= surfaceData.specularOcclusion;
surfaceData.specularOcclusion = 1.0;
#endif
surfaceData.normalWS = float3(0.0, 0.0, 0.0); // Need to init this so that the compiler leaves us alone.
#ifdef _NORMALMAP_TANGENT_SPACE
float3 normalTS = SAMPLE_LAYER_NORMALMAP(ADD_IDX(_NormalMap), ADD_ZERO_IDX(sampler_NormalMap), ADD_IDX(layerTexCoord.base));
#ifdef _DETAIL_MAP
normalTS = lerp(normalTS, BlendNormal(normalTS, detailNormalTS), detailMask);
#endif
surfaceData.normalWS = TransformTangentToWorld(normalTS, input.tangentToWorld);
#else // Object space
#ifdef _NORMALMAP_TANGENT_SPACE
normalTS = SAMPLE_LAYER_NORMALMAP(ADD_IDX(_NormalMap), ADD_ZERO_IDX(sampler_NormalMap), ADD_IDX(layerTexCoord.base));
#else // Object space
float3 normalOS = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_NormalMap), ADD_ZERO_IDX(sampler_NormalMap), ADD_IDX(layerTexCoord.base)).rgb;
surfaceData.normalWS = TransformObjectToWorldDir(normalOS);
#ifdef _DETAIL_MAP
float3 detailNormalWS = TransformTangentToWorld(detailNormalTS, input.tangentToWorld);
surfaceData.normalWS = lerp(surfaceData.normalWS, BlendNormal(surfaceData.normalWS, detailNormalWS), detailMask);
#endif
float3 normalOS = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_NormalMap), ADD_ZERO_IDX(sampler_NormalMap), ADD_IDX(layerTexCoord.base)).rgb * 2.0 - 1.0;
normalTS = TransformObjectToTangent(normalOS, input.tangentToWorld);
#endif
#ifdef _DETAIL_MAP
normalTS = lerp(normalTS, BlendNormalRNM(normalTS, detailNormalTS), detailMask);
surfaceData.normalWS = vertexNormalWS;
normalTS = float3(0.0, 0.0, 1.0);
float3 oppositeNormalWS = -surfaceData.normalWS;
float3 oppositeNormalTS = -normalTS;
float3 oppositeNormalWS = reflect(surfaceData.normalWS, vertexNormalWS);
float3 oppositeNormalTS = reflect(normalTS, vertexNormalWS);
surfaceData.normalWS = input.isFrontFace ?
(GetOdddNegativeScale() >= 0.0 ? surfaceData.normalWS : oppositeNormalWS) :
(-GetOdddNegativeScale() >= 0.0 ? surfaceData.normalWS : oppositeNormalWS);
normalTS = input.isFrontFace ?
(GetOdddNegativeScale() >= 0.0 ? normalTS : oppositeNormalTS) :
(-GetOdddNegativeScale() >= 0.0 ? normalTS : oppositeNormalTS);
#endif
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A

16
Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl


return normalize(mul(float3x3(tangentToWorld[0].xyz, tangentToWorld[1].xyz, tangentToWorld[2].xyz), dirWS));
}
float3 TransformTangentToObject(float3 dirTS, float3 worldToTangent[3])
{
// TODO check: do we need to normalize ?
// worldToTangent is orthonormal so inverse <==> transpose
float3x3 mWorldToTangent = float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz);
float3 normalWS = mul(dirTS, mWorldToTangent);
return normalize(mul((float3x3)unity_WorldToObject, normalWS));
}
// Assume TBN is orthonormal.
float3 TransformObjectToTangent(float3 dirOS, float3 worldToTangent[3])
{
// TODO check: do we need to normalize ?
//return normalize(mul(float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz), mul((float3x3)unity_ObjectToWorld, dirOS)));
return normalize(mul(float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz), mul((float3x3)unity_WorldToObject, dirOS)));
}
#endif // UNITY_SHADER_VARIABLES_INCLUDED

2
Assets/TestScenes/HDTest/LayeredLitTest.unity


m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 112888599}
m_LocalRotation: {x: 0.4442191, y: -0, z: -0, w: 0.8959182}
m_LocalPosition: {x: -41.74, y: -1.55, z: 8.82}
m_LocalPosition: {x: -41.31, y: -1.55, z: 13.03}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1732353142}

35
Assets/TestScenes/HDTest/LayeredLitTest/Material/Layered_HeightBased.mat


- _HeightScale1: 0.1
- _HeightScale2: 0.05
- _HeightScale3: 0.06
- _InheritBaseLayer1: 1
- _InheritBaseLayer2: 1
- _InheritBaseLayer3: 1
- _LayerCount: 4
- _LayerMaskVertexColor: 0
- _Metallic: 0

- _SpecularHighlights: 1
- _SrcBlend: 1
- _SurfaceType: 0
- _TexWorldScale0: 1
- _TexWorldScale1: 1
- _TexWorldScale2: 1
- _TexWorldScale3: 1
- _UVBase0: 0
- _UVBase1: 0
- _UVBase2: 0
- _UVBase3: 0
- _TexWorldScale0: 0.1
- _TexWorldScale1: 0.1
- _TexWorldScale2: 0.1
- _TexWorldScale3: 0.1
- _UVBase0: 4
- _UVBase1: 4
- _UVBase2: 4
- _UVBase3: 4
- _UVMappingPlanar0: 0
- _UVMappingPlanar1: 0
- _UVMappingPlanar2: 0
- _UVMappingPlanar3: 0
- _UVMappingPlanar0: 1
- _UVMappingPlanar1: 1
- _UVMappingPlanar2: 1
- _UVMappingPlanar3: 1
- _UVSec: 0
- _UseHeightBasedBlend: 1
- _UseHeightBasedBlend1: 1

- _UVDetailsMappingMask1: {r: 1, g: 0, b: 0, a: 0}
- _UVDetailsMappingMask2: {r: 1, g: 0, b: 0, a: 0}
- _UVDetailsMappingMask3: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask0: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask1: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask2: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask3: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask0: {r: 0, g: 0, b: 0, a: 0}
- _UVMappingMask1: {r: 0, g: 0, b: 0, a: 0}
- _UVMappingMask2: {r: 0, g: 0, b: 0, a: 0}
- _UVMappingMask3: {r: 0, g: 0, b: 0, a: 0}

11
Assets/TestScenes/HDTest/LayeredLitTest/Material/Lit_White.mat


m_LightmapFlags: 1
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
disabledShaderPasses:
- DistortionVectors
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:

m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DistortionVectorMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}

- _BumpScale: 1
- _CullMode: 2
- _Cutoff: 0.5
- _DepthOffsetEnable: 0
- _DetailAOScale: 1
- _DetailAlbedoScale: 1
- _DetailHeightScale: 1

- _DetailSmoothnessScale: 1
- _DistortionDepthTest: 0
- _DistortionEnable: 0
- _DistortionOnly: 0
- _DoubleSidedMode: 0
- _DstBlend: 0

- _TexWorldScale: 1
- _UVBase: 0
- _UVDetail: 0
- _UVMappingPlanar: 0
- _ZTestMode: 8
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}

正在加载...
取消
保存