8 hours Code/Asset
While not perfect this works as a functioning shield that creates a dynamic mesh. All you need is to place this onto a child empty object then place a material on it. Then modify it to the right size.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshRenderer))]
public class CircleMesh : MonoBehaviour
{
public int elements = 60;
public float startAngle = 0f;
private float internalStartAngle = -1f;
public float endAngle = 360f;
private float internalEndAngle = -1f;
public float innerRadius = 50f;
private float savedInnerRadius = 50f;
public float circleWidth = 10f;
private float savedCircleWidth = 10f;
private float circleRadius = 360f;
public bool addCaps = false;
private Vector3[] allVertices = new Vector3[0];
private Vector2[] allUVs = new Vector2[0];
private int[] allTriangles = new int[0];
public Vector2 uv1 = new Vector2(0f, 0f);
public Vector2 uv2 = new Vector2(0f, 1f);
public Mesh mesh = null;
public bool createNewMeshInAwake = true;
public bool fullCircle = true;
private bool savedFullCircle = false;
public int count = 0;
private int savedCount = -1;
private bool busy = false;
void Awake()
{
if (createNewMeshInAwake)
{
MeshFilter mF = transform.GetComponent<MeshFilter>();
if (mF) mF.sharedMesh = null;
mesh = null;
RecalculateMesh();
}
}
void Update()
{
if (startAngle != internalStartAngle || endAngle != internalEndAngle || innerRadius != savedInnerRadius || circleWidth != savedCircleWidth || mesh == null)
{
RecalculateMesh(uv1, uv2, (mesh == null) ? true : false);
transform.rotation = Quaternion.Euler(90, 0, (endAngle / 2) - (circleRadius / elements /2));
}
}
public void ForceRefreshMesh()
{
StartCoroutine(ForceRefreshMeshNow());
}
IEnumerator ForceRefreshMeshNow()
{
while (busy) yield return null;
RecalculateMesh(uv1, uv2, true);
}
void RecalculateMesh()
{
RecalculateMesh(uv1, uv2, false);
}
void RecalculateMesh(Vector2 uvOne, Vector2 uvTwo, bool forceRefresh)
{
if (busy) return;
busy = true;
float degreeStep = 360f / elements;
internalStartAngle = startAngle;
internalEndAngle = endAngle;
if (internalEndAngle > 360f) internalEndAngle = 360f;
if (internalStartAngle < 0f) internalStartAngle = 0f;
if (internalStartAngle > 0f || internalEndAngle < 360f) fullCircle = false;
else fullCircle = true;
count = 0;
float deg = 0f;
for (int c = 0; c < elements; c++)
{
if (deg >= internalStartAngle && deg <= internalEndAngle) count++;
deg += degreeStep;
}
if (count < 2)
{
GetComponent<Renderer>().enabled = false;
busy = false;
return;
}
else GetComponent<Renderer>().enabled = true;
if (!forceRefresh && count == savedCount && fullCircle == savedFullCircle && innerRadius == savedInnerRadius && circleWidth == savedCircleWidth)
{
busy = false;
return;
}
savedCount = count;
savedFullCircle = fullCircle;
savedInnerRadius = innerRadius;
savedCircleWidth = circleWidth;
if (addCaps && !fullCircle) count += 2;
allVertices = new Vector3[count * 2];
allUVs = new Vector2[count * 2];
int numTris = count * 6;
if (!fullCircle) numTris -= 6;
allTriangles = new int[numTris];
if (addCaps && !fullCircle) count -= 2;
if (!gameObject.GetComponent("MeshFilter")) gameObject.AddComponent<MeshFilter>();
if (!gameObject.GetComponent("MeshRenderer")) gameObject.AddComponent<MeshRenderer>();
if (!mesh) mesh = GetComponent<MeshFilter>().sharedMesh;
if (!mesh)
{
mesh = new Mesh();
mesh.name = "Circle Mesh for " + gameObject.name;
GetComponent<MeshFilter>().sharedMesh = mesh;
}
mesh.Clear();
Quaternion quat = Quaternion.identity;
deg = 0f;
while (deg < internalStartAngle) deg += degreeStep;
for (int i = 0; i < count * 2; i += 2)
{
quat = Quaternion.AngleAxis(deg, -Vector3.forward);
allVertices[i] = quat * new Vector3(0f, innerRadius, 0f);
allVertices[i + 1] = quat * new Vector3(0f, innerRadius + circleWidth, 0f);
allUVs[i] = uvOne;
allUVs[i + 1] = uvTwo;
int nextDown = i + 2;
int nextUp = i + 3;
if (i + 2 >= count * 2)
{
nextUp = 1; nextDown = 0;
}
if (i + 2 >= count * 2 && !fullCircle) break;
allTriangles[(i * 3)] = i;
allTriangles[(i * 3) + 1] = i + 1;
allTriangles[(i * 3) + 2] = nextUp;
allTriangles[(i * 3) + 3] = i;
allTriangles[(i * 3) + 4] = nextUp;
allTriangles[(i * 3) + 5] = nextDown;
deg += degreeStep;
}
if (addCaps && !fullCircle)
{
float capAngleOffset = Mathf.Lerp(2f, 30f, circleWidth / innerRadius);
quat = Quaternion.AngleAxis(internalStartAngle - capAngleOffset, -Vector3.forward);
allVertices[count * 2] = quat * new Vector3(0f, innerRadius, 0f);
allVertices[count * 2 + 1] = quat * new Vector3(0f, innerRadius + circleWidth, 0f);
allUVs[count * 2] = uvOne + new Vector2(1f, 0f);
allUVs[count * 2 + 1] = uvTwo + new Vector2(1f, 0f);
allTriangles[(count * 2 * 3)] = count * 2;
allTriangles[(count * 2 * 3) + 1] = count * 2 + 1;
allTriangles[(count * 2 * 3) + 2] = 0;
allTriangles[(count * 2 * 3) + 3] = count * 2 + 1;
allTriangles[(count * 2 * 3) + 4] = 1;
allTriangles[(count * 2 * 3) + 5] = 0;
quat = Quaternion.AngleAxis(internalEndAngle + capAngleOffset, -Vector3.forward);
allVertices[count * 2 + 2] = quat * new Vector3(0f, innerRadius, 0f);
allVertices[count * 2 + 3] = quat * new Vector3(0f, innerRadius + circleWidth, 0f);
allUVs[count * 2 + 2] = uvOne + new Vector2(1f, 0f);
allUVs[count * 2 + 3] = uvTwo + new Vector2(1f, 0f);
allTriangles[(count * 2 * 3) - 6] = count * 2 - 2;
allTriangles[(count * 2 * 3) - 5] = count * 2 - 1;
allTriangles[(count * 2 * 3) - 4] = count * 2 + 3;
allTriangles[(count * 2 * 3) - 3] = count * 2 - 2;
allTriangles[(count * 2 * 3) - 2] = count * 2 + 3;
allTriangles[(count * 2 * 3) - 1] = count * 2 + 2;
}
mesh.vertices = allVertices;
mesh.uv = allUVs;
mesh.triangles = allTriangles;
mesh.bounds = new Bounds(Vector3.zero, new Vector3(innerRadius + circleWidth, 0.1f, innerRadius + circleWidth));
busy = false;
}
}
No comments:
Post a Comment