【Unity】三渲二Shader学习记录(持续更新)

【Unity】三渲二Shader学习记录(持续更新)仿原神渲染的学习记录 鉴于博主对于图形学的认知只停留在渲染管线和一些线性代数的水平 故希望能靠分析明白这个 shader 来提高自身图形学水平 绝赞更新中 unity3 渲 2

大家好,欢迎来到IT知识分享网。

【UnityShader】 三渲二渲染学习笔记

跟B站上的一个大大学的【虚幻&Unity】两种引擎 原神风格基础卡通渲染 完整流程,现趁忘记之前赶紧记下所有细节()

完成画面↓

【Unity/Shader】三渲二纳西妲

首先是重中之重,Shader的参数部分

参数

可控参数如下

环境颜色 Ambient Color

​ 用于调整整体色彩倾向

漫反射颜色 Diffuse Color

​ 用于调整亮面色彩倾向

阴影颜色 Shadow Color

​ 用于调整暗面色彩倾向

基础贴图 Base Tex

​ 用于最基础的漫反射贴图

基础贴图影响因子 Base Tex Fac

​ 用于调整漫反射贴图的贡献(影响大小)

卡通贴图 Toon Tex

​ 用于将法向朝向地面的面的亮度压低,提高立体感

卡通贴图影响因子 Toon Tex Fac

​ 调整卡通贴图贡献

球形纹理 Sphere Tex

​ 提供球形纹理的反射颜色

球形纹理影响因子 Sphere Tex Fac

​ 调整球形纹理贡献

球形纹理乘或加 Sphere Mul/Add

​ 更改球形纹理混合方式,通常Add会使影响更加明显

双面渲染 Double Sided

​ 控制是否进行双面渲染

透明度 Alpha

​ 控制是否透明

金属贴图 Metal Tex

​ 控制确认金属部分

高光分布 Spec Exponent

​ 控制高光的散步范围(越小越集中,类似镜面反射)

非金属反射 Non-Metallic

​ 控制非金属反射强度

金属反射 Metallic

​ 控制金属反射强度

法线贴图 Normal Map

​ 表面细节

ID图 ILM

​ 区分各种部分

阴影分割图和对应行 Ramp Tex

​ 提高光线的层次感

描边粗度和对应颜色

​ 进行描边

实现部分

ShadowCaster

该Pass负责Unity中的阴影投射和阴影接收,以下是其默认实现

Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} ZWrite On ZTest LEqual ColorMask 0 Cull Off HLSLPROGRAM #pragma exclude_renderers gles gles3 glcore #pragma target 4.5 // ------------------------------------- // Material Keywords #pragma shader_feature_local_fragment _ALPHATEST_ON #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma multi_compile _ DOTS_INSTANCING_ON // ------------------------------------- // Universal Pipeline keywords // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl" ENDHLSL } 

DepthNormals

这个pass通常用于需要获取摄像机、屏幕深度的场景,比如rim轮廓光

// This pass is used when drawing to a _CameraNormalsTexture texture Pass { Name "DepthNormals" Tags{"LightMode" = "DepthNormals"} ZWrite On Cull Off HLSLPROGRAM #pragma exclude_renderers gles gles3 glcore #pragma target 4.5 #pragma vertex DepthNormalsVertex #pragma fragment DepthNormalsFragment // ------------------------------------- // Material Keywords #pragma shader_feature_local _NORMALMAP #pragma shader_feature_local _PARALLAXMAP #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED #pragma shader_feature_local_fragment _ALPHATEST_ON #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma multi_compile _ DOTS_INSTANCING_ON #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl" ENDHLSL } 

DrawObject

该Pass负责进行模型的绘制

数据结构部分

首先是带入顶点着色器的appdata

struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; half3 normal : NORMAL; half4 tangent : TANGENT; half4 color : COLOR0; }; 

POSITION代表着顶点的位置信息

TEXCOORD0代表着第一套UV信息,Shader中支持多个UV信息,如漫反射UV,光照贴图UV,动态光照UV等。该参数在内置管线限制为4个,在URP中没有限制,具体视平台限制而定

NORMAL即法线信息

TANGENT是顶点的切线信息,Normal垂直于表面,切线切过表面,二者互相垂直

COLOR0即顶点颜色

接着是片元着色器所需要的数据结构v2f

struct v2f { float2 uv : TEXCOORD0; float3 positionWS : TEXCOORD1; float3 positionVS : TEXCOORD2; float4 positionCS : SV_POSITION; float4 positionNDC : TEXCOORD3; float3 normalWS : TEXCOORD4; float3 tangentWS : TEXCOORD5; float3 bitangentWS : TEXCOORD6; float fogCoord : TEXCOORD7; float4 shadowCoord : TEXCOORD8; }; 

uv负责采样大部分贴图

世界,模型,摄像机,标准屏幕坐标系四个空间下的片元位置

世界空间下的法线,切线,副切线的片元所在面朝向向量

fogCoord和shadowCoord是两个雾效

顶点着色器
v2f vert(appdata v) { v2f o; VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz); o.uv = TRANSFORM_TEX(v.uv, _BaseTex); o.positionWS = vertexInput.positionWS; o.positionVS = vertexInput.positionVS; o.positionCS = vertexInput.positionCS; o.positionNDC = vertexInput.positionNDC; VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(v.normal, v.tangent); o.tangentWS = vertexNormalInput.tangentWS; o.bitangentWS = vertexNormalInput.bitangentWS; o.normalWS = vertexNormalInput.normalWS; o.fogCoord = ComputeFogFactor(vertexInput.positionCS.z); o.shadowCoord = TransformWorldToShadowCoord(vertexInput.positionWS); return o; } 

GetVertexPositionInputs函数,通过输入顶点坐标,获得对应的顶点信息,所有顶点位置都由其获得

GetVertexNormalInputs函数,通过输入法向和切线,返回对应的顶点的法线相关信息

后面通过对应函数计算fogCoord和shadowCoord,提交返回构造好的v2f

片元着色器
定义函数参数
float4 frag(v2f i, bool isFacing : SV_IsFrontFace) : SV_Target 

返回一个rgba值表示片元颜色,接收收到的v2f,接收isFacing判断正反面

SV_Target用于多目标渲染,在后面加上序号(从0开始,不加也是0),可一次渲染到多个渲染目标

获取基础信息

先获取光照信息,使用如下函数

Light light = GetMainLight(i.shadowCoord); 

接着,采样法线贴图,并将其转换为切线空间

float4 normalMap = tex2D(_NormalMap, i.uv); float3 normalTS = float3(normalMap.ag * 2 - 1, 0); normalTS.z = sqrt(1 - dot(normalTS.xy, normalTS.xy)); 
  • normalMap.ag:这表示从法线贴图中采样出的红色(a通道)和绿色(g通道)分量。
  • normalMap.ag * 2 – 1:这一步将采样到的a和g通道值进行缩放和偏移,将其映射到[-1, 1]的范围内。这是因为法线贴图的a和g通道通常存储在[0, 1]范围内,而法线向量在计算中常常需要在[-1, 1]范围内表示。
  • float3(…, 0):将得到的a和g通道值作为X和Y分量,构成一个三维向量,Z分量设置为0。这样构造的normalTS向量表示了法线向量在切线空间(Tangent Space)的局部方向。
  • normalTS.xy :这是normalTS向量的X和Y分量,即法线在切线空间中的水平和垂直分量。
  • dot(normalTS.xy, normalTS.xy) :这是法线在切线空间中水平和垂直分量的长度的平方。
  • 1 – dot(normalTS.xy, normalTS.xy) :这是用来计算法线在切线空间中Z分量的平方。因为法线向量在切线空间中是单位向量,所以其X、Y、Z分量的平方和应该等于1。
  • sqrt(…) :对上述值进行平方根运算,得到Z分量的实际值。

然后求出基本数据和对应点乘

//N 世界空间法线向量 V 摄像机向量 L 光线向量 H 半角向量 float3 N = normalize(mul(normalTS, float3x3(i.tangentWS, i.bitangentWS, i.normalWS))); float3 V = normalize(mul((float3x3)UNITY_MATRIX_I_V, i.positionVS * (-1))); float3 L = normalize(light.direction); float3 H = normalize(V + L); float NoL = dot(N, L); float NoH = dot(N, H); float NoV = dot(N, V); float3 normalVS = normalize(mul((float3x3)UNITY_MATRIX_V, N)); float2 matcapUV = normalVS.xy * 0.5 + 0.5; 

N:一个3×3的浮点数矩阵,用来将世界空间中的切线、副切线和法线向量组合起来。这种方式通常被用来构建一个从世界空间到切线空间(Tangent Space)的转换矩阵。将其与切线normalTS相乘,最终可得到世界空间下的法线。

V:这是将逆视图矩阵的旋转-缩放部分应用于顶点位置的处理。通过这个乘法,我们得到了一个在世界空间中相对于相机视角反向的方向向量。

L:将光线方向规格化。

H:半角向量,计算了光源方向向量L和视角方向向量V的平均方向,即半向量H,并确保它是一个单位向量。这在光照模型中是常见的步骤,用于确定表面的高光反射方向。

NoL:表示光线与表面的夹角关系,越大表明光线与表面越垂直,越小表示越平行,如果直接点乘,则结果为负时,照在表面正方向,为正则照在表面负方向。在光照模型中,NoL用来计算漫反射光的强度,即光线在表面上的投影对光照强度的影响。

NoH:半向量H代表了光源和视角的平均方向,对于镜面反射效果尤为重要。NoH的值告诉我们光线和视角之间的夹角余弦值,这在光照模型中用来计算高光反射的强度。较大的NoH值表示更强的镜面高光效果。

NoV:NoV告诉我们观察者视角下表面的朝向情况,其值越大表明表面法线越朝向观察者,越小则越背向。在光照模型中,NoV通常用来模拟视角相关的效果,如环境反射或透视效果的强度。

normalVS:

  • UNITY_MATRIX_V:这是Unity中的一个预定义变量,表示视图矩阵。视图矩阵用来将物体从世界空间转换到相机空间或观察空间。
  • N:法线向量,通常在顶点着色器中计算并传递给片元着色器。
  • (float3x3)UNITY_MATRIX_V:将UNITY_MATRIX_V强制转换为float3x3类型的矩阵,用于乘法操作。
  • mul((float3x3)UNITY_MATRIX_V, N):这行代码将法线向量N从物体空间(或世界空间)变换到相机空间。因为UNITY_MATRIX_V是视图矩阵,它的作用是将物体坐标变换到相机坐标系下。
  • normalize(…):对变换后的法线向量进行归一化,确保其长度为1,保持单位长度的方向向量。

经过视图矩阵变换并归一化后的法线向量,在视图空间中表示的表面法线方向。

matcapUV:

  • normalVS.xy:这是视图空间中的法线向量的xy分量,即水平和垂直分量。
  • 0.5:这个数值用来将法线向量的范围缩小到0到1之间。
  • + 0.5:这个操作将归一化后的法线向量范围从[-1, 1]映射到[0, 1]之间。

是法线向量在Matcap贴图中的UV坐标。Matcap贴图通常用来实现表面上的高光效果,其UV坐标的计算基于表面法线向量在视图空间中的投影。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114154.html

(0)
上一篇 2025-12-10 15:10
下一篇 2025-12-10 15:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信