Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize Circular Image component by Unity

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

In this article Xiaobian for you to introduce in detail "Unity how to achieve circular Image components", the content is detailed, the steps are clear, the details are handled properly, I hope that this "Unity how to achieve circular Image components" article can help you solve your doubts, following Xiaobian's ideas slowly in-depth, let's learn new knowledge.

I. Preface

Many pictures in the game are displayed in circles, such as avatars, skill icons, etc. The general practice is to use Image components + Mask components, but Mask components will affect efficiency (adding extra drawcall), so it is not recommended to use a lot of them.

The principle of Mask implementation of UGUI: using the template buffer of GPU

The Mask component assigns a special material to the parent and child UI. This material marks each pixel of the Image and places it in a cache called Stencil Buffer. The mark of each pixel of the parent is set to 1. When the child UI renders, it will check whether the tag in the Stencil Buffer is 1. If it is 1, render, otherwise it will not render.

Second, implement your own circular components

Components like Image,RawImage are inherited from the MsakGraphics class, and the MsakGraphics class inherits from the Graphic class. There is an OnPopulateMesh method in the Graphic class to draw graphics. The principle of the Image component implementation of UGUI is to rewrite the OnPopulateMesh method and draw a rectangle, so according to this idea, we can override the OnPopulateMesh method to draw a circle directly.

-- get the length and width of the picture, uv and other information

-- OnPopulateMesh: the OnPopulateMesh (VertexHelper vh) function is called when the UI element generates vertex data. We only need to clear the original rectangular vertex data and write the circular vertex data instead, so that the rendered image is naturally circular.

-- determination of response region of irregular UI elements

The response area of the UI component is determined by implementing the IsRaycastLocationValid function in the ICanvasRaycastFilter interface. Its return value is a Bool value, and the return true is regarded as responsive. For example, the Image component determines two conditions: whether the current screen coordinates are within the current picture rectangular area and whether the transparency of the picture area of the current screen coordinates is greater than the alphaHitTestMinimumThreshold parameter.

If we want to achieve accurate click judgment, the code can dynamically set the alphaHitTestMinimumThreshold parameter to 0.1. in this way, only pixels with transparency greater than 0.1 can be regarded as responses, but it requires that the Read/Write Enabled of the image must be turned on, which results in the image taking up two pieces of memory, so it is not recommended to use it.

For pixel-level click decision, there is an algorithm that can be implemented: Ray-Crossing algorithm

This algorithm is suitable for all graphics. The idea is to emit a horizontal ray from a specified point in any direction and intersect with the graph. If the intersection point is odd, then the point is in the graph. If the intersection point is even, the point is outside the graph.

Using UnityEngine;using UnityEngine.Sprites;using UnityEngine.UI;using System.Collections.Generic / Circular Image component / [AddComponentMenu ("LFramework/UI/CircleImage", 11)] public class CircleImage: MaskableGraphic, ICanvasRaycastFilter {/ render type / public enum RenderType {Simple, Filled,} / public enum FilledType {Radial360 } / drawing starting point (fill type-360o) / public enum Origin360 {Right, Top, Left, Bottom,} / / Sprite picture [SerializeField] Sprite m_Sprite Public Sprite Sprite {get {return masked Sprit;}} / Map public override Texture mainTexture {get {if (m_Sprite = = null) {if (material! = null & & material.mainTexture! = null) {return material.mainTexture } return slotted WhiteTexture;} return massiveSprite.texture}} / / render type [SerializeField] RenderType massively RenderType; / / fill type [SerializeField] FilledType masked FilledType; / / draw starting point (fill type-360deg) [SerializeField] Origin360 m_Origin360 / / whether to draw [SerializeField] bool masked Clockwise clockwise; / / fill [SerializeField] [Range (0,1)] float masked FillAmount; / / how many triangles make up [SerializeField] int segements = 100; List vertexCache = new List (); 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) milled Origin 360; 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.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++;} read here, this article "how to implement circular Image components in Unity" has been introduced. If you want to master the knowledge points of this article, you still need to practice and use it yourself. If you want to know more about related articles, welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report