Unity中shader实现绘制六边形网格

上一篇 绘制一个正六边形的shader 中实现了在面片上绘制单一的六边形。结合上上篇的六边形网格向量工具,可以创建大量的六边形来实现绘制一个六边形网格。

这里写图片描述

然而这样的绘制问题很明显,顶点数较多,每一个六边形用掉4个顶点。。。那我为什么不去直接用6个顶点的mesh呢?(手动滑稽)。
这里写图片描述

试想一下如果我有10000个格子,就要为了它绘制40000个顶点。。。
这里写图片描述

还有一种很常用的方式,画出一张六边形的贴图,然后用平铺的方式铺出六边形的网格,然而这样的方式六边形位置精度又很难保证,而且很容易变形。入下图中就有变形,注意材质的tiling。
这里写图片描述

综合这些因素,最终决定在上一张的shader基础上扩展出一个shader来实现这种网格的绘制。(网上其他人写了一堆if else的shader 我直接跳过了。。。)。最终实现效果如下图:
这里写图片描述

下面是shader的最终实现。

其中EdgeColor为边框的颜色,Color为背景的颜色,Column为横排格子数量,Edge为边框宽度占格子宽度(不是半径)占比,Center的xy为0,0坐标格子所在的UV位置,zw为格子整体便宜的格子百分比。

Shader "Unlit/Hex2" {
Properties {
    _EdgeColor ("Edge Color", Color) = (1,1,1,1)
    _Color ("BG Color", Color) = (1,1,1,1)
    _Colmun ("Colmun", float) = 1
    _Edge ("Edge Width", Range(0,1)) = 0
    _Center ("Center(xy) OffsetX(zw)", Vector) =  (0,0,0,0)

    _Target ("A(xy)", Vector) =  (0,0,0,0)
}

SubShader {
    Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    LOD 100

    Cull Off
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha 

    Pass {  
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(0)
                UNITY_VERTEX_OUTPUT_STEREO
            };

            fixed4 _Color;
            fixed4 _EdgeColor;
            fixed _Colmun;
            fixed _Edge;

            fixed4 _Target;


            fixed4 _Center;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f input) : COLOR
            {
                //fixed4 col = _EdgeColor;

                fixed size = 0.5 / (_Colmun * 0.86602540378445);
                fixed2 pixel = input.uv.xy + fixed2( 2 * size * _Center.z - _Center.x, 2 * size * _Center.w - _Center.y);

                fixed q = (pixel.x * 0.57735026918963 - pixel.y *0.33333333333) / size;
                fixed r = pixel.y * 0.66666666666 / size;

                fixed rx = round(q);
                fixed ry = round(-q - r);
                fixed rz = round(r);

                fixed yx = step(abs(ry + q + r),abs(rx - q));
                fixed zx = step(abs(rz - r),abs(rx - q));
                fixed zy = step(abs(rz - r),abs(ry + q + r));

                rx = (yx * zx) * (-ry - rz) + (1-yx * zx ) * rx;
                ry = (zy- yx*zx*zy) * (-rx - rz) + (1- zy+yx*zx*zy) *ry;
                rz = (1- zy+yx*zx*zy) * (-rx - ry) + (zy-yx * zx* zy) * rz;

                fixed3 n[6] = {
                    fixed3(0, 1, -1),
                    fixed3(1, 0, -1),
                    fixed3(-1, 1, 0),
                    fixed3(1, -1, 0),
                    fixed3(-1, 0, 1),
                    fixed3(0, -1, 1),
                };

                fixed mindis = 2;
                for(int i=0; i<6; i++){
                    fixed2 pos = fixed2(size * 1.73205080756887 * ((rx+n[i].x) + (rz+n[i].z) * 0.5),size * 1.5 *(rz+ n[i].z));
                    fixed a = distance(pixel.xy,pos);
                    mindis = min(mindis,a);
                }

                fixed isEdge = step(abs(distance(pixel.xy,fixed2(size * 1.73205080756887 * (rx + rz * 0.5) ,size * 1.5 * rz))-mindis),size*_Edge);


                /*
                //目标位置
                zx = (_Target.x<0)*ceil(_Target.x) + (_Target.x>0)*floor(_Target.x);
                zy = (_Target.y<0)*ceil(_Target.y) + (_Target.y>0)*floor(_Target.y);

                fixed hx = zx - (zy - fmod(zy,2)) *0.5;
                hx = step(hx,0) * ceil(hx) + step(0,hx) * floor(hx);
                fixed hz = zy;
                fixed hy = -hx - hz;

                fixed isTarget= distance(fixed3(hx,hy,hz), fixed3(rx,ry,rz)) == 0;

                fixed4 col = isEdge * _EdgeColor + 
                (1 - isEdge)*(1-isTarget) * _Color + 
                (1 - isEdge)* isTarget* fixed4(1,0,0,1);
                */
                fixed4 col = isEdge * _EdgeColor + 
                (1 - isEdge)* _Color;

                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
        ENDCG
    }
}

}

注释掉的代码可以在网格中红色填充显示制定坐标的格子,打开注释后如图。

这里写图片描述

效果很不错,可以试着放到立方体或者球上看看。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
要使用Shader绘制网格,需要在Unity创建一个材质(Material)并将其分配给网格对象(Mesh)。材质包含着Shader的代码,它会告诉Unity如何绘制网格。 以下是一个简单的示例,演示如何使用Shader绘制一个简单的网格: 1. 创建一个新的ShaderUnity,选择"Create" -> "Shader"创建一个新的Shader。选择一个合适的命名,例如"MyShader"。 2. 编写Shader代码 打开新创建的Shader,你会看到一个空白的代码文件。在这里,你可以自由编写你的Shader代码。以下是一个简单的示例,它会绘制一个灰色的网格: ``` Shader "Custom/MyShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags {"Queue"="Transparent" "RenderType"="Opaque"} Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv) * 0.5; } ENDCG } } } ``` 这个Shader包含一个名为"_MainTex"的属性,它是一个2D纹理。在Pass块Shader使用这个纹理对网格进行着色,并将颜色乘以0.5,以便将其变为灰色。 3. 创建一个材质 现在,你需要创建一个材质(Material),并将Shader分配给它。在Unity,选择"Create" -> "Material"创建一个新的材质。给它一个合适的名称,例如"MyMaterial"。 选择新创建的材质,将Shader分配给它。在Inspector窗口,将Shader字段设置为新创建的Shader。 4. 将材质分配给网格对象 最后一步是将材质分配给网格对象。在Unity,选择你想要绘制网格对象,并将新创建的材质分配给它。 现在,当你在场景查看网格对象时,它应该使用你编写的Shader进行着色了。如果需要,你可以进一步调整你的Shader代码,以实现更复杂的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值