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
}
相关推荐
da_vinci_x7 小时前
Substance Designer的通道合并(Channel Packing)自动化工作流
3d·自动化·贴图·技术美术·游戏策划·游戏美术·substance designer
康谋自动驾驶14 小时前
拆解3D Gaussian Splatting:原理框架、实战 demo 与自驾仿真落地探索!
算法·数学建模·3d·自动驾驶·汽车
黑金IT14 小时前
3D虚拟人模型转换的完整指南
服务器·数据库·3d
开发游戏的老王17 小时前
虚幻引擎虚拟制片入门教程目录
游戏引擎·虚幻
future_studio21 小时前
聊聊 Unity(小白专享、C# 小程序 之 自动更新)
unity·小程序·c#
心疼你的一切1 天前
Unity开发利器:ScriptableObject的数据容器设计与内存优化原理
microsoft·unity·c#·游戏引擎
xhload3d1 天前
WebGL/Canvas 内存泄露分析
低代码·3d·html5·webgl·数字孪生·可视化·软件开发·工业互联网·内存泄漏·轻量化·技术应用·hightopo
至善迎风1 天前
将跨平台框架或游戏引擎开发的 Windows 应用上架 Microsoft Store
windows·microsoft·游戏引擎
worxfr1 天前
小游戏引擎架构设计案例分析
游戏引擎
Cool-浩1 天前
【征文计划】Rokid 语音指令开发教程 【包含工程源码 和体验包APK】
unity·ar·语音识别·rokid·语音指令