Unity Shader:几何着色器

Unity Shader:几何着色器,第1张

在我翻译过的OpenGL和实时渲染相关文章中,简要介绍过几何着色器,它的执行顺序位于细分曲面着色器、光栅化与片元着色器之间,有时不会使用细分曲面着色器,且常不表示固定阶段,所以简要来说,顶点着色器的输出到几何着色器,接着进行某些增减基本体的 *** 作,然后进入片元着色器进行光照计算 *** 作。

几何着色器本质上最常用的是增加基本体,可以用于生成粒子,毛发等。

Unity中,和顶点与片元着色器一样,使用一个预编译指令来标明函数,且额外定义一个结构体用于变量的输入输出,供着色器之间通信。这里给出一个简单的几何着色器例子:

注意三个结构体:

对于将顶点转换到裁剪空间,以及变换UV的 *** 作,我们在几何着色器中执行了,实际上也可以在顶点着色器中执行,只是这么做的话,更灵活。

对于几何着色器函数,这里复制一下:

maxvertexcount 代表几何着色器会增加的顶点的最大数量。由于我们在物体上实际添加一个三角形,所以这里设置为3.

接下来讲解几何着色器函数的参数:

接着讲解函数体。首先我们定义一个 g2f 的结构体对象,我们会对其进行 *** 作然后加入列表中。

然后,我们进行一个简单的循环,将每个输入的顶点添加到流中,创建三角形。因为数据要传入片元着色器,因此我们将顶点坐标转换到裁剪空间,并且按系数偏移UV。

最后,我们使用 triStream.Append(o) 将一个修改过的 g2f 结构体添加到三角形流中。在结束循环后,使用 RestartStrip 函数,这可以让流明白一个独立的三角形要在之后添加。这里并没有额外生成顶点等,一切保持原状。

现在我们扩展这个简单的几何着色器,我们从每个三角形上挤出一个金字塔的形状,即在三角形中心添加一个顶点,然后沿法线方向挤出面。

在最开始,我们添加了 _ExtrusionFactor 属性,用于控制挤出的高度。接着开启 Cull Off ,关闭面消隐。

在几何着色器函数中,我们首先设置最大输出顶点数量,相当于生成4个三角形,即在每个三角形的基础上生成3个三角形来组成锥体。

对于挤出 *** 作,我们需要每个三角形的中心作为法线,因此,我们通过对三角形各个顶点的坐标做平均计算来得到重心,然后同样通过平均计算来得到三角形的法线。

然后我们生成锥体,算法过程为:

这就是第一个循环所做的事情。第二个循环中,我们将最开始的三角形组装起来,然后就可以得到想要的三角锥了。

注意到网上的Shader代码中的最后一行FallBack "Specular"没有?该语句的意思是如果没有找到适合该Shader的硬件,那么自动匹配Unity3D自带的Specular Shader。

那么答案就很清楚了:Unity3D自带的Shader必须全面的针对几乎所有可能出现的硬件,所以要添加尽量多的分支来满足要求。每一个分支匹配不同的硬件。而网上下载的Shader往往只需要考虑几种硬件就可以了。一般Shader作者会标明是否匹配移动平台,适应OpenGL ES1,2,3还是需要DX11支持等信息。如果没有标明那么你就只能自己尝试了。

首先在场景中放几个火盆,随便你想放几个。当然这里放几个,后面shader里就需要几张遮罩贴图。这里我们放俩个火盆。

我们在shader中添加三张贴图来做遮罩,猪脚一张、火盆三张,分别为

_Mask ("Mask", 2D) = "white" {}

_Mask0 ("Mask0", 2D) = "white" {}

_Mask1 ("Mask1", 2D) = "white" {}

在纹理混合中进行如下设置:

SetTexture [_Mask] {combine texture}

SetTexture [_MainTex] {combine texture,texture-previous}

SetTexture [_Mask0] {combine previous,previous-texture}

SetTexture [_Mask1] {combine previous,previous-texture}

SetTexture 的原理在

unity用shader遮罩模拟黑夜火把照明效果

中有说过,这里就不详细说了

总之就是将上一步计算的的alpha通道值减去这张贴图的alpha通道值就是了。

保存一下,回到我们的主界面,将我们的遮罩贴图拖到三个子贴图中,

但是这样场景中只看到了一个光圈。

我们把他的offset都偏移一下,这样三个就齐了。

将光圈对准火盆与光圈跟随猪脚移动原理一样。

下一步让光圈移到火盆处。

我们打开脚本,

脚本中添加:

public GameObject fire

public GameObject fire0

然后按照获得俩火盆的位置:

float firex = fire.transform.position.x

float firey = fire.transform.position.y

float fire0x = fire0.transform.position.x

float fire0y = fire0.transform.position.y

然后就是根据火盆的位置获得遮罩的偏移量:

float offsetfirex=-firex/(Le*2f)

float offsetfirey=-firey/(Wi*2f)

float offsetfire0x=-fire0x/(Le*2f)

float offsetfire0y=-fire0y/(Wi*2f)

最后是改变遮罩的位置:

renderer.material.SetTextureOffset ("_Mask0", new Vector2 (offsetfirex,offsetfirey))

renderer.material.SetTextureOffset ("_Mask1", new Vector2 (offsetfire0x,offsetfire0y))

OK,回到场景运行,测试一下效果不错:

我们最后让火盆的光圈也能和猪脚一样忽大忽小:

我们在如图所示脚本位置添加:

renderer.material.SetTexture("_Mask0",mask[i])

renderer.material.SetTexture("_Mask1",mask[i])

具体脚本如下:

f(Time.time>b){

b=b+c

if(i<mask.Length-1){

i++

}else

{

i=0

}

renderer.material.SetTexture("_Mask",mask[i])

renderer.material.SetTexture("_Mask0",mask[i])

renderer.material.SetTexture("_Mask1",mask[i])

}

原理就是循环一组大小不同的的光圈图片作为遮罩的贴图,具体在

unity 贴图动画实现照明忽大忽小

http://jingyan.baidu.com/article/72ee561a58724ae16138df25.html

里面说过,就不详细说了。

最终脚本如下图:

OK,最终效果如下图,很不错吧!


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/7896075.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-11
下一篇 2023-04-11

发表评论

登录后才能评论

评论列表(0条)

保存