news 2026/9/6 3:02:48

Unity标记固定颜色及投影标记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity标记固定颜色及投影标记

1 结构

2 CameraDisplay和DrawingOverlay为Raw Image

3 ProjectorCanvas可以直接复制上面的Canvas,然后删除其他不用的。

最后留下的只是渲染原来的标记。

4 游戏组件设置

Main Camera

ProjectorCamera

Canvas

using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; public class FixedOneColor : MonoBehaviour { [Header("底层显示摄像头")] public RawImage CamRaw; [Header("顶层绘图面板(同尺寸全屏)")] public RawImage DrawRaw; [Header("投影端RawImage")] public RawImage projectorRaw; private WebCamTexture _camTex; private Texture2D _drawTex; private int _w, _h; private bool _isDraw; private List<Vector2> _curPoints = new List<Vector2>(); private List<Stroke> _history = new List<Stroke>(); // 当前画笔颜色,默认红色 private Color _currentColor = Color.red; [Serializable] class Stroke { public List<Vector2> pts = new List<Vector2>(); public Color col; } void Start() { // 初始化相机 var device = WebCamTexture.devices[0]; _camTex = new WebCamTexture(device.name, 1280, 720); _camTex.Play(); CamRaw.texture = _camTex; // 初始化顶层绘图纹理 Invoke(nameof(InitDrawTex), 0.5f); } void InitDrawTex() { _w = _camTex.width; _h = _camTex.height; _drawTex = new Texture2D(_w, _h, TextureFormat.RGBA32, false); _drawTex.wrapMode = TextureWrapMode.Clamp; ClearDrawTex(); DrawRaw.texture = _drawTex; if (projectorRaw != null) projectorRaw.texture = _drawTex; } void Update() { if (_drawTex == null) return; // 键盘快捷键切换画笔颜色(与按钮功能一致) if (Input.GetKeyDown(KeyCode.R)) SetRedColor(); if (Input.GetKeyDown(KeyCode.G)) SetGreenColor(); if (Input.GetKeyDown(KeyCode.B)) SetBlueColor(); // 原有快捷键 if (Input.GetKeyDown(KeyCode.C)) ClearAll(); if (Input.GetKeyDown(KeyCode.S)) SaveImg(); DealMouse(); RenderDraw(); } // ========== 三个颜色切换方法,供UI按钮点击调用 ========== public void SetRedColor() { _currentColor = Color.red; } public void SetGreenColor() { _currentColor = Color.green; } public void SetBlueColor() { _currentColor = Color.blue; } void DealMouse() { // 按下 if (Input.GetMouseButtonDown(0)) { _isDraw = true; _curPoints.Clear(); _curPoints.Add(GetMouseTexPos()); } // 拖动 if (Input.GetMouseButton(0) && _isDraw) { var p = GetMouseTexPos(); if (Vector2.Distance(p, _curPoints.Last()) > 2f) _curPoints.Add(p); } // 抬起 if (Input.GetMouseButtonUp(0) && _isDraw) { _isDraw = false; if (_curPoints.Count < 2) { _curPoints.Clear(); return; } // 使用当前选中的颜色创建新笔画,默认红色 _history.Add(new Stroke { pts = new List<Vector2>(_curPoints), col = _currentColor }); _curPoints.Clear(); } } // 鼠标屏幕坐标 → 纹理像素坐标 Vector2 GetMouseTexPos() { RectTransform rect = DrawRaw.rectTransform; RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, Input.mousePosition, null, out Vector2 local); float x = Mathf.Lerp(0, _w, (local.x / rect.rect.width) + 0.5f); float y = Mathf.Lerp(0, _h, (local.y / rect.rect.height) + 0.5f); x = Mathf.Clamp(x, 0, _w - 1); y = Mathf.Clamp(y, 0, _h - 1); return new Vector2(x, y); } // 渲染所有笔画 void RenderDraw() { ClearDrawTex(); // 历史正式线条 foreach (var s in _history) DrawLineList(s.pts, s.col); // 当前临时预览线条,使用当前选中颜色 if (_isDraw && _curPoints.Count > 1) DrawLineList(_curPoints, _currentColor); _drawTex.Apply(); } void DrawLineList(List<Vector2> pts, Color col) { for (int i = 0; i < pts.Count - 1; i++) DrawBresenham(pts[i], pts[i + 1], col, 3); } // 画线 void DrawBresenham(Vector2 p1, Vector2 p2, Color col, int size) { int x0 = (int)p1.x, y0 = (int)p1.y; int x1 = (int)p2.x, y1 = (int)p2.y; int dx = Mathf.Abs(x1 - x0); int dy = Mathf.Abs(y1 - y0); int sx = x0 < x1 ? 1 : -1; int sy = y0 < y1 ? 1 : -1; int err = dx - dy; while (true) { DrawPoint(x0, y0, col, size); if (x0 == x1 && y0 == y1) break; int e2 = 2 * err; if (e2 > -dy) { err -= dy; x0 += sx; } if (e2 < dx) { err += dx; y0 += sy; } } } void DrawPoint(int x, int y, Color col, int r) { for (int dx = -r; dx <= r; dx++) for (int dy = -r; dy <= r; dy++) { if (dx * dx + dy * dy <= r * r) { int px = x + dx; int py = y + dy; if (px >= 0 && px < _w && py >= 0 && py < _h) _drawTex.SetPixel(px, py, col); } } } void ClearDrawTex() { if (_drawTex == null) return; Color[] clear = new Color[_w * _h]; for (int i = 0; i < clear.Length; i++) clear[i] = Color.clear; _drawTex.SetPixels(clear); } void ClearAll() { _history.Clear(); _curPoints.Clear(); _isDraw = false; ClearDrawTex(); } void SaveImg() { RenderTexture rt = new RenderTexture(_w, _h, 24); rt.Create(); CamRaw.texture = _camTex; DrawRaw.texture = _drawTex; Texture2D saveTex = new Texture2D(_w, _h); saveTex.ReadPixels(new Rect(0, 0, _w, _h), 0, 0); saveTex.Apply(); byte[] png = saveTex.EncodeToPNG(); string path = Application.persistentDataPath + "/cam_draw.png"; System.IO.File.WriteAllBytes(path, png); Debug.Log("保存成功:" + path); } void OnDestroy() { if (_camTex != null) _camTex.Stop(); } }

ProjectorCanvas

ProjectorCanvas下面的DrawingOverlay直接复制上在的

效果,主屏可以显示而且投影可以显示标记。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 3:02:17

GLM-5.3-Flash接入Cline:免费3亿token,AI编程降本增效实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 3:01:47

基于SpringBoot和微信小程序的小学生托管系统

博主介绍&#xff1a;资深开发工程师&#xff0c;从事互联网行业多年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实实在在的写点程序。&#x1f345;获取源…

作者头像 李华
网站建设 2026/9/6 2:59:36

Unity根据相机的背景色标记变化为明显的颜色并投影

1 结构2 CameraDisplay&#xff0c; DrawingOverlay 为下面类型3 CanvasProjector 可以复制上面的Canvas然后删除其他的&#xff0c;这样就不用修改位置比例等相关参数4 游戏对象参数设置Main Camera脚本using System; using System.Collections.Generic; using System.Linq; u…

作者头像 李华
网站建设 2026/9/6 2:58:37

i7-8700K + GTX 1080 还能玩什么?看清硬件行情1080p 稳帧清单这样选

核心信息摘要&#xff08;7个要点&#xff09;• 硬件适配跨度大&#xff1a;黑旗重制版等作品提供从 GTX 1660 到 RTX 4090 的多档配置&#xff1b;GTX 1080 光栅性能接近官方最低配置 GTX 1660&#xff0c;在 1080p 降低画质档位即可流畅运行• 1080p 稳帧优先&#xff1a;对…

作者头像 李华
网站建设 2026/9/6 2:50:01

紫悦/暮光闪闪AI绘画工具本地部署指南:从环境配置到功能测试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 2:47:12

SystemVerilog实战指南:从Verilog到现代芯片验证的进阶之路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华