文章目录
- 前言
- 方式一:对顶点本地空间下的坐标进行相加平移
- 1、在属性面板定义一个四维变量记录在 xyz 上平移多少。
- 2、在常量缓冲区进行申明
- 3、在顶点着色器中,在进行其他坐标转化之前,对模型顶点本地空间下的坐标进行转化
- 4、我们来看看效果
- 方式二:使用矩阵乘法代替相加平移
- 1、原理
- 2、使用矩阵乘法代替相加平移的好处:
- 3、实现
- 4、我们来看看效果
- 三、测试代码
前言
在Shader中,我们对于顶点经常使用到平移变换。我们在这篇文章中,用点的平移看一下平移矩阵。
方式一:对顶点本地空间下的坐标进行相加平移
P(x,y,z)
A(x1,y1,z1)
P` = P + A =(x + x1,y + y1,z + z1)
1、在属性面板定义一个四维变量记录在 xyz 上平移多少。
_Translate(“Translate(XYZ)”,Vector) = (0,0,0,0)
2、在常量缓冲区进行申明
CBUFFER_START(UnityPerMaterial)
float4 _Translate;
CBUFFER_END
3、在顶点着色器中,在进行其他坐标转化之前,对模型顶点本地空间下的坐标进行转化
v.vertexOS += _Translate.xyz;
4、我们来看看效果
方式二:使用矩阵乘法代替相加平移
1、原理
- 我们按照如下格式得到平移矩阵
Translate(a,b,c)
- 我们给P点的坐标增加一维且值为1,作为列矩阵
- 最后,我们让两个矩阵相乘就会得到一个包含平移后结果。
但是,多出一维分量值为1的列矩阵。
- 我们在图形计算器看看效果
2、使用矩阵乘法代替相加平移的好处:
在多种图形变换时,我们可以把多次的图形变换合并到一个矩阵中。
最后,对顶点只进行一次计算就可得出所有变换后的结果。
3、实现
- 在属性面板定义一个四维变量记录在 xyz 上平移多少。
_Translate(“Translate(XYZ)”,Vector) = (0,0,0,0)
- 在常量缓冲区进行申明
CBUFFER_START(UnityPerMaterial)
float4 _Translate;
CBUFFER_END
- 在顶点着色器中,定义平移矩阵
float4x4 T = float4x4
(
1,0,0,_Translate.x,
0,1,0,_Translate.y,
0,0,1,_Translate.z,
0,0,0,1
);
- 我们 Attribute 中,接收的模型顶点是四维向量,前3维是顶点的位置信息,第四个值默认是1,刚好符合我们的列矩阵要求
v.vertexOS = mul(T,v.vertexOS);
对于mul函数(我们这里默认使用了第一种相乘方法):
-
OpenGL(图形接口): 按列存储矩阵(column-major)。调用API形成的矩阵用来和一个列向量相乘,矩阵在左,列向量在右,即mul(M,v)
-
GLSL(着色器语言): 矩阵的存储方式和OpenGL相同(column-major)
-
DirectX(图形接口): 按行存储矩阵(row-major)。调用API形成的矩阵用来和一个行向量相乘,矩阵在右,行向量在左,即mul(v, M)
-
HLSL(着色器语言): 矩阵存储方式和DirectX相反(column-major)
4、我们来看看效果
三、测试代码
//平移变换
Shader "Unlit/P3_5_1"
{
Properties
{
_Translate("Translate(XYZ)",Vector) = (0,0,0,0)
}
SubShader
{
Tags
{
"PenderPipeline"="UniversalPipeline"
"RenderType"="Opaque"
"Queue"="Geometry"
}
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attribute
{
float4 vertexOS : POSITION;
};
struct Varying
{
float4 vertexCS : SV_POSITION;
};
CBUFFER_START(UnityPerMaterial)
float4 _Translate;
CBUFFER_END
Varying vert (Attribute v)
{
Varying o;
float4x4 T = float4x4
(
1,0,0,_Translate.x,
0,1,0,_Translate.y,
0,0,1,_Translate.z,
0,0,0,1
);
v.vertexOS = mul(T,v.vertexOS);
o.vertexCS = TransformObjectToHClip(v.vertexOS.xyz);
return o;
}
half4 frag (Varying i) : SV_Target
{
return 1;
}
ENDHLSL
}
}
}