Unity LineRenderer 根据圆的中心、半径、朝向在三维空间中画圆

2022-08-29 16:35:08 浏览数 (1)

在三维空间中生成一个圆,需要知道圆的中心点位置、圆的半径以及圆的朝向这三个参数,通过这三个参数求得在圆上的点坐标,最终通过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);
        }
    }
}

0 人点赞