UnityShader实例(1) 基于2DSprite实现圆环

想要在Unity2D中实现一个漂亮的圆环,但是除了前面做过的各种笔记和自学,啥都不会,
但是成功摸索出来,在这里记录一下理解流程。
源代码和使用方式在最下面。

2D圆环的最简单实现

圆环最简单的实现就是自己画一个背景色透明的圆环:
(下面是一张图片,不信你把浏览器背景色调一下)
BigCircleEdge

然后直接往场景里一放就行:
20220130134430

当然这种方式很不行,拉伸大了之后模糊感太大,很难看,而且不易控制大小:
在这里插入图片描述

使用Shader实现

2DShader的简单探索(最终代码在最后)

首先2D中用的都是Sprite做渲染,所有显然不适合直接用Mesh顶点作图的方案,
当然如果用Mesh的话也有现成的方案:
https://blog.csdn.net/liuzonrze/article/details/83280463

但只要涉及到渲染肯定就用到Shader
所以先看看Sprite中怎么用上Shader吧。

首先在场景中创建一个新的2D正方形
新建一个Shader和材质作用到它上面,编写Shader代码进行探索。

这里就是用到Shader的一种主要调试方式:将值直接当作颜色输出来
下面这一段代码做的工作就是,
试图将模型顶点在裁剪空间中的坐标输出,
结果是输出全白:

Shader "Custom/CircleEdgeShader"
{
    Properties{
        _MainTex ("Main Tex", 2D) = "white" {}
    }

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        // 开启透明度
        Blend SrcAlpha OneMinusSrcAlpha
        // 设置渲染队列
        Tags { "Queue"="Transparent" "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            // 顶点着色获取
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            // 片元着色
            fixed4 frag (v2f i) : SV_Target
            {
                return i.vertex;
            }
            ENDCG
        }
    }
}

20220130145805

那看来从模型顶点入手是不行了,
毕竟二维精灵也没听说过顶点的说法,
那就是原理上与生成Mesh顶点并调整顶点颜色完全不同。

下面看看从程序导入着色器的另一个参数uv坐标
将片元着色器代码调整如下:

    fixed4 frag (v2f i) : SV_Target
{
    return fixed4(i.uv.x, i.uv.y, 0, 1);
}

输出结果如下:
20220130150429

虽然是混乱的色彩,但我很开心,
这说明决定2维精灵各个像素颜色的变量就在其中。
我们可以通过取色器对各个像素取色,得出uv坐标的分布规律:
20220130150712

左上角是绿色RGB(0, 1, 0), 右上角是黄色RGB(1, 1, 0),
中间显然就是RGB(0.5, 0.5, 0)。

知道uv的分布规律后,我们直接就可以写出代码来画我们需要的一个高清圆弧了!
将片元着色器代码修改如下:

fixed4 frag (v2f i) : SV_Target
{
    float disToCenter = (i.uv.x-0.5)*(i.uv.x-0.5) + (i.uv.y-0.5)*(i.uv.y-0.5);
    if( 0.5*0.5 > disToCenter && disToCenter > 0.45*0.45 )
        return fixed4(1, 1, 1, 1);
    else
        return fixed4(1, 1, 1, 0);
}

20220130151016
不管放多大,这种像素级的色彩定位是不会出现模糊的现象的:
20220130151210

接下来就把代码精进,提供参数接口给C#脚本即可

源代码

主要是两个参数:
一是Color,用来确定圆环颜色,
二是CircleEdge,用来确定圆环宽度占半径的比例(0~1)

Shader "Custom/CircleEdgeShader"
{
    Properties{
        _MainTex ("Main Tex", 2D) = "white" {}
        _ColorTint ("Color", Color) = (1, 1, 1, 1)
        _CircleEdge ("CircleEdge", float) = 0.1
    }

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        // 开启透明度
        Blend SrcAlpha OneMinusSrcAlpha
        // 设置渲染队列
        Tags { "Queue"="Transparent" "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed4 _ColorTint;
            float _CircleEdge;
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            // 顶点着色获取
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            // 片元着色
            fixed4 frag (v2f i) : SV_Target
            {
                float _CircleEdgeInFrag = (1 - _CircleEdge)*0.5;
                float disToCenter = (i.uv.x-0.5)*(i.uv.x-0.5) + (i.uv.y-0.5)*(i.uv.y-0.5);
                if( 0.5*0.5 > disToCenter && disToCenter > _CircleEdgeInFrag*_CircleEdgeInFrag )
                    return fixed4(_ColorTint.xyz, 1);
                else
                    return fixed4(_ColorTint.xyz, 0);
            }
            ENDCG
        }
    }
}
使用注意

圆环整体的大小通过Transform\Scale进行控制,
Scale为1时,可以在场景中看到圆环外环半径刚好是网格线的一半。
在这里插入图片描述


让圆环缩放时,宽度保持不变的C#脚本如下,主要是控制ScaleCircleEdge的比例关系。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FixedEdgeWidth : MonoBehaviour
{
    public Material circleEdgeMaterial;
    float rate;
    void Start()
    {
        rate = circleEdgeMaterial.GetFloat("_CircleEdge");
        rate *= transform.localScale.x;
    }

    void Update()
    {
        circleEdgeMaterial.SetFloat("_CircleEdge", rate / transform.localScale.x);
        if(Input.GetKeyDown(KeyCode.UpArrow)){
            transform.localScale = new Vector3(transform.localScale.x+0.5f, transform.localScale.y+0.5f, transform.localScale.z);
        }
        if(Input.GetKeyDown(KeyCode.DownArrow)){
            transform.localScale = new Vector3(transform.localScale.x-0.5f, transform.localScale.y-0.5f, transform.localScale.z);
        }
    }
}

20220130160604
20220130160619

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值