UnityShader实例(1) 基于2DSprite实现圆环 |
您所在的位置:网站首页 › 像素如何画圆圈 › UnityShader实例(1) 基于2DSprite实现圆环 |
想要在Unity2D中实现一个漂亮的圆环,但是除了前面做过的各种笔记和自学,啥都不会, 但是成功摸索出来,在这里记录一下理解流程。 源代码和使用方式在最下面。 2D圆环的最简单实现圆环最简单的实现就是自己画一个背景色透明的圆环: (下面是一张图片,不信你把浏览器背景色调一下) 然后直接往场景里一放就行: 当然这种方式很不行,拉伸大了之后模糊感太大,很难看,而且不易控制大小: 首先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 } } }那看来从模型顶点入手是不行了, 毕竟二维精灵也没听说过顶点的说法, 那就是原理上与生成Mesh顶点并调整顶点颜色完全不同。 下面看看从程序导入着色器的另一个参数uv坐标, 将片元着色器代码调整如下: fixed4 frag (v2f i) : SV_Target { return fixed4(i.uv.x, i.uv.y, 0, 1); }输出结果如下: 虽然是混乱的色彩,但我很开心, 这说明决定2维精灵各个像素颜色的变量就在其中。 我们可以通过取色器对各个像素取色,得出uv坐标的分布规律: 左上角是绿色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); }
接下来就把代码精进,提供参数接口给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#脚本如下,主要是控制Scale和CircleEdge的比例关系。 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); } } }
|
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |