欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Unity實(shí)現(xiàn)圓形Image組件

 更新時(shí)間:2022年01月07日 12:46:26   作者:Hello?Bug.  
這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)圓形Image組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Unity實(shí)現(xiàn)圓形Image組件的具體代碼,供大家參考,具體內(nèi)容如下

一、前言

游戲里很多圖片都是以圓形展示的,例如頭像、技能圖標(biāo)等,一般做法是使用Image組件+Mask組件實(shí)現(xiàn),但是Mask組件會(huì)影響效率(增加額外的drawcall)所以不建議大量使用

UGUI的Mask實(shí)現(xiàn)原理:利用GPU的模版緩沖

Mask組件會(huì)賦給父級(jí)和子級(jí)UI一個(gè)特殊的材質(zhì),這個(gè)材質(zhì)會(huì)給Image的每個(gè)像素點(diǎn)進(jìn)行標(biāo)記并放在一個(gè)稱為Stencil Buffer的緩存內(nèi),父級(jí)每個(gè)像素點(diǎn)的標(biāo)記設(shè)置為1,子級(jí)UI進(jìn)行渲染的時(shí)候會(huì)去檢查這個(gè)Stencil Buffer內(nèi)的標(biāo)記是否為1,如果為1則進(jìn)行渲染,否則不渲染

二、實(shí)現(xiàn)自己的圓形組件

像Image,RawImage這些組件都是繼承自自MsakGraphics類,MsakGraphics類繼承自Graphic類,Graphic類中有個(gè)OnPopulateMesh方法用于繪制圖形,UGUI的Image組件實(shí)現(xiàn)原理是重寫了OnPopulateMesh方法并繪制了一個(gè)矩形,所以按照這個(gè)思路我們可以重寫OnPopulateMesh方法直接繪制一個(gè)圓形
——獲取圖片的長寬、uv等信息

——OnPopulateMesh:當(dāng)UI元素生成頂點(diǎn)數(shù)據(jù)時(shí)會(huì)調(diào)用OnPopulateMesh(VertexHelper vh)函數(shù),我們只需要將原先的矩形頂點(diǎn)數(shù)據(jù)清除,改寫入圓形頂點(diǎn)數(shù)據(jù),這樣渲染出來的自然是圓形圖片

——不規(guī)則UI元素的響應(yīng)區(qū)域判定
UI組件的響應(yīng)區(qū)域判定是通過實(shí)現(xiàn)ICanvasRaycastFilter接口中的IsRaycastLocationValid函數(shù),它的返回值是一個(gè)bool值,返回true則視為可以響應(yīng),例如Image組件,它判定了兩個(gè)條件:當(dāng)前屏幕坐標(biāo)是否在當(dāng)前圖片矩形區(qū)域內(nèi)和當(dāng)前屏幕坐標(biāo)的圖片區(qū)域透明度是否大于alphaHitTestMinimumThreshold參數(shù)
我們想實(shí)現(xiàn)精確的點(diǎn)擊判斷,可以代碼動(dòng)態(tài)將alphaHitTestMinimumThreshold參數(shù)設(shè)置為0.1,這樣就實(shí)現(xiàn)了只有在透明度大于0.1的像素點(diǎn)才視為響應(yīng),但它要求圖片的Read/Write Enabled必須開啟,這就導(dǎo)致了圖片占用了兩份內(nèi)存,所以不建議使用
對(duì)于像素級(jí)的點(diǎn)擊判定,有一種算法可以實(shí)現(xiàn):Ray-Crossing算法
此算法適用于所有圖形,實(shí)現(xiàn)思路是從指定點(diǎn)向任意方向發(fā)出一條水平射線,與圖形相交,如果交點(diǎn)是奇數(shù)個(gè),則點(diǎn)在圖形內(nèi),如果交點(diǎn)是偶數(shù)個(gè),則點(diǎn)在圖形外

using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;
using System.Collections.Generic;
?
/// <summary>
/// 圓形Image組件
/// </summary>
[AddComponentMenu("LFramework/UI/CircleImage", 11)]
public class CircleImage : MaskableGraphic, ICanvasRaycastFilter
{
? ? /// <summary>
? ? /// 渲染類型
? ? /// </summary>
? ? public enum RenderType
? ? {
? ? ? ? Simple,
? ? ? ? Filled,
? ? }
?
? ? /// <summary>
? ? /// 填充類型
? ? /// </summary>
? ? public enum FilledType
? ? {
? ? ? ? Radial360,
? ? }
?
? ? /// <summary>
? ? /// 繪制起始點(diǎn)(填充類型-360度)
? ? /// </summary>
? ? public enum Origin360
? ? {
? ? ? ? Right,
? ? ? ? Top,
? ? ? ? Left,
? ? ? ? Bottom,
? ? }
?
? ? //Sprite圖片
? ? [SerializeField]
? ? Sprite m_Sprite;
? ? public Sprite Sprite
? ? {
? ? ? ? get { return m_Sprite; }
? ? }
?
? ? //貼圖
? ? public override Texture mainTexture
? ? {
? ? ? ? get
? ? ? ? {
? ? ? ? ? ? if (m_Sprite == null)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if (material != null && material.mainTexture != null)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? return material.mainTexture;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return s_WhiteTexture;
? ? ? ? ? ? }
?
? ? ? ? ? ? return m_Sprite.texture;
? ? ? ? }
? ? }
?
? ? //渲染類型
? ? [SerializeField]
? ? RenderType m_RenderType;
?
? ? //填充類型
? ? [SerializeField]
? ? FilledType m_FilledType;
?
? ? //繪制起始點(diǎn)(填充類型-360度)
? ? [SerializeField]
? ? Origin360 m_Origin360;
?
? ? //是否為順時(shí)針繪制
? ? [SerializeField]
? ? bool m_Clockwise;
?
? ? //填充度
? ? [SerializeField]
? ? [Range(0, 1)]
? ? float m_FillAmount;
?
? ? //多少個(gè)三角面組成
? ? [SerializeField]
? ? int segements = 100;
?
? ? List<Vector3> vertexCache = new List<Vector3>();
?
? ? protected override void OnPopulateMesh(VertexHelper vh)
? ? {
? ? ? ? vh.Clear();
? ? ? ? vertexCache.Clear();
?
? ? ? ? switch (m_RenderType)
? ? ? ? {
? ? ? ? ? ? case RenderType.Simple:
? ? ? ? ? ? ? ? GenerateSimpleSprite(vh);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case RenderType.Filled:
? ? ? ? ? ? ? ? GenerateFilledSprite(vh);
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
?
? ? void GenerateSimpleSprite(VertexHelper vh)
? ? {
? ? ? ? Vector4 uv = m_Sprite == null
? ? ? ? ? ? ? Vector4.zero
? ? ? ? ? ? : DataUtility.GetOuterUV(m_Sprite);
? ? ? ? float uvWidth = uv.z - uv.x;
? ? ? ? float uvHeight = uv.w - uv.y;
? ? ? ? float width = rectTransform.rect.width;
? ? ? ? float height = rectTransform.rect.height;
? ? ? ? float dia = width > height ? width : height;
? ? ? ? float r = dia * 0.5f;
? ? ? ? Vector2 uvCenter = new Vector2((uv.x + uv.z) * 0.5f, (uv.y + uv.w) * 0.5f);
? ? ? ? Vector3 posCenter = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
? ? ? ? float uvScaleX = uvWidth / width;
? ? ? ? float uvScaleY = uvHeight / height;
? ? ? ? float deltaRad = 2 * Mathf.PI / segements;
?
? ? ? ? float curRad = 0;
? ? ? ? int vertexCount = segements + 1;
? ? ? ? vh.AddVert(posCenter, color, uvCenter);
? ? ? ? for (int i = 0; i < vertexCount - 1; i++)
? ? ? ? {
? ? ? ? ? ? UIVertex vertex = new UIVertex();
? ? ? ? ? ? Vector3 posOffset = new Vector3(r * Mathf.Cos(curRad), r * Mathf.Sin(curRad));
? ? ? ? ? ? vertex.position = posCenter + posOffset;
? ? ? ? ? ? vertex.color = color;
? ? ? ? ? ? vertex.uv0 = new Vector2(uvCenter.x + posOffset.x * uvScaleX, uvCenter.y + posOffset.y * uvScaleY);
? ? ? ? ? ? vh.AddVert(vertex);
? ? ? ? ? ? vertexCache.Add(vertex.position);
?
? ? ? ? ? ? curRad += deltaRad;
? ? ? ? }
?
? ? ? ? for (int i = 0; i < vertexCount - 2; i++)
? ? ? ? {
? ? ? ? ? ? vh.AddTriangle(0, i + 1, i + 2);
? ? ? ? }
? ? ? ? vh.AddTriangle(0, segements, 1);
? ? }
?
? ? void GenerateFilledSprite(VertexHelper vh)
? ? {
? ? ? ? Vector4 uv = m_Sprite == null
? ? ? ? ? ? ? Vector4.zero
? ? ? ? ? ? : DataUtility.GetOuterUV(m_Sprite);
? ? ? ? float uvWidth = uv.z - uv.x;
? ? ? ? float uvHeight = uv.w - uv.y;
? ? ? ? float width = rectTransform.rect.width;
? ? ? ? float height = rectTransform.rect.height;
? ? ? ? float dia = width > height ? width : height;
? ? ? ? float r = dia * 0.5f;
? ? ? ? Vector2 uvCenter = new Vector2((uv.x + uv.z) * 0.5f, (uv.y + uv.w) * 0.5f);
? ? ? ? Vector3 posCenter = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
? ? ? ? float uvScaleX = uvWidth / width;
? ? ? ? float uvScaleY = uvHeight / height;
? ? ? ? float deltaRad = 2 * Mathf.PI / segements;
?
? ? ? ? switch (m_FilledType)
? ? ? ? {
? ? ? ? ? ? case FilledType.Radial360:
? ? ? ? ? ? ? ? float quarterRad = 2 * Mathf.PI * 0.25f;
? ? ? ? ? ? ? ? float curRad = quarterRad * (int)m_Origin360;
? ? ? ? ? ? ? ? int vertexCount = m_FillAmount == 1
? ? ? ? ? ? ? ? ? ? ? segements + 1
? ? ? ? ? ? ? ? ? ? : Mathf.RoundToInt(segements * m_FillAmount) + 2;
? ? ? ? ? ? ? ? vh.AddVert(posCenter, color, uvCenter);
? ? ? ? ? ? ? ? for (int i = 0; i < vertexCount - 1; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? UIVertex vertex = new UIVertex();
? ? ? ? ? ? ? ? ? ? Vector3 posOffset = new Vector3(r * Mathf.Cos(curRad), r * Mathf.Sin(curRad));
? ? ? ? ? ? ? ? ? ? vertex.position = posCenter + posOffset;
? ? ? ? ? ? ? ? ? ? vertex.color = color;
? ? ? ? ? ? ? ? ? ? vertex.uv0 = new Vector2(uvCenter.x + posOffset.x * uvScaleX, uvCenter.y + posOffset.y * uvScaleY);
? ? ? ? ? ? ? ? ? ? vh.AddVert(vertex);
? ? ? ? ? ? ? ? ? ? vertexCache.Add(vertex.position);
?
? ? ? ? ? ? ? ? ? ? curRad += m_Clockwise ? -deltaRad : deltaRad;
? ? ? ? ? ? ? ? }
?
? ? ? ? ? ? ? ? for (int i = 0; i < vertexCount - 2; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? vh.AddTriangle(0, i + 1, i + 2);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (m_FillAmount == 1)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? vh.AddTriangle(0, segements, 1);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
?
? ? public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
? ? {
? ? ? ? Vector2 localPos;
? ? ? ? int crossPointCount;
? ? ? ? RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out localPos);
? ? ? ? RayCrossing(localPos, out crossPointCount);
? ? ? ? return crossPointCount % 2 != 0;
? ? }
?
? ? public void RayCrossing(Vector2 localPos, out int crossPointCount)
? ? {
? ? ? ? crossPointCount = 0;
? ? ? ? for (int i = 0; i < vertexCache.Count; i++)
? ? ? ? {
? ? ? ? ? ? Vector3 p1 = vertexCache[i];
? ? ? ? ? ? Vector3 p2 = vertexCache[(i + 1) % vertexCache.Count];
?
? ? ? ? ? ? if (p1.y == p2.y) continue;
? ? ? ? ? ? if (localPos.y <= Mathf.Min(p1.y, p2.y)) continue;
? ? ? ? ? ? if (localPos.y >= Mathf.Max(p1.y, p2.y)) continue;
? ? ? ? ? ? float crossX = (localPos.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
? ? ? ? ? ? if (crossX >= localPos.x)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? crossPointCount++;
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論