找回密码
 立即注册
查看: 253|回复: 0

[简易教程] [URP]内置shader解析笔记

[复制链接]
发表于 2022-4-19 05:24 | 显示全部楼层 |阅读模式
URP


  • SRP:可编程渲染管线,使其拥有更高扩展性,Unity2018.1版本推出了可编程渲染管线功能,并提供两个可以直接使用的SRP模板:HDRP\LWRP
  • HDRP:为高端显卡的设备使用的渲染管线(ps5\XboxOne)\\ \\LWRP:为移动端渲染管线
  • URP:在Unity2019.3版本讲LWRP进行升级,改名为URP
一.创建URP项目


二.升级URP项目
1.安装UPR扩展包

  • Package Manager  Unity Registry  UniversalRp  Install
2.创建UPR Asset

  • 右击Assets  Create  Rendering  UPRAssets(with UR)



项目当前路径下自动创建以上资源


  • Unity在URP中开放出很多调整渲染质量的设置选项



渲染质量设置和在图形设置中添加URPAssets

3.升级旧材质

  • 使用新的URPAsset之后,旧的Shader和URP不兼容,导致物体变为紫色,可以调整材质球
  • Eidt  Rendering  Material  Convert Select Build-in Material to URP
  • Window  Rendering  Render Pipeline Converter



经过以上旧项目升级为URP项目

三.URP内置Shader

  • Urp项目中,由于SRP管线不兼容旧的渲染管线,如果继续使用旧的Shader会报错,因此要使用URP -Shader



Shader存放路径

1.Lit-shader

  • 此shader是基于物理渲染(PBR)光照模型,将Metallic和Specular工作流整合在一起



Lit-Shader材质面板

2.Simple Lit-Shader



移动端设备上运行,光照模型使用Blinn-Phong

3.Bake Lit-Shader

  • 当需要风格化渲染,不需要实时光照\高光反射等渲染时,可以使用此shader,没有PBR\BlinnPhong光照,所有的光照数据来自Unity烘培的光照贴图和光照探灯,不支持实时光


4.Unit-Shader



Unit

四.Packages文件

  • Shader文件



文本样式为Shader的包含文件


  • CoreRP Library \ Universal RP  文件


1.CoreRP Library  ShaderLibrary,存放着Unity宏定义,预定义函数,不同平台的API等,真实名字为com.untiy.render-pipeline.core

  • Common.hlsl:注意事项以及定义数据类型和一些通用性函数LinearEyeDepth( )函数
  • CommonLighting.hlsl:定义了灯光计算的通用函数
  • CommonMaterial.hlsl:粗糙度计算函数和纹理混合插值计算
  • EntityLighting.hlsl:光照贴图采样和环境光解码
  • Macros.hlsl:宏定义
  • Packing.hlsl:数据解码
2.Universal RP  ShaderLibrarty,存放着着URP内置的shader所关联的包含文件

  • Core.hlsl:定义了一些数据结构
  • Input.hlsl:定义了InputData结构体,变换矩阵宏定义
  • lighting.hlsl:光照计算相关函数
  • shadow.hlsl:计算阴影相关函数
  • surfaceInput.hlsl:几种纹理采样函数[sNormal][AlbedoAlpha]
  • UnityInPut..hlsl:包含了全局变量和变换矩阵
  • BRDF.hlsl:BRDF结构体以及初始化
Lit.shader


  • 此文件所在路径为:package/UniversalRP/Shaders/Lit.shader
一:Properties



属性


  • 默认Unity将_MainTex的纹理属性为主纹理,如果想用不同的变量名可以使用指令[MainTexture]/[MainColor],如果添加多个指令,只对第一个有效
  • 设置主纹理和主颜色后可以通过脚本传递参数给使用该shader材质球



  • [ToggleOff]指令:数值类型的属性在材质面板显示为开关,如果属性设置了,还需要在编译指令中声明,[Toggle]指令:关键字后面为ON


二:SubShader



Subshader注释


  • 渲染管线标签是必需的, 如果在Graphics中没有设置URP,这个Subshader将会失效。 可以添加一个subshader\fallBack-Build_in,让材质在URP管线和Build-in兼容



FallBack和自定义的ShaderGUI



UniversalRP-FallbackError.shader



Subshader中的pass个数

①ForwardLit Pass

  • Tags{"LightMode" = "UniversalForward"}这个光照模式要与UniversalRenderPipeline.cs文件定义的名字像匹配,如果使用Unlit-shader可以不用"LightMode"
  • 使用HLSL语言,之前的Cg语言会隐式包含了一些文件eg.“HLSLSupport.cginc”
编译指令

  • 不为一些渲染平台编译Shader
  • 不同的设备支持的 target shader model 是不一样
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5Pass中根据用途将Keywords分为3类
1.Material Keywords(材质属性):为材质面板上与属性对应

  • 当添加了法线贴图,就会传入_NORMALMAP
  • 当开启透明裁剪,就会传入_ALPHATEST_ON


2.Universal Pipeline keywords(渲染管线)为渲染管线声明与属性的对应



当开启主光投射阴影,就会传入 _MAIN_LIGHT_SHADOWS

3.Unity defined keywords(自定义)

  • 这里主要在Lighting设置面板,是否使用光照贴图等
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT

  • 以下为使得Shader支持GPU实例功能
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#pragma multi_compile _ DOTS_INSTANCING_ON


第一个pass结束,并未见到任何关于顶点/片段函数,代码包含在以下2个文件中

#inclue的定义方式
#ifndef UNIVERSAL_PIPELINE_CORE_INCLUDED
#define UNIVERSAL_PIPELINE_CORE_INCLUDED
...//文件代码
#endif

  • #ifndef指令判断当前文件是否已经定义UNIVERSAL_PIPELINE_CORE_INCLUDED,如果没有被定义,那么就使用#define进行定义
包含文件.hlsl的使用方式



与主文件同路径


  • #include"LitInput.hlsl"
  • #include"./LitInput.hlsl" \\\\“./“表示返回主文件的父级
2.与主文件不同路径

  • #include"Assets/ShaderInclude/UnlitInclude.hlsl"使用绝对路径
  • 也可以使用相对路径,通过右击copy Path可以快速复制路径
LitInput.hlsl


  • Litshader 第一个passForwadLit包含的第一个库文件, 主要是做了表面特征的的初始化
  • 路径:Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl
一:声明属性变量

  • URP中声明纹理资源的方式与传统的渲染流水线有些不同
//将声明的属性变量包含其中
//NOTE: Do not ifdef the properties here as SRP batcher can not handle different layouts.
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
...
half _Surface;
CBUFFER_END

  • DX9之前不存在Cbuffer,顶点/片段函数访问同一个常量,必须设置两次,现在GPU单独划分出一块内存存储常量,所以不需要存储多次,可以高效进行计算
  • URP纹理的声明方式与传统渲染流水线区别,unity将纹理声明和定义采样器分开
  • 使用TEXTURE2D(_textureName):声明纹理!!!SAMPLER(sampler_textureName):定义纹理采样器!!
    如果用到Scale和Offset,需要在Cbuffer中声明变量: 纹理名_ST
//Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl
//_BaseMap/ _Bumpmap /_EmissionMap 在SurfaceInput.hlsl设置了
TEXTURE2D(_ParallaxMap);        SAMPLER(sampler_ParallaxMap);
TEXTURE2D(_OcclusionMap);       SAMPLER(sampler_OcclusionMap);
... ...
TEXTURE2D(_SpecGlossMap);       SAMPLER(sampler_SpecGlossMap);



采样器:可以定义纹理设置面板上的Wrap Mode(重复模式)/Filter Mode(过滤模式)

采样器定义3种方式

  • SAMPLER(sampler,_textureName):使用_textureName这个纹理在设置面板中设定采样方式
  • 自定义采样器设置SAMPLER(filter_wrap)


3.SAMPLER(filter_wrapU_wrapV):可以为U和V设定不同的重复模式
二:纹理采样

  • 采样函数宏定义
//开启Specular工作流,采样的是_SpecGlossMap 贴图,否则对_MetallicGlossMap采样
#ifdef _SPECULAR_SETUP
    #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv)
#else
    #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv)
#endif



定义了宏在不同工作流所进行的操作


  • URP中,纹理使用宏定义SAMPLE_TEXTURE2D(_textureName,sampler,uv)进行采样
Metallic和Specular采样函数
//传入参数纹理坐标/Albedo A通道
half4 SampleMetallicSpecGloss(float2 uv, half albedoAlpha)
{
    half4 specGloss;

//有无Metallic\\Specular图
//有:采样
#ifdef _METALLICSPECGLOSSMAP
    specGloss = half4(SAMPLE_METALLICSPECULAR(uv));

//Source = Albedo Alpha 吗?是:执行
    #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
        specGloss.a = albedoAlpha * _Smoothness;
    #else                    
        specGloss.a *= _Smoothness;
    #endif

//没有:不采样
#else // _METALLICSPECGLOSSMAP
    #if _SPECULAR_SETUP
        specGloss.rgb = _SpecColor.rgb;
    #else
        specGloss.rgb = _Metallic.rrr;
    #endif

    #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
        specGloss.a = albedoAlpha * _Smoothness;
    #else
        specGloss.a = _Smoothness;
    #endif
#endif
AO图采样函数
half SampleOcclusion(float2 uv)
{
    #ifdef _OCCLUSIONMAP
// TODO: Controls things like these by exposing SHADER_QUALITY levels (low, medium, high)
//目标平台移动设备
        #if defined(SHADER_API_GLES)
            return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
        #else
            half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
            return LerpWhiteTo(occ, _OcclusionStrength);
//路径:Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl
        #endif
    #else
        return half(1.0);
    #endif
}
SurfaceData结构体
struct SurfaceData
{
    half3 albedo;
    half3 specular;
    half  metallic;
    half  smoothness;
    half3 normalTS;
    half3 emission;
    half  occlusion;
    half  alpha;
    half  clearCoatMask;
    half  clearCoatSmoothness;
};
Alpha()函数
half Alpha(half albedoAlpha, half4 color, half cutoff)
{
#if !defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A) && !defined(_GLOSSINESS_FROM_BASE_ALPHA)
    half alpha = albedoAlpha * color.a;
#else
    half alpha = color.a;
#endif

#if defined(_ALPHATEST_ON)
    clip(alpha - cutoff);
#endif

    return alpha;
}
Albedo纹理采样函数
half4 SampleAlbedoAlpha(float2 uv, TEXTURE2D_PARAM(albedoAlphaMap, sampler_albedoAlphaMap))
{
    return half4(SAMPLE_TEXTURE2D(albedoAlphaMap, sampler_albedoAlphaMap, uv));
}
法线贴图采样函数
half3 SampleNormal(float2 uv, TEXTURE2D_PARAM(bumpMap, sampler_bumpMap), half scale = half(1.0))
{
//判断是否有法线贴图传入
#ifdef _NORMALMAP
    half4 n = SAMPLE_TEXTURE2D(bumpMap, sampler_bumpMap, uv);
//判断设备是否支持法线强度调整
    #if BUMP_SCALE_NOT_SUPPORTED
        return UnpackNormal(n);
    #else
//Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl
//解码法线
        return UnpackNormalScale(n, scale);
    #endif
#else
    return half3(0.0h, 0.0h, 1.0h);
#endif
}
表面数据初始化函数
//主要是为了初始化SurfaceData结构体
inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData)
{

//在D3D11中定义了将2个参数合并
//Packages/com.unity.render-pipelines.core/ShaderLibrary/API/D3D11.hlsl
//#define TEXTURE2D_ARGS(textureName, samplerName)    textureName, samplerName
    half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap));
    outSurfaceData.alpha = Alpha(albedoAlpha.a, _BaseColor, _Cutoff);

    half4 specGloss = SampleMetallicSpecGloss(uv, albedoAlpha.a);
    outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb;

//高光工作流
#if _SPECULAR_SETUP
    outSurfaceData.metallic = half(1.0);
    outSurfaceData.specular = specGloss.rgb;

//金属工作流
#else
    outSurfaceData.metallic = specGloss.r;
    outSurfaceData.specular = half3(0.0, 0.0, 0.0);
#endif

    outSurfaceData.smoothness = specGloss.a;
    outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale);
    outSurfaceData.occlusion = SampleOcclusion(uv);
    outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb,
                                             TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap));

#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
    half2 clearCoat = SampleClearCoat(uv);
    outSurfaceData.clearCoatMask       = clearCoat.r;
    outSurfaceData.clearCoatSmoothness = clearCoat.g;
#else
    outSurfaceData.clearCoatMask       = half(0.0);
    outSurfaceData.clearCoatSmoothness = half(0.0);
#endif

#if defined(_DETAIL)
    half detailMask = SAMPLE_TEXTURE2D(_DetailMask, sampler_DetailMask, uv).a;
    float2 detailUv = uv * _DetailAlbedoMap_ST.xy + _DetailAlbedoMap_ST.zw;
    outSurfaceData.albedo = ApplyDetailAlbedo(detailUv, outSurfaceData.albedo, detailMask);
    outSurfaceData.normalTS = ApplyDetailNormal(detailUv, outSurfaceData.normalTS, detailMask);
#endif
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-7 20:38 , Processed in 0.253094 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表