在三维空间中生成一个圆,需要知道圆的中心点位置、圆的半径以及圆的朝向这三个参数,通过这三个参数求得在圆上的点坐标,最终通过LineRenderer组件将圆绘制出来:
首先从二维平面来看,我们已知圆的中心点(x0, y0),半径r,即可通过以下公式求得角度a的圆上的点坐标位置(x,y):
x = x0 r * cos(a * 3.14 / 180)
y = y0 r * sin(a * 3.14 / 180)
以Unity中的x轴、z轴形成的平面为例,假设我们每一度求得一个圆上的点坐标位置,通过360个坐标画出一个圆,代码如下:
代码语言:javascript复制using UnityEngine;
public class Example : MonoBehaviour
{
private void Start()
{
//圆的中心点位置
Vector3 center = Vector3.zero;
//圆的半径
float radius = 3f;
//添加LineRenderer组件
LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
//设置坐标点个数为360个
lineRenderer.positionCount = 360;
//将LineRenderer绘制线的宽度 即圆的宽度 设为0.04
lineRenderer.startWidth = .04f;
lineRenderer.endWidth = .04f;
//每一度求得一个在圆上的坐标点
for (int i = 0; i < 360; i )
{
float x = center.x radius * Mathf.Cos(i * Mathf.PI / 180f);
float z = center.z radius * Mathf.Sin(i * Mathf.PI / 180f);
lineRenderer.SetPosition(i, new Vector3(x, 0, z));
}
}
}
代码语言:javascript复制 运行上面的代码,即可得到在x、z轴所在的平面上以原点为中心,3为半径的通过Line Renderer组件绘制出的一个圆,如图所示:
圆上缺了一个口,我们可以通过将Line Renderer组件的Loop属性设置为true来处理,该属性设为true后,可以将第一个点和最后一个点相连,形成闭环:
有了上述在二维平面上绘制圆的基础后,在三维空间中绘制一个圆,需要添加一个参数,即圆的朝向,可以通过一个坐标点的位置减去圆的中心的位置求得该方向向量。在x、z轴所在的平面绘制出的圆,其朝向即Vector3.up,我们可以通过Quaternion类中的FromToRotation函数将该方向旋转到我们指定的方向,再通过向量与四元数相乘求得圆上的坐标位置:
代码语言:javascript复制using UnityEngine;
public class Example : MonoBehaviour
{
//该点与圆的中心点形成一个圆的朝向
[SerializeField] private Transform point;
private void Start()
{
//圆的中心点位置 假设为(0, 0, 0)
Vector3 center = Vector3.zero;
//圆的半径
float radius = 3f;
//添加LineRenderer组件
LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
//设置坐标点个数为360个
lineRenderer.positionCount = 360;
//将LineRenderer绘制线的宽度 即圆的宽度 设为0.04
lineRenderer.startWidth = .04f;
lineRenderer.endWidth = .04f;
//设置闭环
lineRenderer.loop = true;
//朝向
Quaternion direction = Quaternion.FromToRotation(Vector3.up, point.position - Vector3.zero);
//每一度求得一个在圆上的坐标点
for (int i = 0; i < 360; i )
{
float x = center.x radius * Mathf.Cos(i * Mathf.PI / 180f);
float z = center.z radius * Mathf.Sin(i * Mathf.PI / 180f);
Vector3 pos = new Vector3(x, 0, z);
pos = direction * pos;
lineRenderer.SetPosition(i, pos);
}
}
}
代码语言:javascript复制 我们将朝向在OnDrawGizmos函数中通过Handles类中的DrawLine方法绘制出来便于查看,该方法可以在Scene场景窗口中绘制出一条直线。关于OnDrawGizmos和Handles的介绍如下:
代码语言:javascript复制private void OnDrawGizmos()
{
Handles.color = Color.cyan;
Handles.DrawLine(Vector3.zero, point.position);
}
到此,已经可以在三维空间中绘制出圆,最终我们通过this关键字将其封装到Line Renderer类中作为拓展方法:
代码语言:javascript复制using UnityEngine;
namespace SK.Framework
{
public static class LineRendererExtension
{
/// <summary>
/// 绘制一个圆
/// </summary>
/// <param name="self">LineRenderer组件</param>
/// <param name="center">圆的中心点坐标</param>
/// <param name="direction">圆的朝向</param>
/// <param name="radius">圆的半径</param>
/// <param name="thickness">圆的宽度 即LineRenderer组件width</param>
/// <returns></returns>
public static LineRenderer DrawCircle(this LineRenderer self, Vector3 center, Vector3 direction, float radius, float thickness)
{
//设置宽度
self.startWidth = thickness;
self.endWidth = thickness;
//设置坐标点个数
self.positionCount = 360;
//设置闭环
self.loop = true;
//朝向
Quaternion q = Quaternion.FromToRotation(Vector3.up, direction);
float x, z;
//每一度求得一个在圆上的坐标点
for (int i = 0; i < 360; i )
{
x = center.x radius * Mathf.Cos(i * Mathf.PI / 180f);
z = center.z radius * Mathf.Sin(i * Mathf.PI / 180f);
Vector3 pos = new Vector3(x, center.y, z);
pos = q * pos;
self.SetPosition(i, pos);
}
return self;
}
}
}
测试代码:
代码语言:javascript复制using UnityEngine;
using UnityEditor;
using SK.Framework;
public class Example : MonoBehaviour
{
//圆的中心点
[SerializeField] private Transform center;
//该点与圆的中心点形成一个圆的朝向
[SerializeField] private Transform point;
private void OnDrawGizmos()
{
Handles.color = Color.cyan;
Handles.DrawLine(center.position, point.position);
}
private void OnGUI()
{
if (GUILayout.Button("生成", GUILayout.Width(200f), GUILayout.Height(50f)))
{
LineRenderer line = gameObject.GetComponent<LineRenderer>();
if (line == null) line = gameObject.AddComponent<LineRenderer>();
line.DrawCircle(center.position, point.position - center.position, 3f, 0.04f);
}
}
}