Unity2018的HDRPStandard材质分析笔记(一)

虽然都快2020了,但是项目用的是2018版本,最近要改下材质,所以分析一下18版的HDRP Standard。

暂时不考虑多层材质和曲面细分,并且项目用的是Forward管线,也暂时不分析Deffered。

Forward

直接引用的Library

先简单看看shader中直接引用的库。

Common

开头介绍了一些library编写的惯例:

  • 变量后缀
  1. WS: world space
  2. RWS: Camera-Relative world space
  3. VS: view space
  4. OS: object space
  5. CS: Homogenous clip spaces
  6. TS: tangent space
  7. TXS: texture space
  • 向量,向量总是指向外侧(为光照做准备),大写字母表示已经归一化(如果不是会加前缀un),如下:
  1. V: View vector
  2. L: Light vector
  3. N: Normal vector
  4. H: Half vector
  • 用input/output作为结构体的变量名。
  • 不要使用“in”,只使用“out”和“inout”。声明“out”的参数要放在最后。也不要使用“inline”,没什么作用。
  • 所有的uniform都要用cb传,原因是在computer shader中需要保证cb在各个kernels一致,如果是global namespace就会自动优化没有用到的uniform。
  • 需要在C#和hlsl共享结构体的定义,由于hlsl会在float4上对齐,有些变量需要填充。也因此都用float4来避免这种问题,比如不要用SetGlobalFloatArray或者SetComputeFloatParams函数,传递float数组时先转换成float4数组,并在hlsl里做下列的操作转换回float数组。
uniform float4 packedArray[3];
static float unpackedArray[12] = (float[12])packedArray;

然后是一些跨平台的工作。

最后定义了一些常用函数,有一点类似原UnityCG的功能。

Wind

风相关的属性和函数。

FragInputs

申明了varying/interpolator的结构体。附带Debug代码。

ShaderPass.cs

定义每种Pass为0 - n,是自动生成的。

LitProperties

定义属性。

ShaderVariables

定义了HDRP的属性。附带一些相关函数。

Lighting

光照、阴影、采样、区域光及IBL。

Material

AlphaBlend相关。

LightLoopDef

主要和间接光和Cluster及Tile相关。

Lit

standard主体。

LightLoop

光照。

LitSharePass

一些宏的定义。

LitData

一些宏的定义。获取UV及GetSurfaceAndBuiltinData方法。

ShaderPassForward

定义Vert和Frag。

 

Vert

在简单的了解之后,从最后ShaderPassForward中给我们的Vert和Frag来切入,来了解forword pass的整个流程。

PackedVaryingsType Vert(AttributesMesh inputMesh)
{
    VaryingsType varyingsType;
    varyingsType.vmesh = VertMesh(inputMesh);
    return PackVaryingsType(varyingsType);
}

把顶点的信息用VertMesh函数计算后储存至varyingsType.vmesh,再打包成PackedVaryingsType类型。

结构体和函数都在VertMesh.hlsl及VaryingMesh.hlsl中定义。

先看这几个结构体。

AttributesMesh

struct AttributesMesh
{
    float3 positionOS   : POSITION;
#ifdef ATTRIBUTES_NEED_NORMAL
    float3 normalOS     : NORMAL;
#endif
#ifdef ATTRIBUTES_NEED_TANGENT
    float4 tangentOS    : TANGENT; // Store sign in w
#endif
#ifdef ATTRIBUTES_NEED_TEXCOORD0
    float2 uv0          : TEXCOORD0;
#endif
#ifdef ATTRIBUTES_NEED_TEXCOORD1
    float2 uv1          : TEXCOORD1;
#endif
#ifdef ATTRIBUTES_NEED_TEXCOORD2
    float2 uv2          : TEXCOORD2;
#endif
#ifdef ATTRIBUTES_NEED_TEXCOORD3
    float2 uv3          : TEXCOORD3;
#endif
#ifdef ATTRIBUTES_NEED_COLOR
    float4 color        : COLOR;
#endif

    UNITY_VERTEX_INPUT_INSTANCE_ID
};

VaryingsType

#define VaryingsType VaryingsToPS

如果不是曲面细分,则为VaryingsToPS。

struct VaryingsToPS
{
    VaryingsMeshToPS vmesh;
#ifdef VARYINGS_NEED_PASS
    VaryingsPassToPS vpass;
#endif
};

其中VARYINGS_NEED_PASS只有在计算Motion的pass中会定义。

struct VaryingsMeshToPS
{
    float4 positionCS;
#ifdef VARYINGS_NEED_POSITION_WS
    float3 positionRWS;
#endif
#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
    float3 normalWS;
    float4 tangentWS;  // w contain mirror sign
#endif
#ifdef VARYINGS_NEED_TEXCOORD0
    float2 texCoord0;
#endif
#ifdef VARYINGS_NEED_TEXCOORD1
    float2 texCoord1;
#endif
#ifdef VARYINGS_NEED_TEXCOORD2
    float2 texCoord2;
#endif
#ifdef VARYINGS_NEED_TEXCOORD3
    float2 texCoord3;
#endif
#ifdef VARYINGS_NEED_COLOR
    float4 color;
#endif

UNITY_VERTEX_INPUT_INSTANCE_ID

};

PackedVaryingsType

#define PackedVaryingsType PackedVaryingsToPS

如果不是曲面细分,则为PackedVaryingsToPS。

struct PackedVaryingsToPS
{
#ifdef VARYINGS_NEED_PASS
    PackedVaryingsPassToPS vpass;
#endif
    PackedVaryingsMeshToPS vmesh;
};
struct PackedVaryingsMeshToPS
{
    float4 positionCS : SV_Position;

#ifdef VARYINGS_NEED_POSITION_WS
    float3 interpolators0 : TEXCOORD0;
#endif

#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
    float3 interpolators1 : TEXCOORD1;
    float4 interpolators2 : TEXCOORD2;
#endif

    // Allocate only necessary space if shader compiler in the future are able to automatically pack
#ifdef VARYINGS_NEED_TEXCOORD1
    float4 interpolators3 : TEXCOORD3;
#elif defined(VARYINGS_NEED_TEXCOORD0)
    float2 interpolators3 : TEXCOORD3;
#endif

#ifdef VARYINGS_NEED_TEXCOORD3
    float4 interpolators4 : TEXCOORD4;
#elif defined(VARYINGS_NEED_TEXCOORD2)
    float2 interpolators4 : TEXCOORD4;
#endif

#ifdef VARYINGS_NEED_COLOR
    float4 interpolators5 : TEXCOORD5;
#endif

    UNITY_VERTEX_INPUT_INSTANCE_ID // Must be declare before FRONT_FACE_SEMANTIC

#if defined(VARYINGS_NEED_CULLFACE) && SHADER_STAGE_FRAGMENT
    FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
#endif
};

再看这两个函数

VertMesh

VaryingsMeshType VertMesh(AttributesMesh input)
{
    VaryingsMeshType output;

    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_TRANSFER_INSTANCE_ID(input, output);

#if defined(HAVE_MESH_MODIFICATION)
    input = ApplyMeshModification(input);
#endif

    // This return the camera relative position (if enable)
    float3 positionRWS = TransformObjectToWorld(input.positionOS);
#ifdef ATTRIBUTES_NEED_NORMAL
    float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
#else
    float3 normalWS = float3(0.0, 0.0, 0.0); // We need this case to be able to compile ApplyVertexModification that doesn't use normal.
#endif

#ifdef ATTRIBUTES_NEED_TANGENT
    float4 tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
#endif

     // Do vertex modification in camera relative space (if enable)
#if defined(HAVE_VERTEX_MODIFICATION)
    ApplyVertexModification(input, normalWS, positionRWS, _Time);
#endif

#ifdef TESSELLATION_ON
    output.positionRWS = positionRWS;
    output.normalWS = normalWS;
    #if defined(VARYINGS_NEED_TANGENT_TO_WORLD) || defined(VARYINGS_DS_NEED_TANGENT)
    output.tangentWS = tangentWS;
    #endif
#else
    #ifdef VARYINGS_NEED_POSITION_WS
    output.positionRWS = positionRWS;
    #endif
    output.positionCS = TransformWorldToHClip(positionRWS);
    #ifdef VARYINGS_NEED_TANGENT_TO_WORLD
    output.normalWS = normalWS;
    output.tangentWS = tangentWS;
    #endif
#endif

#if defined(VARYINGS_NEED_TEXCOORD0) || defined(VARYINGS_DS_NEED_TEXCOORD0)
    output.texCoord0 = input.uv0;
#endif
#if defined(VARYINGS_NEED_TEXCOORD1) || defined(VARYINGS_DS_NEED_TEXCOORD1)
    output.texCoord1 = input.uv1;
#endif
#if defined(VARYINGS_NEED_TEXCOORD2) || defined(VARYINGS_DS_NEED_TEXCOORD2)
    output.texCoord2 = input.uv2;
#endif
#if defined(VARYINGS_NEED_TEXCOORD3) || defined(VARYINGS_DS_NEED_TEXCOORD3)
    output.texCoord3 = input.uv3;
#endif
#if defined(VARYINGS_NEED_COLOR) || defined(VARYINGS_DS_NEED_COLOR)
    output.color = input.color;
#endif

    return output;
}

前两个宏是Instance相关的操作,定义在UnityInstancing.hlsl中。

ApplyMeshModification和地形相关,这里就不分析了。

矩阵计算都在SpaceTransforms.hlsl中定义,可以去那里详细查看。

PackVaryingsToPS

PackedVaryingsToPS PackVaryingsToPS(VaryingsToPS input)
{
    PackedVaryingsToPS output;
    output.vmesh = PackVaryingsMeshToPS(input.vmesh);
#ifdef VARYINGS_NEED_PASS
    output.vpass = PackVaryingsPassToPS(input.vpass);
#endif

    return output;
}
PackedVaryingsMeshToPS PackVaryingsMeshToPS(VaryingsMeshToPS input)
{
    PackedVaryingsMeshToPS output;

    UNITY_TRANSFER_INSTANCE_ID(input, output);

    output.positionCS = input.positionCS;

#ifdef VARYINGS_NEED_POSITION_WS
    output.interpolators0 = input.positionRWS;
#endif

#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
    output.interpolators1 = input.normalWS;
    output.interpolators2 = input.tangentWS;
#endif

#ifdef VARYINGS_NEED_TEXCOORD0
    output.interpolators3.xy = input.texCoord0;
#endif
#ifdef VARYINGS_NEED_TEXCOORD1
    output.interpolators3.zw = input.texCoord1;
#endif
#ifdef VARYINGS_NEED_TEXCOORD2
    output.interpolators4.xy = input.texCoord2;
#endif
#ifdef VARYINGS_NEED_TEXCOORD3
    output.interpolators4.zw = input.texCoord3;
#endif

#ifdef VARYINGS_NEED_COLOR
    output.interpolators5 = input.color;
#endif

    return output;
}

下篇再继续分析Frag。

 

你可能感兴趣的:(Unity)