Unity截图调用OpenGL绘制 | 您所在的位置:网站首页 › unity调用opengl › Unity截图调用OpenGL绘制 |
这次研究的是一个屏幕截取并保存的功能。先上图。 1.Ctrl + Alt + X 开始截图。 2.Enter键执行截屏并弹出保存框。 3.截取后保存的图片。 大致的思路是这样: 1.GL类执行界面选框的显示。 2.用Texture2D类设置新的像素块颜色。 3.System.Windows.forms.dll弹出保存对话框,保存图片文件并打开。 难点在于GL框的绘制逻辑以及新的图片生成时屏幕坐标的计算。 代码如下: ScreenShot类 using UnityEngine; using System.Collections; using System.Windows.Forms; using System.IO; using System.Text; //截屏工具 public class ScreenShot : MonoBehaviour { //选框材质 public Material mat; //初始位置 Vector3 startPos = Vector3.zero; //结束位置 Vector3 endPos = Vector3.zero; //是否绘制 bool isDraw = false; //是否清除 bool isClear = true; void Update () { //左键按下开始绘制 if(Input.GetMouseButtonDown(0)) { isDraw = true; isClear = true; startPos = Input.mousePosition; } //左键松开GL框悬停 if(Input.GetMouseButtonUp(0)) { //鼠标原位置点击不做GL绘制 if(endPos == startPos) { isDraw = false; } isClear = false; } //右键按下重新绘制 if(Input.GetMouseButtonDown(1)) { isDraw = false; enabled = false; } //Enter键按下执行截屏 if(Input.GetKeyDown(KeyCode.Return) && isDraw && !isClear) { isDraw = false; StartCoroutine(DoScreenShot(new Vector2(startPos.x,UnityEngine.Screen.height - startPos.y),new Vector2(endPos.x,UnityEngine.Screen.height - endPos.y))); enabled = false; } } void OnGUI () { //文本提示 if(!isDraw) { GUI.Label(new Rect(Input.mousePosition.x,UnityEngine.Screen.height - Input.mousePosition.y,100,100)," 请框选截图范围"); } if(isDraw && !isClear && endPos != startPos) { GUI.Label(new Rect(Input.mousePosition.x,UnityEngine.Screen.height - Input.mousePosition.y,100,100)," 按下Enter键截屏"); } } void OnPostRender () { //绘制GL线框 if(!isDraw)return; if(isClear) endPos = Input.mousePosition; GL.PushMatrix(); if(!mat)return; mat.SetPass(0); GL.LoadPixelMatrix(); //绘制GL填充面 GL.Begin(GL.QUADS); GL.Color(new Color(Color.yellow.r,Color.yellow.g,Color.yellow.b,0.1f)); GL.Vertex3(startPos.x,startPos.y,0); GL.Vertex3(endPos.x,startPos.y,0); GL.Vertex3(endPos.x,endPos.y,0); GL.Vertex3(startPos.x,endPos.y,0); GL.End(); //绘制GL边框线 GL.Begin(GL.LINES); GL.Color(Color.red); GL.Vertex3(startPos.x,startPos.y,0); GL.Vertex3(endPos.x,startPos.y,0); GL.Vertex3(endPos.x,startPos.y,0); GL.Vertex3(endPos.x,endPos.y,0); GL.Vertex3(endPos.x,endPos.y,0); GL.Vertex3(startPos.x,endPos.y,0); GL.Vertex3(startPos.x,endPos.y,0); GL.Vertex3(startPos.x,startPos.y,0); GL.End(); GL.PopMatrix(); } //截屏 IEnumerator DoScreenShot (Vector2 startPos,Vector2 endPos) { Debug.Log(new Rect(startPos.x < endPos.x ? startPos.x : endPos.x,startPos.y < endPos.y ? UnityEngine.Screen.height - endPos.y : UnityEngine.Screen.height - startPos.y,Mathf.Abs(endPos.x - startPos.x - 2),Mathf.Abs(endPos.y - startPos.y - 2))); yield return new WaitForSeconds(1); Texture2D tex = new Texture2D((int)Mathf.Abs(endPos.x - startPos.x - 2),(int)Mathf.Abs(endPos.y - startPos.y - 2),TextureFormat.RGB24,false); tex.ReadPixels (new Rect(startPos.x < endPos.x ? startPos.x : endPos.x,startPos.y < endPos.y ? UnityEngine.Screen.height - endPos.y : UnityEngine.Screen.height - startPos.y,Mathf.Abs(endPos.x - startPos.x - 2),Mathf.Abs(endPos.y - startPos.y - 2)),0,0); tex.Apply(); Destroy(tex); SaveScreenShot(tex); } //保存文件 void SaveScreenShot (Texture2D tex) { //先将文件保存在工程目录下(其实可以不用这么做) byte[] bytes = tex.EncodeToPNG(); string filename = System.DateTime.Now.Year.ToString("0000") + System.DateTime.Now.Month.ToString("00") + System.DateTime.Now.Day.ToString("00") + System.DateTime.Now.Hour.ToString("00") + System.DateTime.Now.Minute.ToString("00") + System.DateTime.Now.Second.ToString("00") + Random.Range(0,9999).ToString("0000"); string oldFilePath = UnityEngine.Application.dataPath + "/" + filename + ".png"; FileStream f =new FileStream(oldFilePath,FileMode.Create); f.Write(bytes,0,bytes.Length); f.Flush(); f.Close(); System.GC.Collect(); Resources.UnloadUnusedAssets(); //弹出文件保存对话框,调用的是WINDOWS的DLL. SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "png|*.png"; string newFilePath = ""; if (dialog.ShowDialog() == DialogResult.OK) { newFilePath = dialog.FileName; } if(newFilePath != "") { if(File.Exists(newFilePath)) { File.Delete(newFilePath); } File.Move(oldFilePath, newFilePath); UnityEngine.Application.OpenURL(newFilePath); } else { File.Delete(oldFilePath); } } }
ScreenShotControl类 using UnityEngine; using System.Collections; //截屏控制 public class ScreenShotControl : MonoBehaviour { ScreenShot screenshot; // Use this for initialization void Start () { screenshot = GetComponent(); } // Update is called once per frame void Update () { } void OnGUI () { //Ctrl + Alt + X 执行截屏 if(Event.current.Equals(Event.KeyboardEvent("^&X"))) { screenshot.enabled = true; } } }阐述几个开发中的问题: 1.调用Windows的DLL,需要在Unity里更改一下设置。 File -> Build Settings -> Player Settings ->Other Settings -> Optimization -> Api Compatibility Level 更改为 .NET 2.0。 2.在执行完截屏操作后,虽然能够成功生成图片,但是会报一个错。 ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame. 如果有高手知道具体的解决办法,请指教一下。 3.程序的代码结构写的不是太好,请高手指正。 |
CopyRight 2018-2019 实验室设备网 版权所有 |