效果展示
三角面转为三菱体的原理解析
- 我们已知一个图元如下图:
三 角 面 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(P0−P1−P2)为输入的三角面图元,向量V0=P2−P0,向量V1=P1−P0
-
三角面挤出为三菱体的效果如下:
点 P 3 、 P 4 、 P 5 为 挤 出 后 生 成 的 点 点P_3、P_4、P_5为挤出后生成的点 点P3、P4、P5为挤出后生成的点
我 们 只 需 要 求 出 向 量 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 我们只需要求出向量V,就可以通过点P0、P1、P2求出点P3、P4、P5
很 明 显 , 向 量 V 就 是 向 量 V 1 和 向 量 V 0 的 叉 乘 , 即 : c r o s s ( V 1 , V 0 ) 很明显,向量V就是向量V_1和向量V_0的叉乘,即:cross(V1, V0) 很明显,向量V就是向量V1和向量V0的叉乘,即:cross(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=(P0、P3、P2)
P l a n e 1 = ( P 3 、 P 5 、 P 2 ) Plane1=(P_3、P_5、P_2) Plane1=(P3、P5、P2)
P l a n e 2 = ( P 3 、 P 0 、 P 4 ) Plane2=(P_3、P_0、P_4) Plane2=(P3、P0、P4)
P l a n e 3 = ( P 4 、 P 0 、 P 1 ) Plane3=(P_4、P_0、P_1) Plane3=(P4、P0、P1)
P l a n e 4 = ( P 5 、 P 1 、 P 2 ) Plane4=(P_5、P_1、P_2) Plane4=(P5、P1、P2)
P l a n e 5 = ( P 5 、 P 4 、 P 1 ) Plane5=(P_5、P_4、P_1) Plane5=(P5、P4、P1)
P l a n e 6 = ( P 3 、 P 4 、 P 5 ) Plane6=(P_3、P_4、P_5) Plane6=(P3、P4、P5) -
计算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
}
}
}
效果展示
默认的球体:
挤出三角面片的效果: