unity绘制虚线 geometry shader
发布网友
发布时间:2022-10-16 22:10
我来回答
共1个回答
热心网友
时间:2023-10-24 16:36
绘制虚线其实简单。绘制线段,然后通过线段的uv坐标,设置虚线贴图就行。
或者用shader判断uv坐标决定好不要绘制线段的某一部分。
但是这样还是免不了要在CPU中计算好顶点和UV。如果线条数量很多(曲线),要经常更新线条。而且要修改条线的粗细,虚线的密度。那么为什么不把要显示的东西交给GPU呢?
CPU端直接用两个点就好了,也减少了CPU的计算量和额外的数据存储。
绘制线条的抗锯齿效果比绘制三角形抗锯齿效果要差一些
Shader "Unlit/geoline"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_LineColor("LineColor", color) = (0,1,0,1)//颜色
_LineWidth("LineWidth",float) = 10//线宽
_SingleSegmentLength("SingleSegmentLength",float) = 500//线段单元长度
_SolidRatio("SolidRatio",float) = 0.5//绘制实线部分比率
}
SubShader
{
Cull Off
Blend SrcAlpha OneMinusSrcAlpha
Tags {"Queue"="Transparent"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geo//几何着色器入口
#pragma fragment frag
// make fog work
//#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
//UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _LineWidth;
float _SingleSegmentLength;
float _SolidRatio;
float4 _LineColor;
[maxvertexcount(30)]//产生最大的顶点数,append到triStream的次数应该小于此。最大好像是64
void geo(line appdata l[2], inout TriangleStream<v2f> triStream)
{
v2f pIn;
v2f v[4];//先生成四个点,构造两个三角形
float4 a = l[0].vertex;
float4 b = l[1].vertex;
float len = distance(b, a);
float3 dir0 = normalize(b - a);
float3 dir2 = normalize(cross(dir0, float3(0, 0, 1)));//加宽的方向
float2 dir3 = dir2.xy * 0.5 * _LineWidth;
v[0].vertex = UnityObjectToClipPos(a + float4(dir3, 0, 0));
//使用的原来的世界坐标空间计算,完了后再映射为视图空间。如果是在顶点着色进行UnityObjectToClipPos后,坐标空间就是屏幕坐标了。
//屏幕坐标经过投影变换。如果在vertex shader 计算UnityObjectToClipPos。a, b点的坐标x,y,z就不是均匀。垂直于线段的向量dir2就不对。
v[0].uv = float2(0.0f, 1.0f) * float2(len / _SingleSegmentLength, 1.0f);
v[1].vertex = UnityObjectToClipPos(b + float4(dir3, 0, 0));
v[1].uv = float2(1.0f, 1.0f) * float2(len / _SingleSegmentLength, 1.0f);
v[2].vertex = UnityObjectToClipPos(b + float4(-dir3, 0, 0));
v[2].uv = float2(1.0f, 0.0f) * float2(len / _SingleSegmentLength, 1.0f);
v[3].vertex = UnityObjectToClipPos(a + float4(-dir3, 0, 0));
v[3].uv = float2(0.0f, 0.0f) * float2(len / _SingleSegmentLength, 1.0f);
triStream.Append(v[0]);
triStream.Append(v[1]);
triStream.Append(v[2]);
triStream.RestartStrip();//重置三角形计数,提交三角形
triStream.Append(v[2]);
triStream.Append(v[3]);
triStream.Append(v[0]);
triStream.RestartStrip();
//最后倒下角,美化一下。这里可选。
v2f va[3];
v2f vb[3];
float pi = 3.1415926;
float points = 3;
float segs = points + 1;
for (int i = 1;i <= points;i++)
{
float2 rot = normalize(-dir0 * sin(i / segs * pi) + dir2 * cos(i / segs * pi));
va[i - 1].vertex = UnityObjectToClipPos(a + float4(rot * 0.5 * _LineWidth, 0, 0));
va[i - 1].uv = float2(0, dot(rot, dir2)) * float2(len / _SingleSegmentLength, 1.0f);
}
for (int i = 1;i <= points;i++)
{
float2 rot = normalize(dir0 * sin(i / segs * pi) + -dir2 * cos(i / segs * pi));
vb[i - 1].vertex = UnityObjectToClipPos(b + float4(rot * 0.5 * _LineWidth, 0, 0));
vb[i - 1].uv = float2(1, dot(rot, dir2)) * float2(len / _SingleSegmentLength, 1.0f);
}
for (int i = 0;i < points;i++)
{
triStream.Append(v[3]);
triStream.Append(va[i]);
if (i - 1 < 0)
triStream.Append(v[0]);
else
triStream.Append(va[i - 1]);
triStream.RestartStrip();
triStream.Append(v[1]);
triStream.Append(vb[i]);
if (i - 1 < 0)
triStream.Append(v[2]);
else
triStream.Append(vb[i - 1]);
triStream.RestartStrip();
}
}
v2f vert (appdata v)
{
v2f o;
o.vertex = v.vertex;
//o.vertex = UnityObjectToClipPos(v.vertex);
//o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
//fixed4 col = tex2D(_MainTex, i.uv);
fixed4 col = float4(0, 1, 0, 0);
float m = fmod(i.uv.x, 1);
if (m < _SolidRatio)
{
col = _LineColor;
}
// apply fog
//UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}