当前位置:网站首页>Custom shapes for ugui skill learning
Custom shapes for ugui skill learning
2022-06-23 02:04:00 【Thunder Gazi】
as everyone knows ,UGUI My picture is with Image For display , Most of his projects meet basic needs . But if I want to do something like :

A display of such a shape or

Such a display UGUI Currently not supported .
The traditional practice is to make art a mask , Then mask Mask Hang these pictures next . No, no, no , But it adds .
1. Art needs a mask , This can be ignored
2. There are more games 2 individual DrawCall One is masked , One is restored . If the game wants to be better optimized , This is not desirable .
So study UGUI Of Image Source code .
Image Of OnPopulateMesh Method represents this Image Of mesh How to render , The parameters are VertexHelper It can be set pos,uv And so on .
Then click the corresponding overload IsRaycastLocationValid, The screen coordinates will be transmitted here , And cameras . And then call
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint);
Method to obtain the local coordinate position of the screen coordinate in the object . It's easier if it's a circle , Just judge the distance from the circle . If it's a polygon , It is necessary to judge whether the point is within the polygon . What the author has done is very simple , Divide a polygon into triangles . Then loop through , Whether the point is in the triangle . Cross product is used here .
The complete code is as follows :
Round picture :
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;
public class CircleImage : Image
{
/// <summary>
/// How many triangles does a circle consist of
/// </summary>
[SerializeField]
private int segements = 100;
// The percentage of the display part in the circle .
[SerializeField]
private float showPercent = 1;
private readonly Color32 GRAY_COLOR = new Color32(60, 60, 60, 255);
private List<Vector3> _vertexList;
private float checkRadius = 0;
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
_vertexList = new List<Vector3>();
AddVertex(vh, segements);
AddTriangle(vh, segements);
}
private void AddVertex(VertexHelper vh, int segements)
{
float width = rectTransform.rect.width;
float heigth = rectTransform.rect.height;
int realSegments = (int)(segements * showPercent);
Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
float uvWidth = uv.z - uv.x;
float uvHeight = uv.w - uv.y;
Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / heigth);
float radian = (2 * Mathf.PI) / segements;
float radius = width * 0.5f;
checkRadius = radius;
Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * heigth);
Vector2 vertPos = Vector2.zero;
//Color32 colorTemp = GetOriginColor();
Color32 colorTemp = color;
UIVertex origin = GetUIVertex(colorTemp, originPos, vertPos, uvCenter, convertRatio);
vh.AddVert(origin);
int vertexCount = realSegments + 1;
float curRadian = 0;
Vector2 posTermp = Vector2.zero;
for (int i = 0; i < segements + 1; i++)
{
float x = Mathf.Cos(curRadian) * radius;
float y = Mathf.Sin(curRadian) * radius;
curRadian += radian;
if (i < vertexCount)
{
colorTemp = color;
}
else
{
colorTemp = GRAY_COLOR;
}
//colorTemp = color;
posTermp = new Vector2(x, y);
UIVertex vertexTemp = GetUIVertex(colorTemp, posTermp + originPos, posTermp, uvCenter, convertRatio);
vh.AddVert(vertexTemp);
_vertexList.Add(posTermp + originPos);
}
}
private Color32 GetOriginColor()
{
Color32 colorTemp = (Color.white - GRAY_COLOR) * showPercent;
return new Color32(
(byte) (GRAY_COLOR.r + colorTemp.r),
(byte) (GRAY_COLOR.g + colorTemp.g),
(byte) (GRAY_COLOR.b + colorTemp.b),
255);
}
private void AddTriangle(VertexHelper vh, int realSegements)
{
int id = 1;
for (int i = 0; i < realSegements; i++)
{
vh.AddTriangle(id, 0, id + 1);
id++;
}
}
private UIVertex GetUIVertex(Color32 col, Vector3 pos, Vector2 uvPos, Vector2 uvCenter, Vector2 uvScale)
{
UIVertex vertexTemp = new UIVertex();
vertexTemp.color = col;
vertexTemp.position = pos;
vertexTemp.uv0 = new Vector2(uvPos.x * uvScale.x + uvCenter.x, uvPos.y * uvScale.y + uvCenter.y);
return vertexTemp;
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint);
return IsValid(localPoint);
}
private bool IsValid(Vector2 localPoint)
{
return localPoint.SqrMagnitude() <= checkRadius * checkRadius;
//return GetCrossPointNum(localPoint, _vertexList) %2 == 1;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(CircleImage), true)]
[CanEditMultipleObjects]
public class CircleImageEditor : UnityEditor.UI.ImageEditor
{
SerializedProperty _fillPercent;
SerializedProperty _segements;
protected override void OnEnable()
{
base.OnEnable();
_fillPercent = serializedObject.FindProperty("showPercent");
_segements = serializedObject.FindProperty("segements");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUILayout.Slider(_fillPercent, 0, 1, new GUIContent("showPercent"));
EditorGUILayout.PropertyField(_segements);
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
}
Custom polygon :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Sprites;
using UnityEngine;
using UnityEngine.UI;
public class CustomerShapeImage : Image
{
struct TriangleIndex
{
public int x;
public int y;
public int z;
}
/// <summary>
/// Sequential vertex
/// </summary>
[SerializeField]
public List<Vector2> m_Points = new List<Vector2>();
private Vector2 m_Center = Vector2.one * 0.5f;
private List<TriangleIndex> m_Triangles = new List<TriangleIndex>();
protected override void OnPopulateMesh(VertexHelper vh)
{
//if (activeSprite == null)
//{
// base.OnPopulateMesh(vh);
// return;
//}
//GenerateSprite(vh, preserveAspect);
vh.Clear();
m_Triangles.Clear();
AddVertex(vh);
AddTriangle(vh);
}
private void AddVertex(VertexHelper vh)
{
float width = rectTransform.rect.width;
float heigth = rectTransform.rect.height;
Vector2 wh = new Vector2(width, heigth);
Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
float uvWidth = uv.z - uv.x;
float uvHeight = uv.w - uv.y;
Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / heigth);
Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * heigth);
for (int i = 0; i < m_Points.Count; i++)
{
UIVertex vertexTemp = GetUIVertex(color, (m_Points[i] - m_Center) * wh + originPos, m_Points[i] * wh- originPos, Vector2.zero, convertRatio);
vh.AddVert(vertexTemp);
}
}
private UIVertex GetUIVertex(Color32 col, Vector3 pos, Vector2 uvPos, Vector2 uvCenter, Vector2 uvScale)
{
UIVertex vertexTemp = new UIVertex();
vertexTemp.color = col;
vertexTemp.position = pos;
vertexTemp.uv0 = new Vector2(uvPos.x * uvScale.x + uvCenter.x, uvPos.y * uvScale.y + uvCenter.y);
return vertexTemp;
}
private void AddTriangle(VertexHelper vh)
{
if (m_Points.Count < 3)
{
return;
}
for (int i = 0; i < m_Points.Count - 2; i++)
{
for (int j = i + 1; j < m_Points.Count - 1; j++)
{
TriangleIndex triangle = new TriangleIndex() { x=i,y=j,z=j+1};
m_Triangles.Add(triangle);
vh.AddTriangle(i, j, j + 1);
}
}
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint);
return IsValid(localPoint);
}
private bool IsValid(Vector2 localPoint)
{
foreach (var v in m_Triangles)
{
Vector2 v1 = localPoint - m_Points[v.x];
Vector2 v2 = localPoint - m_Points[v.y];
Vector2 v3 = localPoint - m_Points[v.z];
float c1 = CrossVec2(v1, v2);
float c2 = CrossVec2(v1, v3);
bool b = (c1 * c2) >= 0;
if (b)
return true;
}
return false;
//return GetCrossPointNum(localPoint, _vertexList) %2 == 1;
}
private float CrossVec2(Vector2 v1, Vector2 v2)
{
return v1.x * v2.y - v2.x * v1.y;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(CustomerShapeImage), true)]
[CanEditMultipleObjects]
public class CustomerShapeEditor : UnityEditor.UI.ImageEditor
{
SerializedProperty _Points;
protected override void OnEnable()
{
base.OnEnable();
_Points = serializedObject.FindProperty("m_Points");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUILayout.PropertyField(_Points);
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
CustomerShapeImage targetData = serializedObject.targetObject as CustomerShapeImage;
for (int i=0;i< targetData.m_Points.Count;i++)
{
float x, y;
x = Mathf.Clamp01(targetData.m_Points[i].x);
y = Mathf.Clamp01(targetData.m_Points[i].y);
targetData.m_Points[i] = new Vector2(x, y);
}
EditorUtility.SetDirty(target);
}
}
}
Currently, only non atlas images are supported , In fact, it is not very difficult to realize the pictures of the atlas , There are needs on record .
边栏推荐
- There is no corresponding change on the page after the code runs at the Chrome browser break point
- Detailed explanation of makefile usage
- C language games: sanziqi (simple version) implementation explanation
- Exercise analysis summary
- How to design API return codes (error codes)?
- An interesting example of relaxed memory models
- Google account cannot be logged in & external links cannot be opened automatically & words with words cannot be used
- Function part
- //1.11 basic operators
- Classical questions of function recursion
猜你喜欢

Dynamic address book in C language (add, delete, modify, check (duplicate), delete, sort and export)

Branch and loop statements (including goto statements) -part1

Cmake configuration error, error configuration process, Preject files may be invalid

1. Mx6u bare metal program (1) - Lighting master

Information theory and coding

4. functions and inline functions with default values for formal parameters

1. Mx6u bare metal program (4) - GPIO module

Google account cannot be logged in & external links cannot be opened automatically & words with words cannot be used

Detailed explanation of clip attribute parameters

Anaconda creates a new environment encounter pit
随机推荐
How are pub and sub connected in ros1?
Pychart installation instructions
Chapter 3 tensorflow linear regression
8. destruct, construct, deep copy, shallow copy, assignment operator overload
Bc116 xiaolele changed to digital
Operator part
Cmake passing related macros to source code
Bc117 xiaolele walks up the steps
2D prefix and
Array part
Interviewer: what is the difference between SSH and SSM frameworks? How to choose??
CSDN browser assistant for online translation, calculation, learning and removal of all advertisements
8 vertical centering methods
【CodeWars】 Pete, the baker
2022-1-14
Epoll introduction and principle explanation
Cut! 39 year old Ali P9 saved 150million
Install MySQL (5.7+8.0) through docker and configure master-slave replication (gtid+ enhanced semi synchronization)
JS - single sign on
Express framework installation and start service