Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

问题背景:

我们开发中需要有“点”对象,可以是像素的(不具备透视效果),始终等大,还有就是3D场景下的矢量点(随相机距离透视变化的)。

问题解决思路:

方案1:使用GS扩充顶点,并扩充三角面,通过GS直接绘制出想要图形点(我这里有几种图形的点)

方案2:使用GS扩充顶点,绘制出正方形面,到FS中去截取想要的形状

这两种方案基本思想都是一样的,我这里提供两种方案是因为我这个点的边框是有要求的,用GS扩线围一圈效果不好

知识扩展:

Geomotry Shader(几何着色器):几何着色器是可选的着色器,它位于顶点和片段着色器之间,它以一个或多个表示为一个单独基本图形(primitive)即图元的顶点作为输入,比如可以是一个点或者三角形,几何着色器在将这些顶点发送到下一个着色阶段之前,可以将这些顶点转变为它认为合适的内容。几何着色器有意思的地方在于它可以把(一个或多个)顶点转变为完全不同的基本图形(primitive),从而生成比原来多得多的顶点。

 

上面是官方解释,通俗来讲:就是GeometryShader接收的实际上是VS输出的图元,对这些图元进行添加,修改,删除,然后输出新的图元信息。

 

图片说明:

Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

这也就是人们常见的shader流程图。

具体实现代码:

方案一:

  1 Shader "Vector/Point"
  2 {
  3     Properties
  4     {
  5         _Color("MianColor",color)=(1,1,1,1)
  6     }
  7     SubShader
  8     {
  9         Pass
 10         {
 11             Tags { "RenderType"="Opaque" }
 12             LOD 100 
 13             Cull Off
 14             CGPROGRAM
 15             #pragma target 4.0
 16             #pragma vertex vert
 17             #pragma fragment frag
 18             #pragma geometry geom            
 19             #include "UnityCG.cginc" 
 20             struct appdata
 21             {
 22                 float4 vertex : POSITION;
 23                 float2 uv : TEXCOORD0;
 24                 float3 normal : NORMAL;
 25             }; 
 26             struct v2g
 27             {
 28                 float4 vertex : POSITION;
 29                 float3 nor:NORMAL;
 30             };
 31             struct g2f
 32             {
 33                 float4 vertex : SV_POSITION;
 34                 float3 norg:NORMAL;
 35             };
 36 
 37             fixed4 _LightColor0;
 38             fixed4 _Color;
 39             float radius;
 40             float initOffsetAngle=0;
 41             float verticesNumber=3;
 42             float IsEqualPixelPoint=0.0;
 43 
 44             v2g vert(appdata_base v)
 45             {
 46                 v2g o;
 47                 o.vertex = v.vertex;
 48                 o.nor=v.normal;
 49                 return o;
 50             }
 51  
 52         void ADD_VERTEX(float3 v,g2f o,inout TriangleStream<g2f> tristream)
 53         {
 54            o.vertex = UnityObjectToClipPos(v); 
 55            tristream.Append(o);
 56         }      
 57         void  ADD_INFO(float3 p0,float3 p1,float3 p2,g2f o,inout TriangleStream<g2f> tristream)
 58         {
 59 
 60             ADD_VERTEX(p0,o,tristream);
 61             ADD_VERTEX(p1,o,tristream);
 62             ADD_VERTEX(p2,o,tristream);
 63             tristream.RestartStrip();
 64         }
 65                   
 66        // 根据模型坐标获得屏幕坐标
 67        float4 GetScreenPos(float4 vertex)
 68         {
 69           float4 pos = UnityObjectToClipPos(vertex);
 70           //return getScreenPosByClipPos(pos);
 71 
 72           pos = ComputeScreenPos(pos);
 73           pos.xy = pos.xy / pos.w;
 74           pos.xy = pos.xy * _ScreenParams.xy;
 75           return pos;
 76        }
 77 
 78         //将旋转完的坐标转回剪裁空间下
 79         void ADD_VERTEX_Other(float4 v,g2f o,inout TriangleStream<g2f> tristream)
 80         {
 81             float4 pos=v;
 82             pos.xy=v.xy/_ScreenParams.xy;
 83             pos.xy=pos.xy * v.w;
 84 
 85             pos.y= (pos.y-(0.5*pos.w))/(_ProjectionParams.x * 0.5);
 86             pos.x=(pos.x-(0.5*pos.w))/0.5;
 87 
 88             o.vertex = pos; 
 89             tristream.Append(o);
 90         }     
 91         
 92         void  ADD_INFO_Other(float4 p0,float4 p1,float4 p2,g2f o,inout TriangleStream<g2f> tristream)
 93         {
 94             ADD_VERTEX_Other(p0,o,tristream);
 95             ADD_VERTEX_Other(p1,o,tristream);
 96             ADD_VERTEX_Other(p2,o,tristream);
 97             tristream.RestartStrip();
 98         }
 99 
100         [maxvertexcount(60)]
101         void geom(triangle v2g IN[3], inout TriangleStream<g2f> tristream)
102         {
103            g2f o; 
104            if(IsEqualPixelPoint==0.0)
105            {
106             float3 p0=float3(0,0,0);
107             float3 dir=normalize( mul(unity_WorldToObject,_WorldSpaceCameraPos)-IN[0].vertex);
108             float3 cy=float3(0,1,0);
109             float3 right=normalize(cross(cy, dir));
110             float3 up=normalize(cross(dir,right));
111             float3 p=cy * radius;
112             //第一个点
113             float3 p1=float3((cos(radians(initOffsetAngle)) * (p).x)-(sin(radians(initOffsetAngle)) * (p).y),(sin(radians(initOffsetAngle)) * (p).x)+(cos(radians(initOffsetAngle)) * (p).y),(p).z);
114             float3 p2=float3(0,0,0);
115             float3 p3=float3(0,0,0);
116             float angle= radians(360/verticesNumber);
117             p2=float3((cos(angle) * (p1).x)-(sin(angle) * (p1).y),(sin(angle) * (p1).x)+(cos(angle) * (p1).y),(p1).z);
118 
119             float3 p1p=(p1.x*right+p1.y*up+p1.z*dir);
120             p2=(p2.x*right+p2.y*up+p2.z*dir);
121 
122             float3 edgeA = p2 - p1p;
123             float3 edgeB = p3 - p1p;
124             float3 normalFace = normalize(cross(edgeA, edgeB));
125             o.norg=-normalFace;
126 
127             ADD_INFO(p0,p1p,p2,o,tristream);
128 
129             for (float i=1.0; i<verticesNumber;i+=1.0)
130             {
131                 p2=float3((cos(i*angle) * (p1).x)-(sin(i*angle) * (p1).y),(sin(i*angle) * (p1).x) + (cos(i*angle) * (p1).y),(p1).z);
132                 p3=float3((cos((i+1)*angle) * (p1).x)-(sin((i+1)*angle) * (p1).y),(sin((i+1) * angle) * (p1).x)+(cos((i+1) * angle) * (p1).y),(p1).z);
133     
134                 p2=(p2.x*right+p2.y*up+p2.z*dir);
135                 p3=(p3.x*right+p3.y*up+p3.z*dir);
136 
137                 float3 edgeA = p2 - p1;
138                 float3 edgeB = p3 - p1;
139                 float3 normalFace = normalize(cross(edgeA, edgeB));
140                 o.norg=-normalFace;
141 
142                 ADD_INFO(p0,p2,p3,o,tristream);
143             }
144           }
145           else
146           {
147             //等像素
148             float4 pp0=float4(0,0,0,1);
149             pp0= GetScreenPos(pp0);
150             float2 up=float2(0,1);
151             float2 pp=up * radius;
152             //第一个点
153             float4 pp1=pp0;
154             float4 pp2=pp0;
155             float4 pp3=pp0;
156             pp1.xy= float2((cos(radians(initOffsetAngle)) * (pp).x)-(sin(radians(initOffsetAngle)) * (pp).y),(sin(radians(initOffsetAngle)) * (pp).x)+(cos(radians(initOffsetAngle)) * (pp).y));
157             float angle= radians(360/verticesNumber);
158             pp2.xy=float2((cos(angle) * (pp1).x)-(sin(angle) * (pp1).y),(sin(angle) * (pp1).x)+(cos(angle) * (pp1).y));
159             float3 edgeA = pp2 - pp1;
160             float3 edgeB = pp3 - pp1;
161             float3 normalFace = normalize(cross(edgeA, edgeB));
162             o.norg=-normalFace;
163 
164             ADD_INFO_Other(pp0,pp1+float4(pp0.xy,0,0),pp2+float4(pp0.xy,0,0),o,tristream);
165 
166            for (float i=1.0; i<verticesNumber;i+=1.0)
167             {
168                 pp2=pp0;
169                 pp3=pp0;
170                 pp2.xy=float2((cos(i*angle) * (pp1).x)-(sin(i*angle) * (pp1).y),(sin(i*angle) * (pp1).x) + (cos(i*angle) * (pp1).y));
171                 pp3.xy=float2((cos((i+1)*angle) * (pp1).x)-(sin((i+1)*angle) * (pp1).y),(sin((i+1) * angle) * (pp1).x)+(cos((i+1) * angle) * (pp1).y));
172 
173                 float3 edgeA = pp2 - pp1;
174                 float3 edgeB = pp3 - pp1;
175                 float3 normalFace = normalize(cross(edgeA, edgeB));
176                 o.norg=-normalFace;
177 
178                 ADD_INFO_Other(pp0,pp2+float4(pp0.xy,0,0),pp3+float4(pp0.xy,0,0),o,tristream);
179             }
180           }
181         } 
182             fixed4 frag (g2f i) : SV_Target
183             {
184               return _Color;
185             }
186             ENDCG
187         }
188     }
189 }

代码分析:

1.从模型坐标-剪裁空间坐标-屏幕空间坐标,如下:

        float4 GetScreenPos(float4 vertex)
          {
            float4 pos = UnityObjectToClipPos(vertex);
            //return getScreenPosByClipPos(pos);
 
           pos = ComputeScreenPos(pos);
          pos.xy = pos.xy / pos.w;
            pos.xy = pos.xy * _ScreenParams.xy;
            return pos;
        }

2.屏幕坐标扩展完坐标转回剪裁空间

       //将旋转完的坐标转回剪裁空间下
         void ADD_VERTEX_Other(float4 v,g2f o,inout TriangleStream<g2f> tristream)
        {
             float4 pos=v;
              pos.xy=v.xy/_ScreenParams.xy;
              pos.xy=pos.xy * v.w;
  
             pos.y= (pos.y-(0.5*pos.w))/(_ProjectionParams.x * 0.5);
             pos.x=(pos.x-(0.5*pos.w))/0.5;
  
             o.vertex = pos; 
              tristream.Append(o);
          }     

 这个地方就是转屏幕坐标的逆运算,主要注意的是定义位于UnityCG.cginc中的内置方法ComputeScreenPos,它的具体逻辑是这样:

inline float4 ComputeScreenPos (float4 pos)
{
    float4 o = pos * 0.5f;
    o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
    o.zw = pos.zw;
    
    return o;
}
即主要做的是就是这:

o.x = (pos.x * 0.5 + pos.w * 0.5)

o.y = (pos.y * 0.5 * _ProjectionParams.x + pos.w * 0.5)

这一步别忘了逆运算回去。

3.这里的算法逻辑是这样:给我一个中心点坐标,我求出正上方点坐标,根据你是几边形,去旋转(乘以旋转矩阵)得到扩展点。上面矢量点主要问题在于,我构建了本地坐标系,旋转就会有坑,因为我正上方点是通过构建坐标系去求得,然而旋转应该在自身坐标系下,
正上方点就是(0,1,0 )而不是自己构建坐标系下的up,记得转完返回去,所以这是一个坑。


方案二:

  1 Shader "MyShader/PointTwo"
  2 {
  3     Properties
  4     {
  5         _Color("MianColor",color)=(1,1,1,1)
  6     }
  7     SubShader
  8     {
  9 
 10         Tags { "RenderType"="Opaque" }
 11         LOD 100 
 12         Cull Off
 13 
 14         CGINCLUDE
 15     
 16         #include "UnityCG.cginc" 
 17 
 18         struct appdata
 19         {
 20             float4 vertex : POSITION;
 21             float2 uv : TEXCOORD0;
 22             float3 normal : NORMAL;
 23             fixed4 color : COLOR; //顶点自身的颜色
 24         }; 
 25 
 26         struct v2g
 27         {
 28             float4 vertex : POSITION;
 29             float3 nor:NORMAL;
 30             fixed4 color : COLOR; //顶点自身的颜色
 31         };
 32         
 33         struct g2f
 34         {
 35             float4 vertex : SV_POSITION;
 36             float3 pos: TEXCOORD0;
 37             float3 centerPos: TEXCOORD1;
 38             float3 norg:NORMAL;
 39             fixed4 color : COLOR; //顶点自身的颜色
 40         };
 41 
 42         //点的颜色
 43         fixed4 _Color;
 44         //边框的颜色
 45         fixed4 _LineColor;
 46         //点的半径大小(四边形内切圆)
 47         float _Radius;
 48         //点的线框宽度
 49         uniform float _LineWidth=5;
 50         //什么图形(-1圆/)
 51         float _PointType=-1;
 52         //是否是像素点
 53         float IsEqualPixelPoint=0.0;
 54         //交叉点宽度
 55         float _CrossPointWidth;
 56  
 57         //矢量点添加扩展点坐标转换      
 58         void ADD_VERTEX(float3 v,g2f o,inout TriangleStream<g2f> tristream)
 59         {
 60            o.vertex = UnityObjectToClipPos(v);
 61            o.pos = v;
 62            tristream.Append(o);
 63         }
 64 
 65         //矢量点添加扩展点面逻辑      
 66         void  ADD_INFO(float3 p0,float3 p1,float3 p2,g2f o,inout TriangleStream<g2f> tristream)
 67         {
 68             ADD_VERTEX(p0,o,tristream);
 69             ADD_VERTEX(p1,o,tristream);
 70             ADD_VERTEX(p2,o,tristream);
 71             tristream.RestartStrip();
 72         }
 73                   
 74        // (像素点)根据模型坐标获得屏幕坐标
 75        float4 GetScreenPos(float4 vertex)
 76         {
 77           float4 pos = UnityObjectToClipPos(vertex);
 78 
 79           pos = ComputeScreenPos(pos);
 80           pos.xy = pos.xy / pos.w;
 81           pos.xy = pos.xy * _ScreenParams.xy;
 82           return pos;
 83        }
 84 
 85         //(像素点)将旋转完的坐标转回剪裁空间下
 86         void ADD_VERT_Other(float4 v,g2f o,inout TriangleStream<g2f> tristream)
 87         {
 88             float4 pos=v;
 89             pos.xy=v.xy/_ScreenParams.xy;
 90             pos.xy=pos.xy * v.w;
 91 
 92             pos.y= (pos.y-(0.5*pos.w))/(_ProjectionParams.x * 0.5);
 93             pos.x=(pos.x-(0.5*pos.w))/0.5;
 94 
 95             o.vertex = pos; 
 96             o.pos=v;
 97             tristream.Append(o);
 98         }     
 99         
100         //像素点添加点
101         void  ADD_INFO_Other(float4 p0,float4 p1,float4 p2,g2f o,inout TriangleStream<g2f> tristream)
102         {
103             ADD_VERTEX_Other(p0,o,tristream);
104             ADD_VERTEX_Other(p1,o,tristream);
105             ADD_VERTEX_Other(p2,o,tristream);
106             tristream.RestartStrip();
107         }
108 
109         // 判断点是否在三角形内
110         float PointinTriangle(float2 A, float2 B, float2 C, float2 P)
111         {
112             float2 ab=B-A;
113             float2 ac=C-A;
114             float2 ap=P-A;
115              
116             float u=(dot(ab,ab) *dot(ap,ac)-dot(ac,ab)* dot(ap,ab)) / (dot(ac,ac) * dot(ab,ab)-dot(ac,ab) * dot(ab,ac));
117             float v=(dot(ac,ac) *dot(ap,ab)-dot(ac,ab)* dot(ap,ac)) / (dot(ac,ac) * dot(ab,ab)-dot(ac,ab) * dot(ab,ac));
118 
119                if (u < 0 || u > 1) // if u out of range, return directly
120                {
121                   return 2 ;
122                }
123 
124                if (v < 0 || v > 1) // if v out of range, return directly
125                 {
126                     return 2 ;
127                 }
128                 return u+v;
129         }
130 
131         //截圆点
132         void DrawCirclePoint(g2f i,float type)
133         {
134 
135             //边框
136             _LineWidth=5;
137 
138             float _R = abs(type) < 0.05 ? _Radius :  (_Radius - _LineWidth);
139 
140             float dis=distance(i.centerPos,i.pos);
141               
142             //剔除圆
143             if(dis > _R)
144             {
145               discard;
146             }
147             
148         }  
149 
150         //截正方形点
151         void DrawSquarePoint(g2f i,float type)
152         {
153             //边框
154             _LineWidth=5;
155 
156             float _R = abs(type) < 0.05 ? 0.9 * _Radius :  (0.9 *_Radius - _LineWidth);
157 
158              //计算边缘点
159              float2 leftTop=float2(i.centerPos.x  - _R , i.centerPos.y +  _R);
160              float2 leftButtom=float2(i.centerPos.x  - _R , i.centerPos.y -  _R);
161              float2 rightTop=float2(i.centerPos.x  + _R , i.centerPos.y +  _R);
162              float2 rightButtom=float2(i.centerPos.x  + _R , i.centerPos.y -  _R);
163                
164              //正方形剔除
165              if(i.pos.x < leftTop.x | i.pos.x > rightTop.x | i.pos.y < leftButtom.y | i.pos.y > rightTop.y)
166              {
167                  discard;
168              }
176         }
177 
178         //截三角形点
179         void DrawTrianglePoint(g2f i,float type)
180         {
181             //边框
182             _LineWidth=5;
183 
184             float _R = abs(type) < 0.05 ? _Radius :  (_Radius - _LineWidth);
185              
186             //计算边缘点
187             float2 leftTop=float2(i.centerPos.x  - _R , i.centerPos.y +  _R);
188             float2 leftButtom=float2(i.centerPos.x  - _R , i.centerPos.y -  _R);
189             float2 rightTop=float2(i.centerPos.x  + _R , i.centerPos.y +  _R);
190             float2 rightButtom=float2(i.centerPos.x  + _R , i.centerPos.y -  _R);
191 
192             //三角形顶点
193             float2 topCenter=(leftTop+rightTop)/2;
194             float2 rightB=float2((i.centerPos.x + 0.707 * _R),i.centerPos.y - 0.5 *_R);
195             float2 leftB=float2((i.centerPos.x - 0.707 * _R),i.centerPos.y - 0.5 *_R);
196 
197             if(PointinTriangle(topCenter,rightB, leftB, i.pos.xy)>1)
198             {
199                 discard;
200             }
259         }
260         
261         //截交叉十字形点
262         void DrawCrossPoint(g2f i,float type)
263         {
264 
265              //边框
266             _LineWidth=5;
267 
268             _CrossPointWidth=16;
269 
270             float _R = abs(type) < 0.05 ? 0.9* _Radius :  (0.92 * _Radius - _LineWidth);
271 
272             float _InPoint = abs(type) < 0.05 ? _CrossPointWidth / 2 :  (_CrossPointWidth - _LineWidth) / 2;
273 
274             //计算边缘点
275             float2 leftTop=float2(i.centerPos.x  - _R , i.centerPos.y +  _R);
276             float2 leftButtom=float2(i.centerPos.x  - _R , i.centerPos.y -  _R);
277             float2 rightTop=float2(i.centerPos.x  + _R , i.centerPos.y +  _R);
278             float2 rightButtom=float2(i.centerPos.x  + _R , i.centerPos.y -  _R);
279 
280             //十字架内角点  
281             float2 inRightTop=float2(i.centerPos.x  + _InPoint , i.centerPos.y +  _InPoint);
282             float2 inLeftTop=float2(i.centerPos.x  - _InPoint , i.centerPos.y + _InPoint);
283             float2 inRightButtom=float2(i.centerPos.x  + _InPoint , i.centerPos.y -  _InPoint);
284             float2 inLeftButtom=float2(i.centerPos.x  - _InPoint , i.centerPos.y -  _InPoint);
285             
286             if(((i.pos.x) > (inRightTop.x) & (i.pos.y) > (inRightTop.y)) | ((i.pos.x) < (inLeftTop.x) & (i.pos.y) > (inLeftTop.y)) | ((i.pos.x) > (inRightButtom.x) & (i.pos.y) < (inRightButtom.y)) | ((i.pos.x) < (inLeftButtom.x) & (i.pos.y) < (inLeftButtom.y)) | ((i.pos.x) < (i.centerPos.x - _R) | (i.pos.x) > (i.centerPos.x+ _R)) | ((i.pos.y) < (i.centerPos.y- _R) | (i.pos.y) > (i.centerPos.y+ _R)))
287             { 
288                 discard;
289             }
298         }
299 
300         v2g vert(appdata_full  v)
301         {
302             v2g o;
303             o.vertex = v.vertex;
304             o.nor=v.normal;
305             o.color=v.color;
306             return o;
307         }
308 
309         [maxvertexcount(12)]
310         void geom(triangle v2g IN[3], inout TriangleStream<g2f> tristream)
311         {
312            g2f o; 
313            //固定只扩展4个点,且初始偏转为45
314            //矢量点
315            if(IsEqualPixelPoint==0.0)
316            {
317             //中心点   
318             float3 centerPos=float3(0,0,0);
319             o.centerPos=centerPos;
320             o.color=IN[0].color;
321 
322             //计算本地坐标系
323             float3 dir=normalize(mul(unity_WorldToObject,_WorldSpaceCameraPos)-IN[0].vertex);
324             float3 worldUp=float3(0,1,0);
325             float3 right=normalize(cross(worldUp, dir));
326             float3 up=normalize(cross(dir,right));
327 
328             //正上方点
329             float3 p=worldUp * _Radius * 1.414;
330             float3 p1=centerPos;
331             float3 p2=centerPos;
332             float3 p3=centerPos;
333             float3 p4=centerPos;
334 
335             //计算偏移角
336             float angle= radians(360/4);
337 
338             //求正方形四顶点
339             p1=float3((cos(radians(45)) * (p).x)-(sin(radians(45)) * (p).y),(sin(radians(45)) * (p).x)+(cos(radians(45)) * (p).y),(p).z);
340             p2=float3((cos(angle) * (p1).x)-(sin(angle) * (p1).y),(sin(angle) * (p1).x)+(cos(angle) * (p1).y),(p1).z);
341             p3=float3((cos(angle * 2) * (p1).x)-(sin(angle * 2) * (p1).y),(sin(angle * 2) * (p1).x)+(cos(angle * 2) * (p1).y),(p1).z);
342             p4=float3((cos(angle * 3) * (p1).x)-(sin(angle * 3) * (p1).y),(sin(angle * 3) * (p1).x)+(cos(angle * 3) * (p1).y),(p1).z);
343             p1=(p1.x * right + p1.y * up + p1.z * dir);
344             p2=(p2.x * right + p2.y * up + p2.z * dir);
345             p3=(p3.x * right + p3.y * up + p3.z * dir);
346             p4=(p4.x * right + p4.y * up + p4.z * dir);
347 
348             //计算法线
349             float3 edgeA = p2 - p1;
350             float3 edgeB = p3 - p1;
351             float3 normalFace = normalize(cross(edgeA, edgeB));
352             o.norg=-normalFace;
353 
354             ADD_INFO(p1,p2,p3,o,tristream);
355             ADD_INFO(p3,p4,p1,o,tristream);
356           }
357           else
358           {
359             //等像素点
360             float4 centerPos1=float4(0,0,0,1);
361             centerPos1= GetScreenPos(centerPos1);
362             float2 up=float2(0,1);
363             float2 pp=up * _Radius * 1.414;
364             //第一个点
365             float4 pp1=centerPos1;
366             float4 pp2=centerPos1;
367             float4 pp3=centerPos1;
368             float4 pp4=centerPos1;
369 
370             //计算偏移角
371             float angle= radians(360/4);
372 
373             //求正方形四顶点
374             pp1.xy=float2((cos(radians(45)) * (pp).x)-(sin(radians(45)) * (pp).y),(sin(radians(45)) * (pp).x)+(cos(radians(45)) * (pp).y));
375             pp2.xy=float2((cos(angle) * (pp1).x)-(sin(angle) * (pp1).y),(sin(angle) * (pp1).x)+(cos(angle) * (pp1).y));
376             pp3.xy=float2((cos(2 * angle) * (pp1).x)-(sin(2 * angle) * (pp1).y),(sin(2 * angle) * (pp1).x)+(cos(2 * angle) * (pp1).y));
377             pp4.xy=float2((cos(3 * angle) * (pp1).x)-(sin(3 * angle) * (pp1).y),(sin(3 * angle) * (pp1).x)+(cos(3 * angle) * (pp1).y));
378             
379             //计算偏移
380             pp1=pp1+float4(centerPos1.xy,0,0);
381             pp2=pp2+float4(centerPos1.xy,0,0);
382             pp3=pp3+float4(centerPos1.xy,0,0);
383             pp4=pp4+float4(centerPos1.xy,0,0);
384 
385             //计算法线
386             float3 edgeA = pp2 - pp1;
387             float3 edgeB = pp3 - pp1;
388             float3 normalFace = normalize(cross(edgeA, edgeB));
389             o.norg=-normalFace;
390             
391             o.centerPos=centerPos1;
392             o.color=IN[0].color;
393 
394             ADD_INFO_Other(pp1,pp2,pp3,o,tristream);
395             ADD_INFO_Other(pp3,pp4,pp1,o,tristream);
396 
397           }
398         } 
399             
400        fixed4 frag (g2f i) : SV_Target
401         {
402                  
403             //圆形点
404             if (abs(_PointType)<=0.05)
405             {    
406                DrawCirclePoint(i,0.0);       
407             }
408              
409             //正方形
410             if(abs(_PointType-2)<=0.05)
411             {
412                DrawSquarePoint(i,0.0);
413             }
414 
415             //三角形
416             if(abs(_PointType-1)<=0.05)
417             {
418                DrawTrianglePoint(i,0.0);
419             }
420 
421              //交叉十字
422             if(abs(_PointType-3)<=0.05)
423             {
424                 DrawCrossPoint(i,0.0);
425             }
426 
427              return _LineColor;
428         }
429 
430 
431         fixed4 fragOther (g2f i) : SV_Target
432         {
433             //圆形点
434             if (abs(_PointType)<=0.05)
435             {    
436                DrawCirclePoint(i,1.0);   
437             }
438              
439             //正方形
440             if(abs(_PointType-2)<=0.05)
441             {
442                DrawSquarePoint(i,1.0);
443             }
444 
445             //三角形
446             if(abs(_PointType-1)<=0.05)
447             {
448                DrawTrianglePoint(i,1.0);
449             }
450 
451              //交叉十字
452             if(abs(_PointType-3)<=0.05)
453             {
454                 DrawCrossPoint(i,1.0);
455             }
456 
457               return _Color;
458         }
459 
460         ENDCG
461 
462         Pass 
463         {
464               NAME "InitShader"
465 
466               Tags { "RenderType"="Opaque" }
467               LOD 100 
468               Cull Off
469 
470               CGPROGRAM
471               
472               #pragma target 4.0
473               #pragma vertex vert
474               #pragma geometry geom        
475               #pragma fragment frag
476 
477               ENDCG  
478         }
479 
480         Pass 
481         {
482               NAME "LineShader"
483             
484               Tags { "RenderType"="Opaque" }
485               LOD 100 
486               Cull Off
487 
488               CGPROGRAM
489               
490               #pragma target 4.0
491               #pragma vertex vert
492               #pragma geometry geom        
493               #pragma fragment fragOther
494               
495               ENDCG  
496         }
497     }
498 
499     FallBack "Diffuse"
500 }

代码分析:

这个方案主要是为了边框处理,我在这里画了两次,也可以处理一次,通过条件去改变Color,但是我这里不想过多处理过渡问题,所以采取了两个Pass渲两遍。。

这里附带一个判断点是否在三角形内算法:

 

对于三角形ABC和一点P,可以有如下的向量表示:

Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

p点在三角形内部的充分必要条件是:1 >= u >= 0,   1 >= v >= 0,   u+v <= 1。

 

已知A,B,C,P四个点的坐标,可以求出u,v,把上面的式子分别点乘向量AC和向量AB

Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

解方程得到:

Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

解出u,v后只需要看他们是否满足“1 >= u >= 0, 1 >= v >= 0, u+v <= 1”,如满足,则,p 在三角形内。

(u = 0时,p在AB上, v = 0时,p在AC上,两者均为0时,p和A重合)

ps:是不是很熟悉,嘿嘿

Unity 中使用Geomotry Shader(几何着色器)创建点以及其他图形

 

 

 

 

关于GS:

1.属性语法在着色器定义之前设置最大顶点数:
[maxvertexcount(N)]
N是几何着色器为单个调用输出的顶点的最大数量
GS可以在每次调用时输出的顶点数量是可变的,但不能超过定义的最大值。出于性能考虑,最大顶点数应尽可能小; [NVIDIA08]指出,当GS输出在1到20个标量之间时,可以实现GS的性能峰值,如果GS输出在27-40个标量之间,则性能下降50%。

2.GS需要两个参数:输入参数和输出参数。 (实际上,它可能需要更多,但这是一个特殊的主题;请参见§11.2.4。)输入参数一般是一个定义了图元的顶点数组 — 一个顶点定义一个点,两个定义一条线,三个定义三角形,四个定义邻接线段,六个定义邻接三角形。 输入顶点的顶点类型是顶点着色器返回的顶点类型(例如,VertexOut)。 输入参数必须以原始类型为前缀,描述输入到几何着色器中的图元的类型。这可以是以下任何一种:

    1、point:输入图元是点。
    2、line:输入图元是线段(lists或strips)。
    3、triangle:输入图元是三角形(lists或strips)。
    4、lineadj:输入图元是具有邻接(lists或strips)的线段。
    5、triangleadj:输入图元是具有邻接(lists或strips)的三角形。

 

3.几何着色器输出的顶点形成基元; 输出原语的类型由流类型(PointStream,LineStream,TriangleStream)指示。 对于线和三角形,输出原语总是strips。 然而,线和三角形列表可以使用内在的RestartStrip方法进行

 

关于SubShader使用:

subShaderc 中 选择执行哪个?可根据LOG设置,(从上往下 &从大到小)写)<=LOD值就执行相应的子着色器,它会在子着色器列表中找《=LOD的,但是会找第一个满足条件的,所以从小到大,会只跑第一个最小的了,所以从大到小写(LOD)




上一篇:unity层级关系(LOD)


下一篇:六大设计原则之迪米特法则(LOD)