裁剪
1、 一种比较笨拙的裁剪方式:逐像素裁剪
使用discard 可以丢弃掉一些不需要渲染的像素点,需要写在fragment方法中,根据判断像素在==模型空间坐标系==的Y轴的坐标进行裁剪,比如下面的代码,就是吧一个模型的上半部分裁剪掉:
```
float4 frag(vertexOutput input) : COLOR
{
if (input.posInObjectCoords.y > 0.0)
{
discard; // drop the fragment if y coordinate > 0
}
return float4(0.0, 1.0, 0.0, 1.0); // green
}
```
先来分析一下上面这个裁剪方法吧,是在即将要渲染这个片元的时候才进行discard,要知道我们游戏中有多少个模型,又有多少个像素点要渲染,对于硬件来说,走到这一步才忽略,从性能的角度来讲,是个很糟糕的办法,所以在我们正常的shader中,不要使用这个discard,否则带来的性能问题,绝对不是你想看到的。
虽然这个方法不太好,但是我们还是需要学习它的一些东西的;上面说的实在模型坐标系中进行裁剪,那如果我们在游戏开发中,需要世界坐标系下,或者是在相机的视口下进行裁剪怎么办呢?仅仅是模型坐标系是满足不了的,那就看下下面的世界坐标系下的裁剪吧;
如果你比较熟悉Unity中的脚本编写,你可能会尝试下面的做法,在Shader中定义一个四维的矩阵参数,值是(模型的世界坐标到模型坐标的矩阵)逆转换矩阵,然后在shader中进行计算片元在世界坐标系下的坐标转换为模型坐标系下的坐标进行计算,当你拥有了模型坐标系下的坐标,那么就很容易通过上面的方式来进行discard了。
2、裁剪面
主要是对物体的某些像素点进行忽略渲染,这里是用==Cull==关键字进行裁剪面渲染;这句话要写在CGPROGRAM 前面,因为不是CG语句,是个==Unity ShaderLab命令==
Shader中的Pass块里有这么一行代码 Cull Off,这一行在CGPROGRAM之前,因为它不是Cg,事实上,它是一个Unity ShaderLab的命令,意思是关闭任何三角面的裁剪,(也就是渲染任何三角面)。为什么要设置这个Off呢,因为Shader默认的裁剪方式是Cull Back,因为我们再游戏中,模型的内表面基本是不可见的,所以如果我们不设置Off,那就会裁剪我们看不到的那一面,也就是Back,当然,如果我们不需要渲染的话,最好关闭,==性能问题要时刻注意==。
那么,Culling是怎么工作的呢,其实三角面和顶点还是正常的处理,只是在摄像机后处理阶段,GPU定义哪些三角面的某个顶点可见,哪些不可见,基于这个测试,每个三角面被分成前面和后面,如果标记了Cull Front 那么前面就会被discard,Cull Back反之,如果都没标记,那么双面都会被渲染。
So,我们能裁剪什么呢?一个程序可能使用了多个不同的Shader来渲染模型外表面,很少渲染模型内表面的,下面的Shader有两个Pass块,第一个裁剪外表面,
其他的面也就是内表面被渲染成红色,第二个Pass块裁剪了内表面,吧外表面渲染成绿色,所以整体来说,下面的Shader吧模型的内表面渲染成红色,外表面渲染成绿色。
Shader "Cg shader with two passes using discard"
{
SubShader
{
// first pass (is executed before the second pass)
Pass
{
Cull Front // cull only front faces
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct vertexInput
{
float4 vertex :POSITION;
};
struct vertexOutput
{
float4 pos : SV_POSITION;
float4 posInObjectCoords : TEXCOORD0;
};
vertexOutput vert (vertexInput input)
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
output.posInObjectCoords = input.vertex;
return output;
}
float4 frag (vertexOutput input) :COLOR
{
if (input.posInObjectCoords.y > 0.0)
{
discard; // drop the fragment if y coordinate > 0
}
return float4(1.0, 0.0,