Unity Shader中的平移、缩放、旋转 您所在的位置:网站首页 unity中scale怎么定义 Unity Shader中的平移、缩放、旋转

Unity Shader中的平移、缩放、旋转

2023-06-10 07:08| 来源: 网络整理| 查看: 265

在这篇文章中,我们将利用上一篇《Unity中矩阵的平移、旋转、缩放》里所介绍的知识来完成我们这篇文章的任务。至于Unity Shader基础,在本篇文章中不做过多介绍。由于本篇文章基本上很简单,因此如果你是Unity Shader高手的话,建议你还是不要看了。对于新手来说,你将会学到Unity Shader简单的操作,还有一些基本的3D数学。如果你对 Unity Shader 一无所知,请进入下面链接去入入门:

http://blog.csdn.net/candycat1992/article/details/40212735

首先创建一个Unity工程,克森把他命名为“Ugly Shader”(丑陋的着色器),基本配置如下图所示:

为了便于查找,让我们在 Assets 目录下新建两个文件夹,分别命名为“Shader”、“Material”,这个不用解释,大伙们都看得懂吧。如下图所示:

接下来在 Shader 文件夹里创建一个 Shader 脚本,命名为“MyTransform”,该Shader脚本用于构建Unity Shader中的矩阵转换,例如:平移、旋转、缩放等等:

然后在Hierachy面板中创建一个 Cube 物体,并在“Material”文件夹里创建一个 Material(材质),命名为“CubeMat”,然后为其 Cube 物体添加材质,之后在 Material 的 Shader 属性面板中选择“Liction/Transform”,如下图所示:

好,接下来让我们开始码了个码。

为了方便,还是把上次那个图给拿过来了,这个就是平移矩阵,具体介绍请查看《Unity中矩阵的平移、旋转、缩放》。

接下来,我们利用平移矩阵做个简单的平移,让我们双击打开刚刚创建的Shader脚本,代码如图所示:

这是一个使用CG语言编写的 Vertex&Fragment(顶点&片段)Shader程序(从 CGPROGRAM 和 ENDCG 便能看出),首先我们声明了两个属性,分别是“_Transform”和“_Translational”。“_Transform”属性用来选择变换的模式(也就是选择平移、旋转、缩放)。克森在“_Transform”属性的前面加了一点代码:“[enum(Translational,0, Roation,1, Scale,2)]”,这个代码用户在Inspector面板的Shader属性中显示一个下拉菜单,在这里的默认值为0,这就意味着该菜单默认选择的是“Translational”(同样的,Rotation就等于1,Scal等于2)。效果如图所示:

而“_Translational”则是用来在Inspector面板的Shader属性中设置物体的偏移量,如上图所示。

接下来就是创建一个函数,函数如下所示:

其实很简单,该函数就是用于返回一个设置好的平移矩阵,具体内容请对应上图的平移矩阵。

然后在顶点程序里面做计算,也就是这段代码“i.vertex = mul(Translational(_Translational), i.vertex);”。这段代码的意思很简单,那就是计算平移矩阵和顶点位置相乘,然后把结果传给输入的顶点位置。

然后把顶点的位置和Unity提前定义的一个矩阵UNITY_MATRIX_MVP(在UnityShaderVariables.cginc里定义)相乘,从而把顶点位置从model space(模型空间)转换到 clip space(裁剪空间)。也可以称作简单的几何流水线,我们使用了矩阵乘法操作 mul() 函数来执行这个步骤。

UNITY_MATRIX_MVP,所谓MVP变换就是:Model Transform(建模变换) -> View Transform(视变换) -> Projection Transform(投影变换)。

最初始的时候,克森也不懂什么意思,然后就鲁莽的把它看做是一个由3D转换到2D屏幕的过程。。。其实也蛮像的吧。。

下面一行代码就是为输出的颜色赋值,也就是:“o.color = float4(1,0,0,1);”在这里我们给予的是一个红色。最后把这个设置好的输出结构返回,至此,我们的顶点程序便完事儿了。

然后片段程序也很简单,直接返回输出结构的颜色便完事儿。

PS:克森只是讲了该代码里重要的部分,然而 Unity Shader 代码基础框架的东西没讲,这里都可以从顶部克森介绍的链接中学到。

好了,接下来就是我们的测试阶段了。由于 Unity Shader 是实时运算的,因此不在 Play 模式下也可以看到效果。好,现在修可以改一下Inspector面板Material中的“_Translational”的数值差点效果是不是和预期的一致(可以通过修改物体的Position值来检验):

Shader模式下

Position模式下

PS:在这里我新创建了一个 Cube,这便于对于最终效果。

好了,和预期的效果是一致的。大家也可以修改一下参数玩玩。是不是觉得很简单,因为与使用C#脚本编写的步骤惊人的相似。

这个就是缩放矩阵,其中“Sx”、“Sy”、“Sz”就是各个轴上的缩放因子。缩放矩阵是矩阵表现物体大小变换的矩阵。如果缩放因子小于1,表现为物体缩小;如果大于1,则表现为物体扩大,如果等于1则不发生变化。(照搬上一篇文章的东西)

接下来,让我们回到 Shader 脚本中,添加一个点代码即可:

首先添加了一个向量类型的属性“_Scale”,它用于修改缩放矩阵所对应的缩放因子。

接下来创建了一个函数:

这个函数也很简单,就是用于返回一个设置好的缩放矩阵。

接下来就是在顶点程序里面进行计算,然而这里克森多了一步判断:

这段代码也很简单,当你在 Inspector 面板选择 Shader 的“Transform”属性中选择“Scale”便对应着我们的缩放矩阵:

接下来做个测试:

PS:为了方便观察,克森新建了一个 Cube 物体,并且修改它的 Transform 组件的 Scale 属性。

看样子跟预期的效果是一样的,说明我们成功了。

上图就是所谓的旋转矩阵。在上一篇文章中虽然有讲到旋转矩阵,但是讲得不够系统,不够全面,不够清楚。因此呢,克森会在这篇文章中详细的给大伙们讲讲这个旋转矩阵的推导过程。

旋转矩阵到底是怎样运作的呢?下面我们通过一个小小的实验来分析分析这个问题。

现在让我们限制其他轴,只旋转 Z-轴。围绕一个点旋转,就像旋转一个轮胎一样。因为Unity使用的是左手坐标系,因为Z轴的旋转的正方向是围绕逆时针旋转的,得到如下图所示: 

2D旋转示意图

我们假设这个是一个单位圆(也就是半径为1),如下图所示:

接下来我们来做一些操作,让这个圆围绕刚刚我们设定的 Z-轴旋转一圈,我们来观察观察都有些什么规律:

我们先来看看 X-轴(就是红色的线)的变化,变化的过程由(1,0)->(0,1)->(-1,0)->(0,-1)->(1,0)。大家有没有发现什么规律?下面再给大家上一个图:

哈哈,现在是不是有一点感觉了。假设我们的 X-轴的点为(x,y)。旋转一圈的变化过程为:x(1 -> 0 -> -1 -> 0 -> 1),y(0 -> 1 -> 0 -> -1 -> 0)。那么我们便可以把这个变化过写成:(cosZ,sinZ)。同样的 Y-轴点的旋转变化便能写成:(-sinZ,cosZ),大家可以根据 X-轴的推导过程自己去试着推导一下。

好,(cos,sin)和(-sin,cos)只是相对于各个轴上的点,现在我们要做的就是把他们组合起来,假设有一个点为(x,y),我们要让它转换为 xX yY。当没有发生旋转的时候,便为 x(1,0) y(0,1) = (x,y) 。带入上面我们推导出的东西便为:x(cosZ,sinZ) y(-sinZ,cosZ)= (x cosZ - y sinZ,x sinZ y cosZ)。

接下来让我们把上面推导的东西转换成代码:

PS:由于代码太长,上面的代码其实分成了两张图片。

首先声明了一个 float 类型的属性“_Angle”,它用于设置 Z-轴的旋转量。

接下来利用我们推导出来的东西创建一个函数:

这个函数也很简单,就是对应之前推导出来公式:x(cosZ,sinZ) y(-sinZ,cosZ)= (x cosZ - y sinZ,x sinZ y cosZ)。 

接下来就是在顶点程序里面判断即可:

这段代码不用说了吧,就是回到 Inspecor面板中在 Shader 的“Transform”属性中选择 Rotaion 即可。

好,接下来我们做个测试:

Perfect. 和我们预期的效果一样,大伙们可以自行修改参数进行测试一番。

好,在这里我们只做了一个轴的旋转,并且,细心的朋友可能会注意,该函数的返回值是一个float3的数据类型,而不是我们的主题 -- 旋转矩阵。

其实呢,刚刚的推导只是一个2D旋转的推导,近下来我们要做的就是由2D旋转转换到3D旋转,并且完成一个能任意旋转各轴的函数的编写。

我先把(x,y)转换成矩阵。同样的,(x cos Z - y sinZ,x sinZ y cosZ)便能转换成这样子:

注意,我们使用矩阵相称的时候要把 放在后面,例如:  。

如果你还不了解矩阵乘法,请简单的看下图,如果看了还不会的话,还请您去简单的学习学习:

OK,直到现在我们还困在 2D 旋转的圈子里,接下来就是把 2D 旋转转换为 3D 旋转,其实就是加入一个元素 Z 。

Okey,现在我们加上了一个元素 Z,但是我们发现这样似乎无法计算,因为第一个矩阵的列不等于第二个矩阵的行。因此,我们要为第一个矩阵补全一些元素:

然而我们还是发现了一个问题,计算出来的结果的第三行始终为 0 。好,下面我们把第一个矩阵的第三行的最后一个元素修改为 1 :

Perfect,这回像点样子了。

好,接下来推导其它轴的旋转。绕 Y-轴旋转的时候,旋转一圈后 X-轴的变化过程可以写成:,Z-轴 的变化过程可以写成:。最后根据上面的公式组合起来得到下面的矩阵:

相同的绕 X-轴旋转的旋转矩阵为:

PS:首先教大家一个规律:如果绕那个轴旋转,那么最后得到的矩阵行和列都没有改变(矩阵的原型是单位矩阵)。例如绕 X-轴旋转,那么最后得到的矩阵的第一行和第一列便没有发生改变(把X看做1,Y看做2,Z看做3)。

对于绕某轴旋转时,各个轴的点旋转一圈的变化推导过程还是不懂的,克森接下来简单的教大家用 Unity 来观察实现。

首先创建一个物体,克森创建的是一个球体,然后设置所显示的坐标为本地坐标,如下图所示:

好,接下来你就可以推导了,比如现在我要推导出绕 Y-轴旋转时,各个轴上点的变换过程:

注意看克森画圈的地方,现在我绕 Y-轴旋转了90°,而X轴和Z轴所指的方向发生了改变。接下来,你们知道怎么做了吧,仿造下图进行推导即可:

接下来将这三个旋转矩阵组合起来,实现只需一个函数便能旋转任意一个轴。

首先我们先把 Y-轴的矩阵乘上 Z-轴的矩阵(即 YxZ):

然后再用得到的矩阵乘上 X-轴的矩阵:

PS:好像只能按照这个顺序来相乘,反正公式里是这样的,大伙们可以试试其他顺序。

Ok,我们的组合矩阵完成了。

咦,但是不对呀。我们代码里面的矩阵是 4x4 的矩阵呀,因此,我们要把他转换为一个 4x4 的矩阵,其实很简单,该补的地方补上即可,如下图所示:

好了,接下来就用代码把上图给实现出来:

首先声明一个属性“_Rotation”,用于修改各个旋转轴的分量:

然后依据推导出来的矩阵来创建一个函数:

最后再顶点程序里面判断即可:

接下来请大伙们自行验证即可。

好了,这篇文章就到这里了。不知道对大家有没有用。总之呢,克森是很用心很用心的写了,不好的地方请大伙们指出,克森会努力改正的。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有