Unity开发绘画板——04.笔刷大小调节

news2024/11/19 1:44:15

笔刷大小调节

上面的代码中其实我们已经提供了笔刷大小的字段,即brushSize,现在只需要将该字段和界面中的Slider绑定即可,Slider值的范围我们设置为1~20

代码中只需要做如下改动:

public Slider brushSizeSlider; //控制笔刷大小的滑动条
public float brushSize => brushSizeSlider.value;    //笔刷大小取滑动条的值

完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Painter : MonoBehaviour
{
    public RenderTexture renderTexture;
    public Slider brushSizeSlider;
    public Texture2D brushTexture; //笔刷纹理
    public float brushSize => brushSizeSlider.value;    //笔刷大小
    
    public float resolutionMultiplier = 5;  //线性插值密度调节
    
    
    private Vector2 previousMousePos; //记录上一帧鼠标的位置  
    
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            previousMousePos = Input.mousePosition;
        }
        
        if (Input.GetMouseButton(0))
        {
            var mousePosition = Input.mousePosition;
            DrawLine(previousMousePos, mousePosition);
            previousMousePos = mousePosition;
        }
    }

    private void DrawLine(Vector2 start, Vector2 end)
    {
        float distance = Vector2.Distance(start, end);
        int steps = Mathf.CeilToInt(distance * resolutionMultiplier);
        for (int i = 0; i <= steps; i++)
        {
            float t = i / (float)steps;
            int x = Mathf.FloorToInt(Mathf.Lerp(start.x, end.x, t));
            int y = Mathf.FloorToInt(Mathf.Lerp(start.y, end.y, t));
            DrawBrush(x, y);
        }
    }

    private void DrawBrush(int x, int y)
    {
        Rect brushRect = new Rect(x, y, brushSize, brushSize);
        Graphics.SetRenderTarget(renderTexture);
        GL.PushMatrix();
        GL.LoadPixelMatrix(0, renderTexture.width, 0, renderTexture.height);
        Graphics.DrawTexture(brushRect, brushTexture);
        GL.PopMatrix();
        Graphics.SetRenderTarget(null);
    }

    
}

效果优化 

运行效果如下图,可见虽然笔刷粗细已可以调节,但是在调节过程中,滑动的同时滑动条周围有绘制的线条,这本不该出现的,出现的原因是因为我们监听了鼠标按下的事件来绘制,这导致在操作滑动条的时候,绘制依然在进行。

操作UI时屏蔽绘制

我们需要检测当前的鼠标是否在UI元素上,如果在,则不进行绘制,这可以使用EventSystem的射线检测来实现,如下我们定义一个函数,当光标在UI元素上的时候返回true,否则返回false:

private bool IsPointerOverUIElement()
{
    PointerEventData eventData = new PointerEventData(EventSystem.current);
    eventData.position = Input.mousePosition;
    List<RaycastResult> results = new List<RaycastResult>();
    EventSystem.current.RaycastAll(eventData, results);
    return results.Count > 0;
}

我们在鼠标左键点击的时候判断是否在UI元素上,如果在则禁止绘制;

但有个问题,我们用来绘制的RawImage也是UI元素,它铺满整个屏幕,这会导致我们始终没办法绘制,我们可以将其Raycast Target关掉,这样再操作UI元素的时候就不会进行多余的绘制了

完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class Painter : MonoBehaviour
{
    public RenderTexture renderTexture;
    public Slider brushSizeSlider; //控制笔刷大小的滑动条
    public Texture2D brushTexture; //笔刷纹理
    public float brushSize => brushSizeSlider.value;    //笔刷大小取滑动条的值
    
    public float resolutionMultiplier = 5;  //线性插值密度调节
    
    
    private Vector2 previousMousePos; //记录上一帧鼠标的位置  
    private bool startFromUIElement = false; //点击是否是从UI元素上开始的
    void Update()
    {
        //判断光标是否在UI元素上
        if (Input.GetMouseButtonDown(0))
        {
            if (IsPointerOverUIElement())
            {
                startFromUIElement = true;
            }
            previousMousePos = Input.mousePosition;
        }
        
        if (Input.GetMouseButton(0) && !startFromUIElement)
        {
            var mousePosition = Input.mousePosition;
            DrawLine(previousMousePos, mousePosition);
            previousMousePos = mousePosition;
        }

        if (Input.GetMouseButtonUp(0))
        {
            startFromUIElement = false;
        }
    }

    private void DrawLine(Vector2 start, Vector2 end)
    {
        float distance = Vector2.Distance(start, end);
        int steps = Mathf.CeilToInt(distance * resolutionMultiplier);
        for (int i = 0; i <= steps; i++)
        {
            float t = i / (float)steps;
            int x = Mathf.FloorToInt(Mathf.Lerp(start.x, end.x, t));
            int y = Mathf.FloorToInt(Mathf.Lerp(start.y, end.y, t));
            DrawBrush(x, y);
        }
    }

    private void DrawBrush(int x, int y)
    {
        Rect brushRect = new Rect(x, y, brushSize, brushSize);
        Graphics.SetRenderTarget(renderTexture);
        GL.PushMatrix();
        GL.LoadPixelMatrix(0, renderTexture.width, 0, renderTexture.height);
        Graphics.DrawTexture(brushRect, brushTexture);
        GL.PopMatrix();
        Graphics.SetRenderTarget(null);
    }

    private bool IsPointerOverUIElement()
    {
        PointerEventData eventData = new PointerEventData(EventSystem.current);
        eventData.position = Input.mousePosition;
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventData, results);
        return results.Count > 0;
    }
    
}

在下一节我将为大家介绍如何调节线条的颜色~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2180059.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Altium Designer脚本的执行方式

在Altium Designer脚本系统中执行脚本支持多种方法 1.点击工具栏的运行工具(蓝色向右三角图标)可以执行脚本程序&#xff1b; 2.点击菜单栏Run->Run可以执行脚本程序&#xff1b; 3.在脚本编辑器中&#xff0c;按键盘的F9键可以执行脚本程序&#xff1b; 4.通过菜单栏执行脚…

新品 | Teledyne FLIR IIS 推出Forge 1GigE SWIR 短波红外工业相机系列

近日&#xff0c;51camera的合作伙伴Teledyne FLIR IIS推出了新品Forge 1GigE SWIR 130万像素的红外相机。 Forge 1GigE SWIR系列的首款相机配备宽频带、高灵敏度的Sony SenSWIR™️ 130万像素IMX990 InGaAs传感器。这款先进的传感器采用5um像素捕捉可见光和SWIR光谱&#xff…

【2025】基于Spring Boot的智慧农业小程序(源码+文档+调试+答疑)

文章目录 一、***-项目介绍二、***-开发环境三、***-系统展示四、***-代码展示五、***-项目文档展示六、***-项目总结 大家可以帮忙点赞、收藏、关注、评论啦 &#x1f447;&#x1f3fb; 一、***-项目介绍 当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#x…

【网盘源码】网站拦截申诉之部署验证文件

文件中新增文件&#xff0c;填写验证内容 nginx中配置反向代理 location /字符文件名.txt {alias /www/wwwroot/****/字符文件名.txt;}

倍增求 LCA

1. 树上倍增——倍增求 LCA LCA 指的是最近的公共祖先&#xff0c;倍增法求解 LCA 的步骤如下。 &#xff08;1&#xff09;预处理 a. 求深度&#xff1a;对于每个节点 dfs 预处理处节点深度&#xff1b; b. 求倍增祖先&#xff1a;计算出每个节点向父元素跳 步所到达的节点…

@网安人,欢度国庆,共享盛世!

一、网络安全&#xff1a;时代发展的关键基石 网络安全在当今数字化时代的重要性不言而喻&#xff0c;它如同坚实的基石&#xff0c;支撑着国家的稳定、经济的发展和社会的和谐。 &#xff08;一&#xff09;国家安全的关键防线 在当今世界&#xff0c;网络空间的战略地位愈…

Linux中配置docker环境

1.基础信息了解 &#xff08;1&#xff09;docker信息了解&#xff0c;docker官网 https://www.docker.com/&#xff0c;docker中文网 https://dockerdocs.cn/&#xff0c;还可以了解下虚拟化和容器化的知识&#xff0c;虚拟化和容器化 &#xff08;2&#xff09;查看当前Lin…

PyCharm vs VSCode,是时候改变你的 IDE 了!

在编程世界中&#xff0c;选择一个合适的 IDE (集成开发环境) 对开发者来说至关重要&#xff0c;直接影响开发效率和体验。 在软件开发的世界里&#xff0c;选择一个合适的集成开发环境&#xff08;IDE&#xff09;就如同为自己找到了一把趁手的工具。PyCharm 和 VSCode 是两款…

springboot厨房达人美食分享平台(源码+文档+调试+答疑)

文章目录 前言一、主要技术&#xff1f;二、项目内容1.整体介绍&#xff08;示范&#xff09;2.运行截图3.部分代码介绍 总结更多项目 前言 厨房达人美食分享平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c…

uniapp中在web端如何友好的展示app当前的版本等信息

一个小技巧&#xff0c;分享下在webapp中友好展示当前app信息的方法 实现效果 代码实现 导入 import {version,name} from ./package.json应用声明周期中处理 onLaunch: function() { // #ifdef H5console.log(%c hello uniapp %c v${version} ,background:#35495e ; paddin…

YOLOv11改进策略【损失函数篇】| Slide Loss,解决简单样本和困难样本之间的不平衡问题

一、本文介绍 本文记录的是改进YOLOv11的损失函数&#xff0c;将其替换成Slide Loss&#xff0c;并详细说明了优化原因&#xff0c;注意事项等。Slide Loss函数可以有效地解决样本不平衡问题&#xff0c;为困难样本赋予更高的权重&#xff0c;使模型在训练过程中更加关注困难样…

第十七章:c语言内存函数

1. memcpy使⽤和模拟实现 2. memmove使⽤ 3. memset函数的使⽤ 4. memcmp函数的使⽤ 天行健 君子以自强不息一、memcpy的使用和模拟实现 作用&#xff1a; 1. 函数memcpy从source的位置向后复制num个字节的数据到destination指向的内存位置。 2. 这个函数在遇到‘\0’的时…

如何创建出更鲁棒、更值得信赖的大模型

尽管深度学习取得了令人瞩目的成就&#xff0c;提供了各种各样的产品和功能&#xff0c;但它还没有跨过最后的障碍。 随着复杂的神经网络越来越多地应用于任务关键型和安全关键型应用中&#xff0c;围绕其鲁棒性出现的问题也越来越多。 许多深度学习算法的黑箱性质让精通安全的…

【完-网络安全】Windows注册表

文章目录 注册表启动项及常见作用五个根节点常见入侵方式 注册表 注册表在windows系统的配置和控制方面扮演了一个非常关键的角色&#xff0c;它既是系统全局设置的存储仓库&#xff0c;也是每个用户的设置信息的存储仓库。 启动项及常见作用 快捷键 WinR打开运行窗口&#x…

谱减法和维纳滤波的关系

目录 一、基本原理二、谱减法与维纳滤波的联系三、实际应用中的对比四、优缺点分析五、两者的融合与改进六、举例说明七、总结与展望 谱减法和维纳滤波是两种常见的语音增强算法&#xff0c;在信号处理领域中&#xff0c;特别是语音降噪方面有着广泛的应用。它们各自具有独特的…

【Python|接口自动化测试】使用requests发送http请求时添加headers

文章目录 1.前言2.HTTP请求头的作用3.在不添加headers时4.反爬虫是什么&#xff1f;5.在请求时添加headers 1.前言 本篇文章主要讲解如何使用requests请求时添加headers&#xff0c;为什么要加headers呢&#xff1f;是因为有些接口不添加headers时&#xff0c;请求会失败。 2…

执行力怎么培养?

执行力怎么培养&#xff1f; 并行&#xff1a;适合在初期养成习惯&#xff0c;不抱对结果的期望天才就是强迫症&#xff1a;适合中期修身&#xff1a;适合高级 并行&#xff1a;适合在初期养成习惯&#xff0c;不抱对结果的期望 在你开始做任何事情的时候&#xff0c;不要一开…

【STM32】 TCP/IP通信协议(1)--LwIP介绍

一、前言 TCP/IP是干啥的&#xff1f;它跟SPI、IIC、CAN有什么区别&#xff1f;它如何实现stm32的通讯&#xff1f;如何去配置&#xff1f;为了搞懂这些问题&#xff0c;查询资料可解决如下疑问&#xff1a; 1.为什么要用以太网通信? 以太网(Ethernet) 是指遵守 IEEE 802.3 …

基于Springboot+Vue的视频点播系统设计与实现登录 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

springboot工伤事故管理系统-计算机毕业设计源码04050

摘 要 工伤事故管理系统是为了提高企业对工伤事故的管理和处理能力而设计的。该系统主要利用现代技术手段构建一个全面、高效的工伤事故管理平台&#xff0c;帮助企业实现工伤事故的预防、记录、报告和分析。通过工伤事故管理系统&#xff0c;企业可以进行工伤事故的登记和记录…