Unity开发绘画板——03.简单的实现绘制功能
从本篇文章开始,将带着大家一起写代码,我不会直接贴出成品代码,而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面,当然,同一个问题的解决方案可能会有很多,甚至有更好更高效的方式是我所没有想到的,大家也可以在评论区一起讨论一下。
1.监听鼠标输入
要实现绘画的功能,监听鼠标的输入是首先要解决的问题,我们希望按下鼠标左键之后开始在屏幕中绘制,要实现这个也比较简单。
我们先在Scripts文件夹下创建一个新脚本,命名为Painter.cs, 并将其挂载到场景中的Painter节点上,我们将在Painter.cs的Update中实现该逻辑。
public class Painter : MonoBehaviour
{void Update(){if (Input.GetMouseButtonDown(0)){//开始绘制var mousePosition = Input.mousePosition; //获取当前鼠标位置}if (Input.GetMouseButton(0)){//绘制}if (Input.GetMouseUp(0)){//停止绘制}}
}
2.绘制图案
通过Graphics.DrawTexture接口向RenderTexture中绘制图案,这里的图案其实就是我们的笔刷样式了。
例如我们现在有一张圆形的图案:
想要用这个作为笔刷在一张空的RenderTexture上去作画,实现的代码也很简单,在Painter.cs中实现如下方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Painter : MonoBehaviour
{public RenderTexture renderTexture;public Texture2D brushTexture; //笔刷纹理public float brushSize = 5f;void Update(){if (Input.GetMouseButtonDown(0)){}if (Input.GetMouseButton(0)){var mousePosition = Input.mousePosition;DrawBrush((int)mousePosition.x, (int)mousePosition.y);}}private void DrawBrush(int x, int y){//纹理绘制的位置和大小Rect brushRect = new Rect(x, y, brushSize, brushSize);//指定渲染目标为renderTextureGraphics.SetRenderTarget(renderTexture);//保存当前矩阵状态GL.PushMatrix();//设置像素矩阵GL.LoadPixelMatrix(0, renderTexture.width, 0, renderTexture.height);//绘制纹理Graphics.DrawTexture(brushRect, brushTexture);//恢复之前的矩阵状态GL.PopMatrix();//重置渲染目标Graphics.SetRenderTarget(null);}}
由于笔刷颜色是白色的,画板背景也是白色,为了让绘制结果能被看到,我们先把背景颜色调成黑色,改变MainCamera的Background即可(改变线条颜色我们之后会讲到),执行效果如下图所示:
可见已经有点感觉了,但是表现是很多间断的点,而不是连续的线,因为我们的绘制是由Update驱动的,所以绘制速度也受Update帧率影响,当鼠标速度快的时候尤其明显。
为了解决这个问题,我们可以考虑在点与点之间进行线性插值,绘制更多的点,这样就会显得连续了。
原理如下图:
从A点到B点之间线性插入若干点。
为了达到此目的,我们需要从一下几个点入手:
- 我们期望这些插入点的密度是可以通过参数调节的
- 我们在绘制当前的位置时需要知道上一次绘制的位置
简单改一下代码:
新增一个previousMousePos字段,用于记录上一次笔刷位置
新增函数 private void DrawLine(Vector2 start, Vector2 end) 用于绘制两点之间的连线
优化后的代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Painter : MonoBehaviour
{public RenderTexture renderTexture;public Texture2D brushTexture; //笔刷纹理public float brushSize = 5f; //笔刷大小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);}}
效果如下,感觉还是不错的~
这样我们就简单实现了绘制的功能,下一章我们来实现滑动条调节画笔的大小~
相关文章:

Unity开发绘画板——03.简单的实现绘制功能
从本篇文章开始,将带着大家一起写代码,我不会直接贴出成品代码,而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面,当然,同一个问题的解决方案可能会有很多,甚至有更好更高效的方式是…...

R语言的基础知识R语言函数总结
R语言与数据挖掘:公式;数据;方法 R语言特征 对大小写敏感通常,数字,字母,. 和 _都是允许的(在一些国家还包括重音字母)。不过,一个命名必须以 . 或者字母开头,并且如果以 . 开头&…...

龙年国庆专属姓氏头像
关注▲洋洋科创星球▲一起成长! 2024年,我们迎来了龙年,龙年国庆姓氏头像! 慢慢找! 你的和你朋友的都有。 01赵 02 钱 03 孙 04 李 05 周 06 吴 07 郑 08 王 09 冯 010 陈 011 褚 012 卫 013 蒋 014 沈 015 韩 姓氏…...

基于Es和智普AI实现的语义检索
1、什么是语义检索 语义检索是一种利用自然语言处理(NLP)和人工智能(AI)技术来理解搜索查询的语义,以提供更准确和相关搜索结果的搜索技术,语义检索是一项突破性的技术,旨在通过深入理解单词和…...

URI和URL的区别
1: 将 URI 转换为 URL import java.net.URI; import java.net.URL;public class UriToUrlExample {public static void main(String[] args) {// 创建一个 URI 对象URI uri = new URI("http://example.com/path/to/resource");// 将 URI 转换为 URLtry {URL url = u…...
Java 入门指南:获取对象的内存地址
文章目录 hashCode()应用重写 hashCode() 方法示例 Symstem . indentityHashCode()应用 注意事项 在 Java 开发中,了解对象的内存管理是十分重要的,尽管 Java 的设计初衷是让开发者更专注于业务逻辑而非底层资源管理。但在某些情况下,了解对象…...

【Linux】项目自动化构建工具-make/Makefile 详解
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…...
嵌入式开发中学习C++的用处?
这个问题一直有同学在问,其实从我的角度是一定是需要学的,最直接的就是你面试大厂的嵌入式岗位或者相关岗位,最后一定会问c,而很多人是不会的,这就是最大的用处,至于从技术角度考量倒是其次,因为…...
基于SAM大模型的遥感影像分割工具,用于创建交互式标注、识别地物的能力,可利用Flask进行封装作为Web后台服务
如有帮助,支持一下(GitHub - Lvbta/ImageSegmentationTool-SAM: An interactive annotation case developed based on SAM for remote sensing image annotation, which can generate corresponding segmentation results based on point, multi-point, …...
Selenium入门
Selenium 是一个用于自动化 web 应用程序测试的工具,它支持多种浏览器和编程语言。 下载驱动程序:根据你的浏览器类型和版本,下载相应的 WebDriver。例如,Chrome 浏览器需要 ChromeDriver。 安装 Selenium 库 pip install sele…...

USB 3.1 Micro-A 与 Micro-B 插头,Micro-AB 与 Micro-B 插座,及其引脚定义
连接器配对 下表列出 USB 插座可接受的插头: USB 3.1 Micro-B 连接器 USB 3.1 Micro-B 插头和 USB 3.1 Micro-B 插座连接器是为小型手持设备和其他可能使用小尺寸连接器的应用而定义的。其定义使得 USB 3.1 Micro-B 插座既可以接受 USB 3.1 Micro-B 插头ÿ…...

MySQL多版本并发控制MVCC实现原理
MVCC MVCC 是多版本并发控制方法,用来解决读和写之间的冲突,比如脏读、不可重复读问题,MVCC主要针对读操作做限制,保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。 概述 当一个事务要对数据库中的数据进行selec…...
【并查集】[ABC372E] K-th Largest Connected Components 题解
题意 前置阅读:并查集算法介绍 洛谷链接 Atcoder 链接 给定 n ( 1 ≤ n ≤ 2 1 0 5 ) n(1 \leq n \leq 2\times 10^5) n(1≤n≤2105) 个点,初始没有边,您要进行以下操作: 1 a b,表示连接一条 ( a , b ) (a,b) …...
HarmonyOS面试题(持续更新中)
1、用过线程通信吗,线程是怎么进行通信的? emitter 和 eventHub 相同: 都是基于事件总线的 区别是: ① eventHub当前线程内通信 ② emitter是同一进程不同线程或者同一进程和同一线程也可以通信 2、页面和组件的生命周期 …...
QT中QWidget和QObject的区别与联系是什么
在Qt框架中,QWidget和QObject是两个核心类,它们各自扮演着不同的角色,但又紧密相连。以下是关于它们区别与联系的详细解释: 区别 基类和功能定位: QObject是Qt中所有类的基类,包括几乎所有的Qt对象。它提供…...

解决macOS安装redis以后不支持远程链接的问题
参考文档:https://blog.csdn.net/qq_37703224/article/details/142542179?spm1001.2014.3001.5501 安装的时候有个提示, 使用指定配置启动: /opt/homebrew/opt/redis/bin/redis-server /opt/homebrew/etc/redis.conf那么我们可以尝试修改这个配置文件: code /opt/homebrew/…...

2024年研究生数学建模“华为杯”E题——肘部法则、k-means聚类、目标检测(python)、ARIMA、逻辑回归、混淆矩阵(附:目标检测代码)
文章目录 一、情况介绍二、思路情况二、代码展示三、感受 一、情况介绍 前几天也是参加了研究生数学建模竞赛(也就是华为杯),也是和本校的两个数学学院的朋友在网上组的队伍。昨天(9.25)通宵干完论文(一条…...

绝了,自从用了它,我每天能多摸鱼2小时!
大家好,我是可乐。 俗话说的好:“摸鱼一时爽,一直摸鱼一直爽”。 作为一个程序员,是否有过调试代码熬到深夜?是否有过找不到解决方案而挠秃头顶? 但现在你即将要解放了,用了这款工具——秘塔…...

C语言指针系列1——初识指针
祛魅:其实指针这块儿并不难,有人说难只是因为基础到进阶没有处理好,大家要好好跟着一步一步学习,今天我们先来认识一下指针 指针定义:指针就是内存地址,指针变量是用来存放内存地址的变量,在同一…...

传神论文中心|第26期人工智能领域论文推荐
在人工智能领域的快速发展中,我们不断看到令人振奋的技术进步和创新。近期,开放传神(OpenCSG)传神社区发现了一些值得关注的成就。传神社区本周也为对AI和大模型感兴趣的读者们提供了一些值得一读的研究工作的简要概述以及它们各自…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...