【Unity Shader入门】5、几何着色器Geometry Shaders之实例1:通过一个三角面片挤出

效果展示

三角面转为三菱体的原理解析

  • 我们已知一个图元如下图:
    在这里插入图片描述

三 角 面 P l a n e ( P 0 − P 1 − P 2 ) 为 输 入 的 三 角 面 图 元 , 向 量 V 0 = P 2 − P 0 , 向 量 V 1 = P 1 − P 0 三角面Plane(P_0-P_1-P_2)为输入的三角面图元, 向量V_0=P_2-P_0, 向量V_1=P_1-P_0 Plane(P0P1P2)V0=P2P0,V1=P1P0

  • 三角面挤出为三菱体的效果如下:
    在这里插入图片描述
    点 P 3 、 P 4 、 P 5 为 挤 出 后 生 成 的 点 点P_3、P_4、P_5为挤出后生成的点 P3P4P5
    我 们 只 需 要 求 出 向 量 V , 就 可 以 通 过 点 P 0 、 P 1 、 P 2 求 出 点 P 3 、 P 4 、 P 5 我们只需要求出向量V,就可以通过点P_0、P_1、P_2求出点P_3、P_4、P_5 VP0P1P2P3P4P5
    很 明 显 , 向 量 V 就 是 向 量 V 1 和 向 量 V 0 的 叉 乘 , 即 : c r o s s ( V 1 , V 0 ) 很明显,向量V就是向量V_1和向量V_0的叉乘,即:cross(V1, V0) VV1V0cross(V1,V0)

  • 重构三角面
    挤出点后,还需要构建三角面,如果舍弃三菱体的底面,那三角面总共需要7个,即输出的顶点要21个。几何着色器的最大顶点数就要是21以上了,即:[maxvertexcount(21)]
    7个三角面的和顶点的关系如下(Unity顶点的顺序是逆时针的):
    P l a n e 0 = ( P 0 、 P 3 、 P 2 ) Plane0=(P_0、P_3、P_2) Plane0=(P0P3P2)
    P l a n e 1 = ( P 3 、 P 5 、 P 2 ) Plane1=(P_3、P_5、P_2) Plane1=(P3P5P2)
    P l a n e 2 = ( P 3 、 P 0 、 P 4 ) Plane2=(P_3、P_0、P_4) Plane2=(P3P0P4)
    P l a n e 3 = ( P 4 、 P 0 、 P 1 ) Plane3=(P_4、P_0、P_1) Plane3=(P4P0P1)
    P l a n e 4 = ( P 5 、 P 1 、 P 2 ) Plane4=(P_5、P_1、P_2) Plane4=(P5P1P2)
    P l a n e 5 = ( P 5 、 P 4 、 P 1 ) Plane5=(P_5、P_4、P_1) Plane5=(P5P4P1)
    P l a n e 6 = ( P 3 、 P 4 、 P 5 ) Plane6=(P_3、P_4、P_5) Plane6=(P3P4P5)

  • 计算UV
    计算UV的方法根据自己的需求,我这里给出我自己展UV的习惯
    在这里插入图片描述
    Plane6的UV与几何体默认的UV一致。

Shader代码

Shader "LST/GS/GSShader02"
{
	Properties
	{
		_MainTex("MainTex", 2D) = "white" {}
		//三角面挤出的长度
		_Length("Length", Float) = 0.02
	}

	SubShader
	{
		Pass
		{
			Tags{ "RenderType" = "Opaque" }
			LOD 200

			CGPROGRAM
			//设定着色器编译目标级别为4.0(几何着色器4.0以上才能支持)
			#pragma target 4.0
			#pragma vertex VS_Main
			//设定几何体着色器函数名称为GS_Main
			#pragma geometry GS_Main
			#pragma fragment FS_Main
			#include "UnityCG.cginc"

			uniform sampler2D _MainTex;
			uniform float _Length;

			struct v2g
			{
				float4  pos     : POSITION;
				float2  uv     : TEXCOORD0;
			};

			struct g2f
			{
				float4  pos     : POSITION;
				float2  uv     : TEXCOORD0;
			};

			// Vertex Shader
			v2g VS_Main(appdata_base v)
			{
				v2g o = (v2g)0;
				o.pos = v.vertex;
				o.uv  = v.texcoord;

				return o;
			}

			// 几何着色器
			[maxvertexcount(21)] 
			void GS_Main(triangle v2g p[3], inout TriangleStream<g2f> tStream)
			{



				//求出向量V0和V1
				float3 V0 = p[2].pos.xyz - p[0].pos.xyz;
				float3 V1 = p[1].pos.xyz - p[0].pos.xyz;
				//通过V0和V1的叉乘求出V
				float3 V = normalize(cross(V1, V0));

				//求出P3、P4、P5
				float4 p0 = UnityObjectToClipPos(p[0].pos);
				float4 p1 = UnityObjectToClipPos(p[1].pos);
				float4 p2 = UnityObjectToClipPos(p[2].pos);
				float4 p3 = UnityObjectToClipPos(float4(p[0].pos.xyz + V * _Length,1));
				float4 p4 = UnityObjectToClipPos(float4(p[1].pos.xyz + V * _Length,1));
				float4 p5 = UnityObjectToClipPos(float4(p[2].pos.xyz + V * _Length,1));

				g2f o;

				//Plane0=(P0、P3、P2)
				o.pos = p0;//P0
				o.uv = float2(0.3333,0);
				tStream.Append(o);//把顶点添加到流
				o.pos = p3;//P3
				o.uv = float2(0.3333,1);
				tStream.Append(o);
				o.pos = p2;//P2
				o.uv = float2(0,0);
				tStream.Append(o);
				tStream.RestartStrip();//三个顶点都添加到流后使用RestartStrip()构成一个图元

				//Plane1=(P3、P5、P2)
				o.pos = p3;//P3
				o.uv = float2(0.3333,1);
				tStream.Append(o);
				o.pos = p5;//P5
				o.uv = float2(0,1);
				tStream.Append(o);
				o.pos = p2;//P2
				o.uv = float2(0,0);
				tStream.Append(o);
				tStream.RestartStrip();

				//Plane2=(P3、P0、P4)
				o.pos = p3;//P3
				o.uv = float2(0.3333,1);
				tStream.Append(o);
				o.pos = p0;//P0
				o.uv = float2(0.3333,0);
				tStream.Append(o);
				o.pos = p4;//P4
				o.uv = float2(0.6666,1);
				tStream.Append(o);
				tStream.RestartStrip();

				//Plane3=(P4、P0、P1)
				o.pos = p4;//P4
				o.uv = float2(0.6666,1);
				tStream.Append(o);
				o.pos = p0;//P0
				o.uv = float2(0.3333,0);
				tStream.Append(o);
				o.pos = p1;//P1
				o.uv = float2(0.6666,0);
				tStream.Append(o);
				tStream.RestartStrip();

				//Plane4=(P5、P1、P2)
				o.pos = p5 ;//P5
				o.uv = float2(1,1);
				tStream.Append(o);
				o.pos = p1;//P1
				o.uv = float2(0.6666,0);
				tStream.Append(o);
				o.pos = p2;//P2
				o.uv = float2(1,0);
				tStream.Append(o);
				tStream.RestartStrip();

				//Plane5=(P5、P4、P1)
				o.pos = p5 ;//P5
				o.uv = float2(1,1);
				tStream.Append(o);
				o.pos = p4;//P4
				o.uv = float2(0.6666,1);
				tStream.Append(o);
				o.pos = p1;//P1
				o.uv = float2(0.6666,0);
				tStream.Append(o);
				tStream.RestartStrip();

				//Plane6=(P3、P4、P5)
				o.pos = p3 ;//P3
				o.uv = p[0].uv;
				tStream.Append(o);
				o.pos = p4;//P4
				o.uv = p[1].uv;
				tStream.Append(o);
				o.pos = p5;//P5
				o.uv = p[2].uv;
				tStream.Append(o);
				tStream.RestartStrip();
			}

			// Fragment Shader
			float4 FS_Main(g2f i) : COLOR
			{
				return tex2D(_MainTex, i.uv);
			}

			ENDCG
		}
	}
}

效果展示

默认的球体:
在这里插入图片描述
挤出三角面片的效果:
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值