using QFramework; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.Rendering; using UnityEngine.UI; [RequireComponent(typeof(Camera))] public class ScreenShotPainter : MonoBehaviour { public class LineSegment { public RenderTexture Texture { get; set; } public Color Color { get; set; } public float Width { get; set; } public bool IsEraser { get; set; } public LineSegment(Color color, float width, bool isEraser) { Texture = RenderTexture.GetTemporary(Screen.width, Screen.height, 24); Color = color; Width = width; IsEraser = isEraser; } } public static ScreenShotPainter instance; #region private numbers //[SerializeField] private string _captureSavePath; //private Canvas _paintCanvas; //[SerializeField] private Texture _defaultBrushRawImage; /// /// 涂鸦的RenderTexture图片 /// private RenderTexture _currentRenderTexture; /// /// 涂鸦的RenderTexture图片 /// //private RenderTexture _historyRenderTexture; /// /// 截图灰化背景图 /// //[SerializeField] private RawImage _bgRawImage; //绘图shader&material //[SerializeField] private Shader _paintBrushShader; private Material _paintBrushMat; //清理renderTexture的shader&material //[SerializeField] private Shader _clearBrushShader; private Material _clearBrushMat; //[SerializeField] private Shader _eraserBrushShader; private Material _eraserBrushMat; //笔刷的默认颜色 [SerializeField] private Color _defaultColor = Color.black; //涂鸦的画布 [SerializeField] private RawImage _paintCanvasImg; /// /// 笔刷的大小 /// [SerializeField] private float _brushSize = 300f; /// /// 橡皮擦的大小 /// [SerializeField] private float _eraserSize = 300f; /// /// 笔刷间隔 /// private float _brushLerpSize; /// /// 默认上一次点的位置 /// private Vector2 _lastPoint; /// /// 截图框选左下角点坐标 /// private Vector2 _leftDownConnerPoint; /// /// 截图框选右上角点坐标 /// private Vector2 _rightUpConnerPoint; /// /// 截图框选左上角点坐标 /// private Vector2 _leftUpConnerPoint; /// /// 截图框选右下角点坐标 /// private Vector2 _rightDownConnerPoint; //屏幕的宽高 private int _screenWidth; private int _screenHeight; #region 框选截图区域 //框选截图起始点 private Vector2 _startPoint; private Vector2 _endPoint; //框的颜色 [SerializeField] private Color _rectColor = Color.red; private bool _haveCirmformRectStarPoint; #endregion /// /// 组件开关 /// private bool _enabled; private bool _eraserFlag; private CaptureType _defaultCaptureType; /// /// 是否已经选了区域 /// private bool _haveRegion; private bool _drawRegionRect; /// /// 截图标记位 /// private bool _captureFlag; /// /// 是否要截取UI /// [SerializeField] private bool _captureWithUI; private Material _lineMaterial; #region 一些外部注册事件 /// /// 画完区域后要做的事情(其实就是处理UI面板,给外部调用) /// private FinishedRegionEvent _finishedRegionEvent = new FinishedRegionEvent(); /// /// 取消选择区域后要做的事情(其实就是处理UI面板,给外部调用) /// private CannelRegionEvent _cannelRegionEvent = new CannelRegionEvent(); private FinishedCaptureEvent _finishedCapture = new FinishedCaptureEvent(); private EscapeCaptureEvent _escapeCaptureEvent = new EscapeCaptureEvent(); private EnterCaptureModeEvent _enterCaptureModeEvent = new EnterCaptureModeEvent(); private EraserModeUpdateEvent _eraserModeUpdateEvent = new EraserModeUpdateEvent(); #endregion #endregion #region public properties public FinishedRegionEvent FinishedRegionEvent { get { return _finishedRegionEvent; } } public CannelRegionEvent CannelRegionEvent { get { return _cannelRegionEvent; } } public FinishedCaptureEvent FinishedCapture { get { return _finishedCapture; } } public EscapeCaptureEvent EscapeCaptureEvent { get { return _escapeCaptureEvent; } } #endregion private Stack _lineStack = new Stack(); private LineSegment _currentLine; public enum Status { Pen, Eraser, Line, Rect, Circle, } public EnterCaptureModeEvent EnterCaptureModeEvent { get { return _enterCaptureModeEvent; } } public EraserModeUpdateEvent EraserModeUpdateEvent { get { return _eraserModeUpdateEvent; } } #region life circle bool isInited = false; Status status = Status.Pen; private CommandBuffer _commandBuffer; private float _lastPaintTime; private float _paintInterval = 0.02f; // 每0.02秒绘制一次 Image circleImg; Image rectImg; void Awake() { instance = this; } public void Init(RawImage drawImg, RawImage bgRawImg, Image circleImg, Image rectImg) { if (isInited == false) { isInited = true; this.circleImg = circleImg; this.rectImg = rectImg; _commandBuffer = new CommandBuffer(); _commandBuffer.name = "PaintCommandBuffer"; _bgRawImage = bgRawImg; _paintCanvasImg = drawImg; _captureWithUI = true; _captureSavePath = Application.dataPath; _defaultCaptureType = CaptureType.FreeRegion; //_paintCanvasImg = GameObject.FindObjectOfType().transform.Find("paintCanvasImg").GetComponent(); _screenWidth = Screen.width; _screenHeight = Screen.height; _paintBrushShader = Resources.Load("Shaders/PaintBrush"); _paintBrushMat = new Material(_paintBrushShader); _clearBrushShader = Resources.Load("Shaders/ClearBrush"); _clearBrushMat = new Material(_clearBrushShader); _eraserBrushShader = Resources.Load("Shaders/EraserBrush"); _eraserBrushMat = new Material(_eraserBrushShader); _defaultBrushRawImage = Resources.Load("brush-1"); //初始化刷子 _paintBrushMat.SetTexture("_BrushTex", _defaultBrushRawImage); _paintBrushMat.SetColor("_Color", _defaultColor); _brushSize = PaintingParams.BrushDefaultSize; _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / _brushSize; _paintBrushMat.SetFloat("_Size", _brushSize); _paintBrushMat.SetFloat("_SizeY", _brushSize * (float)_screenHeight / (float)_screenWidth); _eraserSize = PaintingParams.EraserDefaultSize; _eraserBrushMat.SetTexture("_BrushTex", _defaultBrushRawImage); _eraserBrushMat.SetColor("_Color", new Color(0f, 0f, 0f, 0f)); _eraserBrushMat.SetFloat("_Size", _eraserSize); _eraserBrushMat.SetFloat("_SizeY", _eraserSize * (float)_screenHeight / (float)_screenWidth); _currentRenderTexture = RenderTexture.GetTemporary(_screenWidth, _screenHeight, 24); _paintCanvasImg.texture = _currentRenderTexture; // 激活渲染纹理,确保它可以被写入 RenderTexture.active = _currentRenderTexture; GL.Clear(true, true, Color.clear); //给画布添加事件 var paintEventTrigger = _paintCanvasImg.GetOrAddComponent(); paintEventTrigger.triggers = new List(); EventTrigger.Entry dragEntry = new EventTrigger.Entry(); dragEntry.eventID = EventTriggerType.Drag; dragEntry.callback.AddListener(PaintDragging); EventTrigger.Entry endDragEntry = new EventTrigger.Entry(); endDragEntry.eventID = EventTriggerType.EndDrag; endDragEntry.callback.AddListener(OnPaintEndDrag); paintEventTrigger.triggers.Add(dragEntry); paintEventTrigger.triggers.Add(endDragEntry); EventTrigger.Entry beginDrawEntry = new EventTrigger.Entry(); beginDrawEntry.eventID = EventTriggerType.BeginDrag; beginDrawEntry.callback.AddListener(OnPaintBeginDrag); //paintEventTrigger.triggers.Add(dragEntry); paintEventTrigger.triggers.Add(beginDrawEntry); // 使用 Graphics.Blit 清除渲染纹理 Graphics.Blit(null, _currentRenderTexture, _clearBrushMat); // 恢复默认的渲染纹理 RenderTexture.active = null; } } void Update() { if (_enabled) { switch (_defaultCaptureType) { case CaptureType.FullScreen: break; case CaptureType.FreeRegion: //已经选了区域,可以开始涂鸦了 if (_haveRegion) { //如果按下右键,表示重新选择区域,清除掉之前的记录 if (Input.GetMouseButtonUp(1)) { _defaultCaptureType = CaptureType.FreeRegion; _haveRegion = false; _haveCirmformRectStarPoint = false; _startPoint = Vector2.zero; _endPoint = Vector2.zero; _drawRegionRect = false; _leftUpConnerPoint = Vector2.zero; _leftDownConnerPoint = Vector2.zero; _rightUpConnerPoint = Vector2.zero; _rightDownConnerPoint = Vector2.zero; _currentRenderTexture.Release(); _bgRawImage.material.SetVector("_Rect", new Vector4(0, 0, 0, 0)); _eraserFlag = false; //Graphics.Blit(_blitRenderTexture, _blitRenderTexture, _clearBrushMat); //清除一下 CannelRegionEvent.Invoke(); return; } //涂鸦的侦听逻辑 } //未选择区域,要先选区域 else { //switch (_defaultCaptureType) //{ // case CaptureType.FullScreen: // break; // case CaptureType.FreeRegion: // //如果没有点下选择起点 if (!_haveCirmformRectStarPoint) { if (Input.GetMouseButtonDown(0)) { //超出屏幕外 if (Input.mousePosition.x < 0 || Input.mousePosition.x > Screen.width || Input.mousePosition.y < 0 || Input.mousePosition.y > Screen.height) { return; } _startPoint = Input.mousePosition; _haveCirmformRectStarPoint = true; } } //如果选下了起点,刷新鼠标位置 else { _drawRegionRect = true; if (Input.GetMouseButton(0)) { _endPoint = Input.mousePosition; //限制坐标在屏幕内 _endPoint.x = Mathf.Clamp(_endPoint.x, 0f, Screen.width); _endPoint.y = Mathf.Clamp(_endPoint.y, 0f, Screen.height); //设置灰化区域 Vector4 rect = new Vector4(Mathf.Min(_startPoint.x, _endPoint.x) / Screen.width, Mathf.Min(_startPoint.y, _endPoint.y) / Screen.height, Mathf.Max(_startPoint.x, _endPoint.x) / Screen.width, Mathf.Max(_startPoint.y, _endPoint.y) / Screen.height); _bgRawImage.material.SetVector("_Rect", rect); } //鼠标抬起,截图框选区域确定 if (Input.GetMouseButtonUp(0)) { _endPoint = Input.mousePosition; //限制坐标在屏幕内 _endPoint.x = Mathf.Clamp(_endPoint.x, 0f, Screen.width); _endPoint.y = Mathf.Clamp(_endPoint.y, 0f, Screen.height); _haveRegion = true; _leftUpConnerPoint = GetCaptureViewLeftUpConnerPoint(); _rightUpConnerPoint = GetCaptureViewRightUpConnerPoint(); _rightDownConnerPoint = GetCaptureViewRightDownConnerPoint(); _leftDownConnerPoint = GetCaptureViewLeftDownConnerPoint(); FinishedRegionEvent.Invoke(); } } // break; // default: // throw new ArgumentOutOfRangeException(); //} } ////侦听截图事件 //if (Input.GetKeyUp(KeyCode.Space)) //{ // _CaptureFlag = true; //} //全屏截图 if (Input.GetKeyUp(KeyCode.F) && _defaultCaptureType == CaptureType.FreeRegion && !_haveRegion) { _defaultCaptureType = CaptureType.FullScreen; _leftDownConnerPoint = Vector2.zero; _leftUpConnerPoint = new Vector2(0, _screenHeight); _rightUpConnerPoint = new Vector2(_screenWidth, _screenHeight); _rightDownConnerPoint = new Vector2(_screenWidth, 0); _drawRegionRect = true; _haveCirmformRectStarPoint = true; _haveRegion = true; _bgRawImage.gameObject.SetActive(false); _bgRawImage.material.SetVector("_Rect", new Vector4(0, 0, 1, 1)); //涂鸦选项UI初始化 FinishedRegionEvent.Invoke(); } break; default: break; } _eraserModeUpdateEvent.Invoke(_eraserFlag); //退出截图 if (Input.GetKeyUp(KeyCode.Escape)) { ResetData(); _enabled = false; _escapeCaptureEvent.Invoke(); return; } } } void OnPostRender() { if (!enabled) return; if (_drawRegionRect) { //如果材质球不存在 if (!_lineMaterial) { //实例一个材质球 Shader shader = Shader.Find("Hidden/Internal-Colored"); _lineMaterial = new Material(shader); _lineMaterial.hideFlags = HideFlags.HideAndDontSave; //设置参数 _lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); _lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); //设置参数 _lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off); //设置参数 _lineMaterial.SetInt("_ZWrite", 0); } GL.PushMatrix();//保存摄像机变换矩阵,把投影视图矩阵和模型视图矩阵压入堆栈保 GL.LoadPixelMatrix();//设置用屏幕坐标绘图 _lineMaterial.SetPass(0); GL.Begin(GL.LINES); GL.Color(_rectColor); switch (_defaultCaptureType) { case CaptureType.FullScreen: GL.Vertex3(_leftUpConnerPoint.x, _leftUpConnerPoint.y, 0); GL.Vertex3(_rightUpConnerPoint.x, _rightUpConnerPoint.y, 0); GL.Vertex3(_rightUpConnerPoint.x, _rightUpConnerPoint.y, 0); GL.Vertex3(_rightDownConnerPoint.x, _rightDownConnerPoint.y, 0); GL.Vertex3(_rightDownConnerPoint.x, _rightDownConnerPoint.y, 0); GL.Vertex3(_leftDownConnerPoint.x, _leftDownConnerPoint.y, 0); GL.Vertex3(_leftDownConnerPoint.x, _leftDownConnerPoint.y, 0); GL.Vertex3(_leftUpConnerPoint.x, _leftUpConnerPoint.y, 0); break; case CaptureType.FreeRegion: GL.Vertex3(_startPoint.x, _startPoint.y, 0); GL.Vertex3(_endPoint.x, _startPoint.y, 0); GL.Vertex3(_endPoint.x, _startPoint.y, 0); GL.Vertex3(_endPoint.x, _endPoint.y, 0); GL.Vertex3(_endPoint.x, _endPoint.y, 0); GL.Vertex3(_startPoint.x, _endPoint.y, 0); GL.Vertex3(_startPoint.x, _endPoint.y, 0); GL.Vertex3(_startPoint.x, _startPoint.y, 0); break; default: throw new ArgumentOutOfRangeException(); } GL.End(); GL.PopMatrix();//恢复摄像机投影矩阵 } //截图 if (_captureFlag && !_captureWithUI && _haveRegion) { _drawRegionRect = false; float width = _rightUpConnerPoint.x - _leftDownConnerPoint.x; float height = _rightUpConnerPoint.y - _leftDownConnerPoint.y; Rect rect = new Rect(_leftDownConnerPoint.x, Screen.height - _leftUpConnerPoint.y, width, height); Texture2D tex1 = new Texture2D((int)width, (int)height, TextureFormat.RGB24, false); //Read the pixels in the Rect starting at 0,0 and ending at the screen's width and height tex1.ReadPixels(rect, 0, 0, false); tex1.Apply(); //Check that the display field has been assigned in the Inspector #if UNITY_EDITOR byte[] tex1bytes = tex1.EncodeToPNG(); string tex1path = _captureSavePath + "/RenderTextureActive.png"; System.IO.File.WriteAllBytes(tex1path, tex1bytes); Debug.Log(string.Format("截屏了一张照片: {0}", tex1path)); #endif //Texture2D CombineTex = new Texture2D(_renderTex.width, _renderTex.height, TextureFormat.ARGB32, false); RenderTexture prev = RenderTexture.active; RenderTexture.active = _currentRenderTexture; Texture2D BliTexture2D = new Texture2D((int)width, (int)height, TextureFormat.ARGB32, false); BliTexture2D.ReadPixels(rect, 0, 0); #if UNITY_EDITOR byte[] bytes = BliTexture2D.EncodeToPNG(); string path = _captureSavePath + "/BlitTexture.png"; string filename = path; System.IO.File.WriteAllBytes(filename, bytes); Debug.Log(string.Format("截屏了一张照片: {0}", filename)); #endif RenderTexture.active = null; Texture2D combineTexture2D = MergeImage(tex1, BliTexture2D); byte[] combineTexture2DbBytes = combineTexture2D.EncodeToPNG(); string str = DateTime.Now.ToString("hh_mm_ss"); string fileName = DateTime.Now.ToString("yyyy_MM_dd") + "_" + str + ".png"; string path2 = _captureSavePath + "/" + fileName; System.IO.File.WriteAllBytes(path2, combineTexture2DbBytes); Debug.Log(string.Format("截屏了一张照片: {0}", path2)); _captureFlag = false; //重置数据 ResetData(); _finishedCapture.Invoke(); } //UI也截取 if (_captureFlag && _captureWithUI && _haveRegion) { StartCoroutine(StartCapture()); } } #endregion #region private function #region 涂鸦相关方法 public void SetStatus(Status status) { this.status = status; ChangeToEraser(this.status == Status.Eraser); } private void OnPaintBeginDrag(BaseEventData arg0) { if (_enabled && _haveRegion) { switch (status) { case Status.Pen: break; case Status.Line: if (Input.GetMouseButton(0)) { if (_currentLine == null) { _currentLine = new LineSegment(_paintBrushMat.GetColor("_Color"), _brushSize, _eraserFlag); } LerpPaint(Input.mousePosition, _eraserFlag); } break; case Status.Circle: _currentLine = new LineSegment(_paintBrushMat.GetColor("_Color"), _brushSize, _eraserFlag); _lastPoint = Input.mousePosition; circleImg.gameObject.SetActive(true); // TODO: 这样会使UI位置有偏差 后续修改 circleImg.transform.position = Input.mousePosition; break; case Status.Rect: _currentLine = new LineSegment(_paintBrushMat.GetColor("_Color"), _brushSize, _eraserFlag); _lastPoint = Input.mousePosition; //rectImg.gameObject.SetActive(true); // TODO: 这样会使UI位置有偏差 后续修改 //rectImg.transform.position = Input.mousePosition; isRect = true; break; } } } private void PaintDragging(BaseEventData data) { if (_enabled && _haveRegion) { if (Input.GetMouseButton(0) && Time.time - _lastPaintTime > _paintInterval) { _lastPaintTime = Time.time; // 绘制逻辑 if (Input.GetMouseButton(0)) { switch (status) { case Status.Pen: case Status.Eraser: if (_currentLine == null) { _currentLine = new LineSegment(_paintBrushMat.GetColor("_Color"), _brushSize, _eraserFlag); } LerpPaint(Input.mousePosition, _eraserFlag); break; case Status.Rect: break; case Status.Circle: var dis = Vector2.Distance(_lastPoint, Input.mousePosition) * 2; circleImg.rectTransform.sizeDelta = new Vector2(dis, dis); break; } } } } } private void OnPaintEndDrag(BaseEventData data) { if (_enabled && _haveRegion) { switch (status) { case Status.Pen: case Status.Eraser: if (Input.GetMouseButtonUp(0)) { FinishedRaw(); } break; case Status.Line: if (_currentLine != null) { LerpPaint(Input.mousePosition, false); FinishedRaw(); } break; case Status.Rect: isRect = false; RectFactory(); break; case Status.Circle: if (_currentLine != null) { float radius = Vector2.Distance(_lastPoint, Input.mousePosition); var points = GenerateCirclePoints(_lastPoint, radius); _lastPoint = default; foreach (var item in points) { LerpPaint(item, false); } LerpPaint(points[0], false); FinishedRaw(); circleImg.gameObject.SetActive(false); } break; default: break; } } } public void FinishedRaw() { if (_currentLine != null) { // 保存当前纹理到 LineSegment RenderTexture.active = _currentLine.Texture; Graphics.Blit(_currentRenderTexture, _currentLine.Texture); RenderTexture.active = null; _lineStack.Push(_currentLine); _currentLine = null; } _lastPoint = Vector2.zero; } bool isRect = false; private void OnGUI() { if (isRect) { var points = GenerateRectanglePoints(_lastPoint, Input.mousePosition); float minX = float.MaxValue; float minY = float.MaxValue; float maxX = float.MinValue; float maxY = float.MinValue; // 找出最小和最大的 x、y 坐标 foreach (Vector2 point in points) { if (point.x < minX) { minX = point.x; } if (point.x > maxX) { maxX = point.x; } if (point.y < minY) { minY = point.y; } if (point.y > maxY) { maxY = point.y; } } float x = minX; float y = maxY; float width = maxX - minX; float height = maxY - minY; Rect rect = new Rect(x, y, width, height); GUI.backgroundColor = Color.blue; GUI.color = Color.yellow; GUI.Box(rect, "我帮你绘制了个 Rect Box"); } } List GenerateCirclePoints(Vector2 center, float r, int numPoints = 36) { List points = new List(); for (int i = 0; i < numPoints; i++) { // 计算每个点的角度 float angle = 2 * Mathf.PI * i / numPoints; // 根据三角函数计算点的坐标 float x = center.x + r * Mathf.Cos(angle); float y = center.y + r * Mathf.Sin(angle); points.Add(new Vector2(x, y)); } return points; } public void RectFactory() { if (_lastPoint != default) { var points = GenerateRectanglePoints(_lastPoint, Input.mousePosition); LerpPaint(points[0], false); LerpPaint(points[1], false); LerpPaint(points[2], false); LerpPaint(points[3], false); LerpPaint(points[0], false); FinishedRaw(); } } public Vector2[] GenerateRectanglePoints(Vector2 start, Vector2 thirdPoint) { Vector2[] points = new Vector2[4]; points[0] = start; // 原本的 end 点(这里用 thirdPoint 替代)作为数组的第三个元素 points[2] = thirdPoint; if (start.x < thirdPoint.x) { if (start.y < thirdPoint.y) { // 从左下方到右上方 points[1] = new Vector2(thirdPoint.x, start.y); points[3] = new Vector2(start.x, thirdPoint.y); } else { // 从左上方到右下方 points[1] = new Vector2(thirdPoint.x, start.y); points[3] = new Vector2(start.x, thirdPoint.y); } } else { if (start.y < thirdPoint.y) { // 从右下方到左上方 points[1] = new Vector2(start.x, thirdPoint.y); points[3] = new Vector2(thirdPoint.x, start.y); } else { // 从右上方到左下方 points[1] = new Vector2(start.x, thirdPoint.y); points[3] = new Vector2(thirdPoint.x, start.y); } } return points; } public void Clear() { // 重新分配 RenderTexture _currentRenderTexture = RenderTexture.GetTemporary(_screenWidth, _screenHeight, 24); // 更新画布的纹理 _paintCanvasImg.texture = _currentRenderTexture; // 清空线条栈 _lineStack.Clear(); } public void Undo() { if (_lineStack.Count > 0) { // 移除最后一条线 var line = _lineStack.Pop(); // 如果栈中还有剩余的线条,切换到上一个线条的纹理 if (_lineStack.Count > 0) { var previousLine = _lineStack.Peek(); //RenderTexture.active = _currentRenderTexture; //Graphics.Blit(previousLine.Texture, _currentRenderTexture); //RenderTexture.active = null; _currentRenderTexture = previousLine.Texture; _paintCanvasImg.texture = previousLine.Texture; } else { Clear(); } } } /// /// 绘画进行插值 /// /// Vector2[] vector2s = new Vector2[10000]; private void LerpPaint(Vector2 point, bool isEraser) { Paint(isEraser, point); if (_lastPoint == Vector2.zero) { _lastPoint = point; return; } float dis = Vector2.Distance(point, _lastPoint); if (dis > _brushLerpSize) { Vector2 dir = (point - _lastPoint).normalized; int num = (int)(dis / (_brushLerpSize)); for (int i = 0; i < num; i++) { vector2s[i] = _lastPoint + dir * (i + 1) * _brushLerpSize; Paint(isEraser, vector2s[i]); } } _lastPoint = point; } // 画点方法 private void Paint(bool isEraser, Vector2 point) { Material material = null; if (point.x < _leftDownConnerPoint.x || point.x > _rightUpConnerPoint.x || point.y < _leftDownConnerPoint.y || point.y > _rightUpConnerPoint.y) return; Vector2 uv = new Vector2(point.x / (float)_screenWidth, point.y / (float)_screenHeight); if (isEraser) { _eraserBrushMat.SetVector("_UV", uv); material = _eraserBrushMat; } else { _paintBrushMat.SetVector("_UV", uv); material = _paintBrushMat; } _commandBuffer.Blit(_currentRenderTexture, _currentRenderTexture, material); Graphics.ExecuteCommandBuffer(_commandBuffer); _commandBuffer.Clear(); } public Vector2 GetCaptureViewLeftDownConnerPoint() { Vector2 vec = new Vector2(Mathf.Min(_startPoint.x, _endPoint.x), Mathf.Min(_startPoint.y, _endPoint.y)); return vec; } public Vector2 GetCaptureViewRightUpConnerPoint() { Vector2 vec = new Vector2(Mathf.Max(_startPoint.x, _endPoint.x), Mathf.Max(_startPoint.y, _endPoint.y)); return vec; } public Vector2 GetCaptureViewLeftUpConnerPoint() { Vector2 vec = new Vector2(Mathf.Min(_startPoint.x, _endPoint.x), Mathf.Max(_startPoint.y, _endPoint.y)); return vec; } public Vector2 GetCaptureViewRightDownConnerPoint() { Vector2 vec = new Vector2(Mathf.Max(_startPoint.x, _endPoint.x), Mathf.Min(_startPoint.y, _endPoint.y)); return vec; } #endregion /// /// 合成图片 /// private Texture2D MergeImage(Texture2D tex1, Texture2D tex2) { for (int i = 0; i < tex1.width; i++) { for (int j = 0; j < tex1.height; j++) { Color color1 = tex1.GetPixel(i, j); Color color2 = tex2.GetPixel(i, j); Color newColor = color2.a * color2 + (1.0f - color2.a) * color1; newColor.a = 1f; tex1.SetPixel(i, j, newColor); } } return tex1; } IEnumerator StartCapture() { yield return new WaitForEndOfFrame(); float width = _rightUpConnerPoint.x - _leftDownConnerPoint.x; float height = _rightUpConnerPoint.y - _leftDownConnerPoint.y; Debug.Log(_leftDownConnerPoint.x.ToString("0.00")); Debug.Log(_leftDownConnerPoint.y.ToString("0.00")); Debug.Log("width:" + width); Debug.Log("width:" + height); Rect rect = new Rect(_leftDownConnerPoint.x, _leftDownConnerPoint.y, width, height); //坑爹啊 如果是开携程在WaitForEndOfFrame时候截图,那么他的坐标系换了。。rect起始点要设置在左下角 Texture2D tex1 = new Texture2D((int)width, (int)height, TextureFormat.RGB24, false); //Read the pixels in the Rect starting at 0,0 and ending at the screen's width and height tex1.ReadPixels(rect, 0, 0, false); tex1.Apply(); //Check that the display field has been assigned in the Inspector byte[] tex1bytes = tex1.EncodeToPNG(); string str = DateTime.Now.ToString("hh_mm_ss"); string fileName = DateTime.Now.ToString("yyyy_MM_dd") + "_" + str + ".png"; string tex1path = _captureSavePath + "/" + fileName; System.IO.File.WriteAllBytes(tex1path, tex1bytes); Debug.Log(string.Format("截屏了一张照片(有UI): {0}", tex1path)); _captureFlag = false; ResetData(); //推出截屏 EscapeCaptureEvent.Invoke(); } /// /// 截图完成后重置数据 /// private void ResetData() { _defaultCaptureType = CaptureType.FreeRegion; _drawRegionRect = false; _haveRegion = false; _haveCirmformRectStarPoint = false; _currentRenderTexture.Release(); _startPoint = Vector2.zero; _endPoint = Vector2.zero; _leftUpConnerPoint = Vector2.zero; _leftDownConnerPoint = Vector2.zero; _rightDownConnerPoint = Vector2.zero; _rightUpConnerPoint = Vector2.zero; _lastPoint = Vector2.zero; _bgRawImage.material.SetVector("_Rect", new Vector4(0, 0, 1, 1)); _bgRawImage.gameObject.SetActive(false); _paintCanvasImg.gameObject.SetActive(false); _eraserFlag = false; _enabled = false; } #endregion #region public function /// /// 进入截图模式 /// public void SwitchOn(bool isFullScreen) { if (isFullScreen) { _defaultCaptureType = CaptureType.FullScreen; _bgRawImage.gameObject.SetActive(false); _bgRawImage.material.SetVector("_Rect", new Vector4(0, 0, 1, 1)); _leftDownConnerPoint = Vector2.zero; _leftUpConnerPoint = new Vector2(0, _screenHeight); _rightUpConnerPoint = new Vector2(_screenWidth, _screenHeight); _rightDownConnerPoint = new Vector2(_screenWidth, 0); _drawRegionRect = true; _haveCirmformRectStarPoint = true; _haveRegion = true; _lastPoint = Vector2.zero; //涂鸦选项UI初始化 FinishedRegionEvent.Invoke(); } else { _defaultCaptureType = CaptureType.FreeRegion; _bgRawImage.gameObject.SetActive(true); _bgRawImage.material.SetVector("_Rect", new Vector4(0, 0, 0, 0)); } _paintCanvasImg.gameObject.SetActive(true); _enterCaptureModeEvent.Invoke(); _enabled = true; } public void SaveCapture() { _captureFlag = true; } public void SetPaintColor(Color color) { _paintBrushMat.SetColor("_Color", color); } public void SetPaintingSize(float size) { _paintBrushMat.SetFloat("_Size", size); _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / size; _eraserBrushMat.SetFloat("_Size", size); _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / size; } public void SetPaintingSize(float sizeX, float sizeY) { _paintBrushMat.SetFloat("_Size", sizeX); _paintBrushMat.SetFloat("_SizeY", sizeY); if (sizeX > sizeY) _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / sizeX; if (sizeX <= sizeY) _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / sizeY; } public void SetEraserSize(float sizeX, float sizeY) { if (sizeX > sizeY) _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / sizeX; if (sizeX <= sizeY) _brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / sizeY; _eraserBrushMat.SetFloat("_Size", sizeX); _eraserBrushMat.SetFloat("_SizeY", sizeY); //_brushLerpSize = (_defaultBrushRawImage.width + _defaultBrushRawImage.height) / 2.0f / size; } public void ChangeToEraser(bool toEraser) { _eraserFlag = toEraser; } #endregion } public class FinishedRegionEvent : UnityEvent { } public class CannelRegionEvent : UnityEvent { } public class FinishedCaptureEvent : UnityEvent { } public class EscapeCaptureEvent : UnityEvent { } public class EnterCaptureModeEvent : UnityEvent { } public class EraserModeUpdateEvent : UnityEvent { } public enum CaptureType { /// /// 自动全屏截屏 /// FullScreen, /// /// 自由框选截屏 /// FreeRegion } /// /// 笔刷橡皮擦计算参数 ,计算公式,比如笔刷的是【缩放倍数=BrushSizeMaxValue +(1-slider.value)*BrushSizeFactor】,橡皮擦类似 /// public static class PaintingParams { /// /// 缩小因子,越大说明可调节范围越大 /// public static float BrushSizeFactor = 300f; /// /// 笔刷图片最大缩小倍数(画布大小的笔刷图案要缩小多少倍数显示,缩小的越小,笔刷显示效果越大) /// public static float BrushSizeMaxValue = 50; public static float EraserSizeFactor = 50; public static float EraserSizeMaxValue = 50; public static float BrushDefaultSize = 300; public static float EraserDefaultSize = 100; }