unity基础——3D画线

关键术语解释:

  1. LineRenderer

    • Unity的组件类,用于在3D空间绘制连续线段

    • 主要属性:positions(坐标点集合)、width(线条粗细)、material(外观材质)

    • numCapVertices:线端顶点数,影响端点圆滑度

    • numCornerVertices:拐角顶点数,影响转角平滑度

  2. Raycast

    • 物理检测方法,发射不可见射线检测碰撞体

    • ScreenPointToRay:将屏幕坐标转换为3D空间射线

    • 依赖Collider组件,用于准确定位绘制位置

  3. List<Vector3>

    • C#泛型集合,动态存储坐标序列

    • 相比数组,支持动态扩容和便捷操作(Add/Clear等)

  4. Vector3.Distance

    • 静态方法,计算两个三维点之间的欧几里得距离

    • 用于判断鼠标移动量是否达到绘制阈值

  5. UI Toggle

    • Unity UI系统的开关组件

    • 通过OnValueChanged事件绑定颜色/尺寸切换方法

脚本设计思路:

  1. 输入处理流程

    • 按下阶段:初始化新线条,记录起始点

    • 持续阶段:每帧检测鼠标移动,满足条件时添加新点

    • 释放阶段:清理数据,准备下次绘制

  2. 坐标获取机制

    • 使用主摄像机发射射线

    • 依赖场景中的Collider获取准确坐标

    • Z轴偏移解决渲染重叠问题

  3. 渲染优化策略

    • 动态更新LineRenderer的positions数组

    • 使用List管理坐标点,自动处理内存

    • 通过顶点数配置提升线条视觉质量

  4. 模块化设计

    • 分离核心绘制逻辑(AddPosition)

    • 独立坐标获取方法(GetMousePoint)

    • 清晰的UI事件处理区域

实现代码:

cs 复制代码
using System.Collections.Generic;
using UnityEngine;

public class Mapaint : MonoBehaviour
{
    // 画笔颜色属性 和 画笔大小属性
    public Color paintColor = Color.red;
    public float paintSize = 0.1f;
    // 当前画线
    public LineRenderer Currentline;
    // 画线的材质
    public Material lineMaterial;
    //存储线条点的坐标集合
    private List<Vector3> positions = new List<Vector3>();
    // 鼠标按下状态标志
    private bool isMouseDown = false;
    // 鼠标上一帧位置
    private Vector3 lastMousePosition = Vector3.zero;

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // 创建新的游戏对象承载LineRenderer组件
            GameObject go = new GameObject();
            go.transform.SetParent(this.transform);  // 挂载到当前物体下
            Currentline = go.AddComponent<LineRenderer>();  // 添加LineRenderer组件

            // 设置材质
            Currentline.material = lineMaterial;
            // 设置宽度
            Currentline.startWidth = paintSize;
            Currentline.endWidth = paintSize;
            // 设置颜色
            Currentline.startColor = paintColor;
            Currentline.endColor = paintColor;

            Currentline.numCapVertices = 5;  // 设置顶点数
            Currentline.numCornerVertices = 5;  // 设置角点数

            // 初始化第一个点
            Vector3 position = GetMousePoint();
            position.z -= 1f;
            positions.Clear();
            AddPosition(position);  // 调用AddPosition方法
            lastMousePosition = position; // 记录初始位置

            // 标记鼠标按下状态
            isMouseDown = true;


        }
        // 持续按住鼠标时持续添加点
        if (isMouseDown)
        {
            Vector3 currentPos = GetMousePoint();
            currentPos.z -= 1f;
           
            // 鼠标移动时,距离大于0.01时才添加点
            if (Vector3.Distance(currentPos, lastMousePosition) > 0.01f)
            {
                AddPosition(currentPos);
                lastMousePosition = currentPos;
                Debug.Log("加点");
            }
        }

        // 鼠标松开时结束绘制
        if (Input.GetMouseButtonUp(0))
        {
            Currentline = null;
            // 清空历史坐标点
            positions.Clear();
            isMouseDown = false;
        }

        // 添加坐标点到当前线条
        void AddPosition(Vector3 position)
        {
            positions.Add(position);

            // 更新LineRenderer数据
            Currentline.positionCount = positions.Count;
            Currentline.SetPositions(positions.ToArray());

        }
        // 通过射线检测获取鼠标在场景中的坐标(需要场景中存在碰撞体)
        Vector3 GetMousePoint()
        {
            // 创建从摄像机发射的射线
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;  // 存储射线碰撞信息的结构体

            // 进行物理射线检测(最大距离默认为无限)
            bool isCollider = Physics.Raycast(ray, out hit);
            if (isCollider)
            {
                return hit.point;  // 返回碰撞点的世界坐标
            }

            return Vector3.zero;  // 安全返回值

        }
    }

    #region
    public void OnRedColorChanged(bool isON)
    {
        if (isON)
        {
            paintColor = Color.red;
        }
    }
    public void OnGreenColorChanged(bool isON)
    {
        if (isON)
        {
            paintColor = Color.green;
        }
    }
    public void OnBlueColorChanged(bool isON)
    {
        if (isON)
        {
            paintColor = Color.blue;
        }
    }
    public void OnPaint1Changed(bool isON)
    {
        if (isON)
        {
            paintSize = 0.1f;
        }
    }
    public void OnPaint2Changed(bool isON)
    {
        if (isON)
        {
            paintSize = 0.2f;
        }
    }
    public void OnPaint3Changed(bool isON)
    {
        if (isON)
        {
            paintSize = 0.4f;
        }
    }
    #endregion
}
相关推荐
MWHLS4 小时前
【以及好久没上号的闲聊】Unity记录8.1-地图-重构与优化
unity·开源
虾球xz5 小时前
游戏引擎学习第286天:开始解耦实体行为
c++·人工智能·学习·游戏引擎
广州智造10 小时前
OptiStruct实例:3D实体转子分析
数据库·人工智能·算法·机器学习·数学建模·3d·性能优化
码农黛兮_4610 小时前
4. 文字效果/2D-3D转换 - 3D翻转卡片
3d·html·css3
WarPigs16 小时前
Unity光照笔记
笔记·unity·游戏引擎
gameatp20 小时前
UE RPG游戏开发练手 第二十六课 普通攻击1
游戏引擎·虚幻
神码编程20 小时前
【Unity】 HTFramework框架(六十五)ScrollList滚动数据列表
unity·游戏引擎·ugui
DanmF--21 小时前
Protobuf工具
网络·unity·游戏引擎·游戏程序
敲代码的 蜡笔小新1 天前
【行为型之迭代器模式】游戏开发实战——Unity高效集合遍历与场景管理的架构精髓
unity·设计模式·c#·迭代器模式
Magnum Lehar2 天前
3d游戏引擎的math矩阵实现
线性代数·矩阵·游戏引擎