Outline Pass
用于渲染轮廓。这个 Pass 看起来比较简单,就是对模型正面剔除后,将背面沿法线偏移线宽的距离,然后直接用轮廓线的颜色渲染背面。
ShaderLab
Pass {
Name "Outline"
Tags {
"LightMode" = "SRPDefaultUnlit"
}
Cull Front // 进行了正面剔除
HLSLPROGRAM
#pragma vertex OutlinePassVertex // 顶点着色器: OutlinePassVertex
#pragma fragment OutlinePassFragment // 片段着色器: OutlinePassFragment
#include "ToonInput.hlsl"
#include "ToonOutlinePass.hlsl"
ENDHLSL
}
ToonOutlinePass.hlsl
先来看一些 ToonOutlinePass.hlsl
里用到的东西。
VertexPositionInputs
其中顶点位置输入 VertexPositionInputs
结构体定义在 "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 中,内容如下:
struct VertexPositionInputs {
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
GetVertexPositionInputs(float3 positionOS)
将物体空间下的顶点坐标转换为世界空间、观察空间、裁剪空间、NDC下的坐标,填充给 VertexPositionInputs
结构体并返回。
VertexPositionInputs GetVertexPositionInputs(float3 positionOS) {
VertexPositionInputs input;
input.positionWS = TransformObjectToWorld(positionOS);
input.positionVS = TransformWorldToView(input.positionWS);
input.positionCS = TransformWorldToHClip(input.positionWS);
float4 ndc = input.positionCS * 0.5f;
input.positionNDC.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
input.positionNDC.zw = input.positionCS.zw;
return input;
}
VertexNormalInputs
顶点法线输入 VertexNormalInputs
结构体同样定义在 "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 中,内容如下:
struct VertexNormalInputs { // 存储了世界空间下的 TBN 向量
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
GetVertexNormalInputs(float3 normalOS, float4 tangentOS)
接收物体空间下的法线和切线,填充 VertexNormalInputs
结构体并返回。
VertexNormalInputs GetVertexNormalInputs(float3 normalOS, float4 tangentOS) {
VertexNormalInputs tbn;
// mikkts space compliant. only normalize when extracting normal at frag.
real sign = real(tangentOS.w) * GetOddNegativeScale();
tbn.normalWS = TransformObjectToWorldNormal(normalOS);
tbn.tangentWS = real3(TransformObjectToWorldDir(tangentOS.xyz));
tbn.bitangentWS = real3(cross(tbn.normalWS, float3(tbn.tangentWS))) * sign;
return tbn;
}
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes { // 顶点着色器的输入
float4 positionOS : POSITION; // 物体空间下的顶点坐标
float3 normalOS : NORMAL; // 物体空间下的法线
float4 tangentOS : TANGENT; // 物体空间下的切线
float2 uv : TEXCOORD0; // uv坐标
};
struct Varyings { // 片段着色器的输入
float2 uv : TEXCOORD0; // uv坐标
float4 positionCS : SV_POSITION; // 裁剪空间下的顶点坐标
};
float3 GetOutlinePosition(VertexPositionInputs vertexInput, VertexNormalInputs normalInput) {
float z = abs(vertexInput.positionVS.z); // 观察空间下的z分量
float width = _OutlineWidth * saturate(z) * 0.001; // 宽度和 z 的大小成正比,离摄像机越远,宽度越大
// 抵消透视造成的远处的线条变细
// 使得远近的线条看起来差不多宽
return vertexInput.positionWS + normalInput.normalWS * width; // 将世界空间下的顶点坐标沿法线偏移线宽的距离
}
// 顶点着色器
Varyings OutlinePassVertex(Attributes input) {
// 填充顶点位置输入结构体
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
// 填充顶点法线输入结构体
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
float3 positionWS = GetOutlinePosition(vertexInput, normalInput); // 获取轮廓线的位置
Varyings output = (Varyings)0;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap); // 填充 uv 坐标
output.positionCS = TransformWorldToHClip(positionWS); // 填充裁剪空间下的顶点坐标
return output;
}
// 片段着色器
half4 OutlinePassFragment(Varyings input) : SV_TARGET {
return _OutlineColor; // 直接返回顶点颜色
}
标签:仿原,hlsl,VertexNormalInputs,Unity,URP,顶点,float4,input,float3
From: https://www.cnblogs.com/AEMShana/p/17709203.html