想学一下NPR渲染,话不多说,先搞一只芙再说,边做边学
一、资源整理
终于是把东西全都集齐了
1、纹理设置
首先要把将Diffuse和Lightmap的压缩改成"无"或"高质量"。
法线贴图的纹理类型改成"法线贴图"。
除颜色图外其它贴图全部取消勾选sRGB。
如果最终的渲染结果,出现贴图不清晰,有锯齿,有杂色,颜色深浅不对等问题,那大概率是贴图设置有问题,建议先重新认真检查一遍贴图设置。
2、纹理分析
body和hair的diffuse贴图的a通道存放了自发光的遮罩
face的a通道则存放了腮红的遮罩
hair和body的lightmap的4个通道分别存放了高光范围,AO,高光强度,ramp分层
Body
Hair
两张ShadowRamp分别控制白天和晚上的阴影颜色
NoramlMap是正常的法线贴图
MetalMap控制金属高光
FaceLightMap是一张SDF面部阴影图。
ShadowMap控制了阴影区域的遮罩。
二、渲染设置
原神的角色实际上应该是渲染了三遍,第一遍用第一套UV渲染正面,第二遍用第二套UV渲染背面,第三遍渲染描边,这样可以做到单面片正反两面的贴图不一样,崩铁应该也是使用了这套技术。
RendererFeatures
URP使用多pass需要使用RendererFeatures,先设置一下RendererFeatures。在项目大纲找到UniversalRenderer,默认路径在Assets/Settings/UniversalRenderer。
然后在检查器找到RendererFeatures,点击Add RendererFeature添加一个RenderObjects,然后在LightModeTags添加三个元素,三个元素分别为“渲染正面pass、渲染背面pass和渲染描边pass”。
然后在LayerMask(图层蒙版)把角色对应的图层勾上,默认在Default层,勾上Everything会所有图层都显示。
三、Shader分析
1.Shader准备
正式开始前先把计算需要用到的变量和向量等数据准备好,先来准备面板参数,面板参数如下:
Properties
[Space(20.0)][Toggle]_genshinShader("是否脸部", float) = 0.0
[Space(20.0)]
//Unity的自定义属性(Attribute),用于在Unity的Inspector面板中为后续的属性或字段添加垂直空间
//这里的20.0
表示这个空间的高度为20个像素。这有助于组织Inspector面板中的属性,使其更易于阅读和管理
[Toggle]_genshinShader("是否脸部", float) = 0.0
//定义了一个名为_genshinShader
的变量,但其实际类型被指定为float
//由于[Toggle]
属性的存在,这个float
变量实际上在Inspector面板中会被呈现为一个切换开关(Toggle)。
[Space(20.0)][NoScaleOffset]_diffuse("Diffuse", 2d) = "white"{}_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02
[NoScaleOffset]
//[NoScaleOffset]
: 这是一个自定义属性,通常在Shader中用于告诉Unity不要对纹理应用缩放或偏移(Scale或Offset)的默认参数。这通常用于那些不需要或不应该有额外变换的纹理。
_diffuse("Diffuse", 2D) = "white"{}
//_diffuse
: 用于存储Diffuse纹理的引用。
_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7
//_fresnel
: 用于存储与Fresnel效应(菲涅尔反射)相关的参数,通常用于控制边缘光的范围。
_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02
//_edgeLight
: 用于存储与边缘光强度相关的参数。
[Space(8.0)]_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)_flicker( "发光闪烁速度" , float) = 0.8
_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0
//用于控制材质的透明度(当值为1时)或自发光强度(当值为2时)。
_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0
//用于确定哪些像素是完全不透明的(高于阈值)和哪些像素是透明的(低于阈值)。
[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)
//[HDR]
是一个Unity的自定义属性,通常用于指示该属性支持高动态范围(HDR)颜色。这意味着该属性的颜色值可以超过常规的0到1范围。
//用于控制自发光的效果强度。
_flicker( "发光闪烁速度" , float) = 0.8
//用于控制某种发光效果的闪烁速度。
[NoScaleOffset]_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}_bright( "亮面范围" , float) = 0.99_grey( "灰面范围" , float) = 1.14_dark( "暗面范围" , float) = 0.5
_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}
//用于全局光照或面部光照。
_bright( "亮面范围" , float) = 0.99
//用于控制材质中亮面部分的范围或强度。
_grey( "灰面范围" , float) = 1.14
//用于控制材质中灰色或中间亮度部分的范围或强度。
_dark( "暗面范围" , float) = 0.5
//用于控制材质中暗面部分的范围或强度。
[NoScaleOffset]_bumpMap( "Normalmap" , 2d) = "bump"{}_bumpScale( "法线强度" , float) = 1.0
_bumpMap( "Normalmap" , 2d) = "bump"{}
//用于存储法线贴图(normal map)数据。
_bumpScale( "法线强度" , float) = 1.0
//整法线贴图产生的凹凸效果的强弱。
[NoScaleOffset]_ramp( "Shadow_Ramp" , 2d) = "white"{}[Toggle]_dayAndNight("是否是白天" , float) = 0.0
_ramp( "Shadow_Ramp" , 2d) = "white"{}
//在Inspector中显示的属性标签。
[Toggle]_dayAndNight("是否是白天" , float) = 0.0
//显示为一个切换按钮
_lightmapA0("1.0_Ramp条数" , Range(1, 5)) = 1_lightmapA1("0.7_Ramp条数" , Range(1, 5)) = 4_lightmapA2("0.5_Ramp条数" , Range(1, 5)) = 3_lightmapA3("0.3_Ramp条数" , Range(1, 5)) = 5_lightmapA4("0.0_Ramp条数" , Range(1, 5)) = 2
_lightmapA0
到 _lightmapA4
//用于控制不同光照强度下的Ramp条数。Ramp通常用于创建渐变或层次效果。
[NoScaleOffset]_metalMap( "MetalMap" , 2d) = "white"{}_gloss( "高光范围" , Range(1, 256.0)) = 1_glossStrength( "高光强度" , Range(0.0, 1.0)) = 1_metalMapColor( "金属反射颜色" , color) = (1.0, 1.0, 1.0, 1.0)
_metalMap( "MetalMap" , 2d) = "white"{}
//与_ramp
类似,但这个是用于金属的贴图
_gloss
到 _metalMapColor
//_gloss
: 高光范围。
//_glossStrength
: 高光强度。
//_metalMapColor
: 金属反射的基础颜色。
_outline( "描边粗细" , Range(0.0, 1.0)) = 0.4_outlineColor0( "描边颜色1" , color) = (1.0, 0.0, 0.0, 0.0)_outlineColor1( "描边颜色2" , color) = (0.0, 1.0, 0.0, 0.0)_outlineColor2( "描边颜色3" , color) = (0.0, 0.0, 1.0, 0.0)_outlineColor3( "描边颜色4" , color) = (1.0, 1.0, 0.0, 0.0)_outlineColor4( "描边颜色5" , color) = (0.5, 0.0, 1.0, 0.0)
_outline
到 _outlineColor5
//_outline
: 描边的粗细。
//_outlineColor0
到 _outlineColor5
: 不同的描边颜色。
2.URP框架简单总结
(一)、Bulit-in管线到URP管线的部分改变
本次渲染复刻使用的是Unity的URP管线,与Bulit-in管线存在部分的改变:
1.在URP管线中,我们将原来的CG代码改为HLSL代码
原来为 CGPROGRAM
现在为 HLSLPROGRAM;原来为 ENDCG
现在为 ENDHLSL;
2.一些unity封装的函数名称,以及定义的宏发生了改变,例如:
原来为 UnityObjectToClipPos
现在为 TransformObjectToHClip;原来为 UNITY_DECLARE_TEX2D(name)
现在为 TEXTURE2D(textureName); SAMPLER(samplerName);;
3.引用的头文件发生了改变,例如:
导入库
原来为 #include "UnityCG.cginc"
现在为 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//默认库
原来为 #include "AutoLight.cginc"
现在为 #include "Packages/com.unity.render-pipuniversal/ShaderLibrary/Lighting.hlsl"//光照库
一个简单总结了Bulit-in到URP变化的blog :From Built-in to URP (teodutra.com)
//导入库#include "Packages/com.unity.renderpipelines.universal/ShaderLibrary/Core.hlsl" //默认库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" //光照库CBUFFER_START(UnityPerMaterial) //常量缓冲区开头
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
和
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
- 这两行代码是预处理器指令,用于包含(或“导入”)其他HLSL文件。
Core.hlsl
通常是URP的核心库,它包含了URP Shader中常用的基础函数和宏定义。Lighting.hlsl
是URP的光照库,它提供了与光照相关的函数和宏定义。- 这两个库文件是URP Shader开发的基础,提供了许多便利的函数和工具。
CBUFFER_START(UnityPerMaterial)
CBUFFER_START
是一个宏定义,通常用于声明常量缓冲区(Constant Buffer)的开始。- 在URP和其他Unity渲染管道中,常量缓冲区是一种高效的方式,用于将大量数据(如材质属性)从CPU传递到GPU。
UnityPerMaterial
是这个常量缓冲区的名称。这表示这个常量缓冲区中的数据是每个材质特有的,而不是每个实例或每个顶点特有的。- 通常,在这个宏之后,你会看到一系列的变量声明,这些变量将存储在
UnityPerMaterial
常量缓冲区中。- 当你完成常量缓冲区的变量声明后,你会使用
CBUFFER_END
宏来结束这个常量缓冲区的定义。
(二)、整体框架
Shader "Furina"
{Properties{[Space(20.0)] [Toggle]_genshinShader("是否脸部", float) = 0.0[Space(20.0)][NoScaleOffset]_diffuse("Diffuse", 2d) = "white"{}_fresnel("边缘光范围", Range(0.0, 10.0)) = 1.7_edgeLight("边缘光强度", Range(0.0, 10.0)) = 0.02[Space(8.0)]_diffuseA( "Alpha(1透明, 2自发光)" , Range(0.0, 2.0)) = 0_Cutoff( "透明阈值" , Range(0.0, 1.0)) = 1.0[HDR]_glow( "自发光强度" , color) = (1.0, 1.0, 1.0, 1.0)_flicker( "发光闪烁速度" , float) = 0.8[Space(30.0)][NoScaleOffset]_lightmap( "Lightmap/FaceLightmap" , 2d) = "white"{}_bright( "亮面范围" , float) = 0.99_grey( "灰面范围" , float) = 1.14_dark( "暗面范围" , float) = 0.5[Space(30.0)][NoScaleOffset]_bumpMap( "Normalmap" , 2d) = "bump"{}_bumpScale( "法线强度" , float) = 1.0[Space(30.0)][NoScaleOffset]_ramp( "Shadow_Ramp" , 2d) = "white"{}[Toggle]_dayAndNight("是否是白天" , float) = 0.0[Space(8.0)]_lightmapA0("1.0_Ramp条数" , Range(1, 5)) = 1_lightmapA1("0.7_Ramp条数" , Range(1, 5)) = 4_lightmapA2("0.5_Ramp条数" , Range(1, 5)) = 3_lightmapA3("0.3_Ramp条数" , Range(1, 5)) = 5_lightmapA4("0.0_Ramp条数" , Range(1, 5)) = 2[Space(30.0)][NoScaleOffset]_metalMap( "MetalMap" , 2d) = "white"{}_gloss( "高光范围" , Range(1, 256.0)) = 1_glossStrength( "高光强度" , Range(0.0, 1.0)) = 1_metalMapColor( "金属反射颜色" , color) = (1.0, 1.0, 1.0, 1.0)[Space(30.0)]_outline( "描边粗细" , Range(0.0, 1.0)) = 0.4_outlineColor0( "描边颜色1" , color) = (1.0, 0.0, 0.0, 0.0)_outlineColor1( "描边颜色2" , color) = (0.0, 1.0, 0.0, 0.0)_outlineColor2( "描边颜色3" , color) = (0.0, 0.0, 1.0, 0.0)_outlineColor3( "描边颜色4" , color) = (1.0, 1.0, 0.0, 0.0)_outlineColor4( "描边颜色5" , color) = (0.5, 0.0, 1.0, 0.0)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{HLSLPROGRAM#pragma vertex vert#pragma fragment frag//导入库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" //默认库#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" //光照库CBUFFER_START(UnityPerMaterial) //常量缓冲区开头//声明面板参数float _genshinShader; //是否是脸部//diffusefloat _fresnel; //边缘光范围float _edgeLight; //边缘光强度float _diffuseA; //diffuseAfloat _Cutoff; //透明阈值float4 _glow; //自发光强度float _flicker; //发光闪烁速度//lightmap/FaceLightmapfloat _bright; //亮面范围float _grey; //灰面范围float _dark; //暗面范围//normalfloat _bumpScale; //法线强度//rampfloat _dayAndNight; //是否是白天float _lightmapA0; //1.0_Ramp条数float _lightmapA1; //0.7_Ramp条数float _lightmapA2; //0.5_Ramp条数float _lightmapA3; //0.3_Ramp条数float _lightmapA4; //0.0_Ramp条数//高光float _gloss; //高光范围float _glossStrength; //高光强度float3 _metalMapColor; //金属折射颜色//描边float _outline; //描边粗细float3 _outlineColor0; //描边颜色1float3 _outlineColor1; //描边颜色2float3 _outlineColor2; //描边颜色3float3 _outlineColor3; //描边颜色4float3 _outlineColor4; //描边颜色5CBUFFER_END //常量缓冲区结尾//声明贴图TEXTURE2D(_diffuse); //DiffuseSAMPLER(sampler_diffuse);TEXTURE2D(_lightmap); //Lightmap/FaceLightmapSAMPLER(sampler_lightmap);TEXTURE2D(_bumpMap); //NormalSAMPLER(sampler_bumpMap);TEXTURE2D(_ramp); //Shadow_RampSAMPLER(sampler_ramp);TEXTURE2D(_metalMap); //MetalMapSAMPLER(sampler_metalMap);ENDHLSL struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col = tex2D(_MainTex, i.uv);// apply fogUNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDHLSL}}
}