TA学习之路——2.3图形的HLSL常用函数详解
1.基本数学运算
函数 | 作用 |
---|---|
max(a,b) | 返回a,b值中较大的那个 |
min(a,b) | 返回a,b值中较小的那个 |
mul(a,b | 两变量相乘,常用于矩阵 |
abs(a) | 返回a的绝对值 |
sqrt(x) | 返回x的平方根 |
rsqrt(x) | 返回x的平方根的倒数 |
degrees(x) | 将弧度转成角度 |
radians(x) | 将角度转成弧度 |
noise(x) | 噪声函数 |
1.1 创建一个测试用例
第一步,创建一个Quad,并将Scale调到7
第二步,创建一个MathMax材质
第三步,创建一个MathMaxShader
第四步,把材质挂载到Quad上
1.2 MathMaxShader
MathMaxShader代码如下:
Shader "Math/MathMaxShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例_Scale = 1.6;float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = max(1 - x * x,abs(1 - x * x));// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用第62行:
float Y = max(1 - x * x,abs(1 - x * x));
测试效果展示(测试用例请参考1.1中的介绍):
1.3 MathMinShader
MathMinShader代码如下:
Shader "Math/MathMinShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例_Scale = 1.6;float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = min(x, abs(1 - x * x));// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用第62行:
float Y = min(x, abs(1 - x * x));
测试效果展示(测试用例请参考1.1中的介绍)::
1.4 MathMulShader
mul 函数是 HLSL 中的内置函数,用于执行矩阵乘法或矩阵与向量的乘法。由于 Unity 使用列主序矩阵,矩阵乘法的顺序需要特别注意。
利用mul函数可以让1.3中的图形进行旋转。以下是使用了一个绕y轴旋转的旋转矩阵。
MathMulShader的代码,如下:
Shader "Math/MathMulShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0_Angle ("Angle", Range(-360, 360)) = 0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面//Cull Back // 剔除背面,仅渲染正面Cull Off // 关闭剔除CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;float _Angle;v2f vert (appdata v){v2f o;// 创建绕Y轴旋转矩阵(注意角度转弧度)float angle = radians(_Angle); float4x4 rotMatrix = float4x4(cos(angle), 0, sin(angle), 0,0, 1, 0, 0,-sin(angle), 0, cos(angle), 0,0, 0, 0, 1);// 先旋转模型顶点,再进行MVP变换float4 rotatedVertex = mul(rotMatrix, v.vertex); // 模型空间旋转o.vertex = UnityObjectToClipPos(rotatedVertex); // MVP变换o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = min(x, abs(1 - x * x));// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float4 rotatedVertex = mul(rotMatrix, v.vertex);
测试效果展示(测试用例请参考1.1中的介绍):
绕y轴的旋转矩阵参考
1.5 MathAbsShader
MathAbsShader代码如下:
Shader "Math/MathAbsShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例_Scale = 1.6;float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = abs(x);// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float Y = abs(x);
测试效果展示(测试用例请参考1.1中的介绍):
1.6 MathRoundShader
MathRoundShader代码如下:
Shader "Math/MathRoundShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例_Scale = 1.6;float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = round(x * x);// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float Y = round(x * x);
测试效果展示(测试用例请参考1.1中的介绍):
1.7 MathSqrtShader
MathSqrtShader代码如下:
Shader "Math/MathSqrtShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{//这里可以注释掉自己调节_Scale = 1.6;// 将UV转换到中心坐标系并调整比例float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = sqrt(x * x);// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float Y = sqrt(x * x);
测试效果展示(测试用例请参考1.1中的介绍):
1.8 MathRsqrtShader
MathRsqrtShader代码如下:
Shader "Math/MathRsqrtShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面Cull Back // 剔除背面,仅渲染正面//Cull Off // 剔除正面,仅渲染背面CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{//这里可以注释掉自己调节_Scale = 1.6;// 将UV转换到中心坐标系并调整比例float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = rsqrt(x * x);// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float Y = rsqrt(x * x);
测试效果展示(测试用例请参考1.1中的介绍):
1.9 MathDegreeAndRadiansShader
MathDegreeAndRadians代码如下:
Shader "Math/MathDegreeAndRadians"
{Properties{_Color ("Color", Color) = (1,1,1,1)_LineWidth ("Line Width", Range(0.001, 0.1)) = 0.01_Scale ("Scale", Float) = 1.0_Radians ("Radians", Range(-10, 10)) = 0}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }LOD 100//Blend SrcAlpha OneMinusSrcAlpha 是 Unity Shader 中用于定义颜色混合模式的命令,//其核心作用是 实现透明效果的标准 Alpha 混合。//具体来说,它会将当前片元(源颜色)的 Alpha 值作为混合因子,//与帧缓冲区中已有颜色(目标颜色)进行加权混合//混合公式为最终颜色最终颜色=(源颜色 * SrcAlpha)+(目标颜色 * (1-SrcAlpha))Blend SrcAlpha OneMinusSrcAlphaPass{//Cull Front // 剔除正面,仅渲染背面//Cull Back // 剔除背面,仅渲染正面Cull Off // 关闭剔除CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _LineWidth;float _Scale;float _Radians;v2f vert (appdata v){v2f o;// 创建绕Y轴旋转矩阵(注意角度转弧度)//弧度转角度float angle = degrees(_Radians);//角度转弧度float rad = radians(angle); //这里为了方便理解degrees和radians,这样写;//也可以不要degrees和radians上面两个,直接把rad换成_Radiansfloat4x4 rotMatrix = float4x4(cos(rad), 0, sin(rad), 0,0, 1, 0, 0,-sin(rad), 0, cos(rad), 0,0, 0, 0, 1);//以下代码与上面三句等同//float4x4 rotMatrix = float4x4(// cos(_Radians), 0, sin(_Radians), 0,// 0, 1, 0, 0,// -sin(_Radians), 0, cos(_Radians), 0,// 0, 0, 0, 1//);// 先旋转模型顶点,再进行MVP变换float4 rotatedVertex = mul(rotMatrix, v.vertex); // 模型空间旋转o.vertex = UnityObjectToClipPos(rotatedVertex); // MVP变换o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{ // 将UV转换到中心坐标系并调整比例float x = (i.uv.x - 0.5) * 2.0 * _Scale;float y = (i.uv.y - 0.5) * 2.0 * _Scale;// 计算函数Y值float Y = abs(x);// 计算垂直距离并应用抗锯齿float diff = abs(y - Y);float line1 = 1.0 - smoothstep(0.0, _LineWidth, diff);// 组合颜色fixed4 col = _Color;col.a *= line1;return col;}ENDCG}}
}
关键函数运用:
float angle = degrees(_Radians);
float rad = radians(angle);
同样滑动_Radians值可以绕y轴旋转
1.10 自定义的MathNoiseShader
MathNoiseShader代码如下:
Shader "Math/MathNoise" {Properties {_Color ("Color", Color) = (1,1,1,1)_NoiseScale ("Noise Scale", Range(0.1, 50)) = 10.0}SubShader {Tags { "RenderType"="Opaque" }Pass {CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f {float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};float4 _Color;float _NoiseScale;v2f vert (appdata v) {v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}// 随机函数float rand(float2 co) {return frac(sin(dot(co, float2(12.9898, 78.233))) * 43758.5453);}// 噪声函数float noise(float2 uv) {float2 i = floor(uv);float2 f = frac(uv);float a = rand(i);float b = rand(i + float2(1, 0));float c = rand(i + float2(0, 1));float d = rand(i + float2(1, 1));float2 u = f * f * (3.0 - 2.0 * f);return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y);}fixed4 frag (v2f i) : SV_Target {float n = noise(i.uv * _NoiseScale);return _Color * n;}ENDCG}}
}
测试效果展示(测试用例请参考1.1中的介绍):
2.幂指对函数
函数 | 作用 | 例 |
---|---|---|
pow(x,y) | x的y次幂 | x y x^y xy |
exp(x) | 返回以e为底的指数函数 | e x e^x ex |
exp2(x) | 返回以2为底的指数函数 | 2 x 2^x 2x |
Idexp(x,exp) | 返回x与2的exp次方的乘积 | x 2 e p x x2^{epx} x2epx |
log(x) | 求以10为底的对数 | l n x lnx lnx |
log10(x) | 求以10为底的对数 | l o g 10 x log_{10}x log10x |
log2(x) | 求以2为底的对数 | l o g 2 x log_2x log2x |
frexp(x,out exp) | 把浮点数x分解成尾数和指数返回值是尾数,exp参数返回的值是指数 | x = r e t ∗ 2 e x p x = ret*2^{exp} x=ret∗2exp |
2.1 pow(x,y)
MathPowShader代码如下:
Shader "Math/MathPowShader"
{Properties{_Color ("Line Color", Color) = (1,0,0,1)_LineWidth ("Line Width", Range(0, 0.1)) = 0.05_XMin ("X Min", Float) = -5_XMax ("X Max", Float) = 5_YMin ("Y Min", Float) = 0_YMax ("Y Max", Float) = 32}SubShader{Tags { "RenderType"="Transparent" "Queue"="Transparent" }Blend SrcAlpha OneMinusSrcAlphaPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct