2018-07-23 14:46:26 nicepainkiller 阅读数 3252
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

Unity3D 截图功能(1屏幕区域截图,2两张图片的合成)

先看效果 1.

看图 我想把图片 区域 的位置截图出来,

效果 2

看图,他二维码图片 放在 Texture2D 目标区域

现在我们来实行相关功能!

效果1:

       /// <summary>
        /// 传入一个 RectTransform 区域!, 就不把资格区域的图像保存下来
        /// </summary>
        /// <param name="rect"></param>
        public void OnShowTexture(RectTransform rect)
        {

            ///要现实的位置 RrctTransform, 转化到屏幕坐标。
            Vector3 vect                 = RectTransformUtility.WorldToScreenPoint(Camera.main, rect.gameObject.transform.position);
            Canvas canvas                = GameObject.Find("Canvas").GetComponent<Canvas>();
            CanvasScaler    canvasScaler = canvas.GetComponent<CanvasScaler>();

            float radio                  = Screen.width / canvasScaler.referenceResolution.x;//适配
            float x = vect.x - rect.sizeDelta.x * rect.pivot.x * radio;
            float y = vect.y - rect.sizeDelta.y * rect.pivot.x * radio;

  
            targetRect      = new Rect(x, y, rect.sizeDelta.x * radio, rect.sizeDelta.y * radio);



            Debug.Log(string.Format("x:{0}, y:{1}, width:{2}, height:{3}", targetRect.x, targetRect.y, targetRect.width, targetRect.height));

            StartCoroutine(UploadPNG());

        }

        IEnumerator UploadPNG()
        {

            yield return new WaitForEndOfFrame();
            Texture2D tex = new Texture2D((int)targetRect.width, (int)targetRect.height, TextureFormat.RGB24, false);

            tex.ReadPixels(new Rect((int)targetRect.x, (int)targetRect.y, (int)targetRect.width, (int)targetRect.height), 0, 0);
            tex.Apply();
     
            string path = Application.persistentDataPath + "/onMobileSavedScreen.png";
            Debug.Log(path);
            File.WriteAllBytes(path, tex.EncodeToPNG());

        }

 

效果2:

        /// <summary>
        /// 传入两张Texture2D 图片
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        public Texture2D TwoToOne(Texture2D source, Texture2D target)
        {
            ///显示位置
            int startWidth  = source.width  / 2  - target.width / 2;
            int startHeight = 35;
 

            source.SetPixels32(startWidth, startHeight, target.width,target.height, target.GetPixels32());

            source.Apply();
            string path = Application.persistentDataPath + "/1111.png";
            Debug.Log(path);
            File.WriteAllBytes(path, source.EncodeToPNG());

            return source;
        }

以上两种方法, 都可以满足 目前看两种效率 相差不多。应为底层实现差不多!

 

这是两张保存的图片

2015-12-25 15:16:49 HeBiReChenAi 阅读数 1394
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚
最近项目需求截图,于是就全部研究了一下,期间遇到了各种问题,与诸位大神讨论后终于解决了
主要有三种方法:
  • unity自带的全屏截图
  • unity主场景局部区域截图
  • unity针对某个相机看到的区域局部截图

  1. 针对第一种方案的截图很容易

            使用Application.CaptureScreenshot方法,
      第一个参数是文件路径名,第二个参数是截图的大小,默认是0,1代表当前大小的一倍,以此类推

          

  1. unity主场景局部区域截图

          这里遇到两个个坑。
          坑一:坐标转换
          一开始不知道坐标系不一样,发现一些坐标一运行截图方法,unity就崩了,还无从查找问题,后来费了好大一番功夫,发现GUI的rect的坐标系和ReadPixels用的矩形坐标系不一样。如下图所示:
     
          
          下面我们先验证一下这个说法:
          如图使我们场景运行的效果,我们想要截按钮那个地方的图,Rect(0, 0, 200, 200)
          

         
        理想的截图出来应该是左边图样的,实际截出来的图是右边的图样,明显的截了左下角的了:
                         
           于是我写了一个矩形转换坐标的函数:
            
            截图前转换矩形坐标后:
             截出来的图如图,现在就对上了,而且范围超出屏幕范围,unity会崩掉,这里直接容错:
             
             
          
          坑二:相机渲染顺序
          官网的案例是写在OnPostRender中的,然后在相机渲染玩所有它的物体之后被调用,但是在其它相机和GUI被渲染前调用:
           
            结果如图:截图中没有GUI,由于OnPostRender只能挂在摄像机上,你也可以其它地方直接调用截图方法。其它方法类似情况也出现过,比如只有天空盒子,或者只有GUI没有三维模型等等。还会报如下图的错误
             

     解决方案:
             WaitForEndOfFrame,可以把OnPostRender方法改成协同,也可以直接把截图方法改成协同调用

               下面言归正传:
                踩过上面两个坑后,我们就可以正常的截屏幕中的任意矩形了,比如Rect(200, 200, 200, 200),如图:
            
        
  1. unity针对某个相机看到的区域局部截图

          当场景中不止一个相机时,你想要截图某个相机看到的部分区域时,就要使用相机的rendertexture来截图:
          这里的截图和2基本差不多,不过这里不需要做坐标转换,RenderTexture的坐标和GUI的是一样的。
          我的第二个相机只能看到两个球:
          
          运行场景如图:
        
        截图如图所示:
                     原理是此摄像机的renderTexture是全屏的,我们从中截取我们需要的
                    

第三种方案还已遗留了个坑,当第二个摄像机带有天空盒子时,截图只看到天空盒子,大神高手会的帮忙解答下。




               



          
2018-08-17 14:21:43 qq_41203881 阅读数 321
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

      由于工作需要在游戏内截屏,就开始在网上找截图方法,有很多种,我为了自己以后的方便,也顺便再次熟悉一下流程,将自己的流程写出来以供自己以后查阅。

在unity中也有自己的截图方法Application.CaptureScreenshot("图片名+图片格式"); 不过该方法是截取的全屏,存放在工程目录中

好了,我们会到正题,自定义截图。

首先我们需要创建一张图片

Texture2D t = new Texture2D(capwidth, capheight, TextureFormat.RGB24, true);

方法中4个参数分别为图片的  宽 高  图片样式 后面一个目前不清楚不过本人实测不论填写true 还是false都 一样,望知道的指点一二。图片创建完成开始截取图片。

     t.ReadPixels(new Rect(pointx pointy, capwidth, capheight), 0, 0, false);

pointx,pointy为一个坐标,截图区域左下角为原点开始截取,也就是说改坐标点为图片的左下角。

 t.Apply();

设置完成后别忘记调用保存的方法。到此步表示图片已经截取完成了下面开始保存图片到我们的手机上

 //保存图片 判断我们是属于哪个平台

   //将图片转为Png格式或者jpg格式并转为二进制

byte[] byt = t.EncodeToPNG();  EncodeToJPG()

  string fileName ="测试.jpg",mpath ="";
            if (Application.platform == RuntimePlatform.Android)
            {
              //  "安卓平台"  
                string destination = "/sdcard/Pictures";
                //判断目录是否存在,不存在则会创建目录  
                if (!Directory.Exists(destination))
                {
                    Directory.CreateDirectory(destination);
                }
                 mpath = destination + "/" + fileName;
                //报存图片  
                File.WriteAllBytes(mpath, byt);
            }
            else if (Application.platform ==RuntimePlatform.IPhonePlayer)
            {
             //"苹果平台"
                string destination = Application.persistentDataPath;
                if (!Directory.Exists(destination))
                {
                  //"没有文件夹,创建文件夹"
                    Directory.CreateDirectory(destination);
                }
                mpath = destination + "/" + fileName;
                //报存图片  
                File.WriteAllBytes(mpath, byt);
            }
            else
            {
                File.WriteAllBytes(Application.dataPath + fileName, byt);
            }

好了到这一步我们就已经把图片保存在手机上面了但是还没完哦 !只是c#代码写完了接下来我们要通过java代码来刷新一下手机上的资源库 unity和安卓的通信这里就不说了直接上java代码

 public void Refresh(String filePath)
    {
          Log.i("Unity", "------------刷新相册");    
         
          Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
          scanIntent.setData(Uri.fromFile(new java.io.File(filePath)));//
          mActivity.sendBroadcast(scanIntent);  //  
    }

接收自unity中传过来的图片路径  mActivity  为this ,到这一步就表示安卓平台已经完成了 。

接下来看一看 Ios平台 ,说真的ios比安卓就麻烦 一点了

  extern void Refresh_IOS(char *readAddr)
    {
        NSString *strReadAddr = [NSString stringWithUTF8String:readAddr];
        UIImage *img = [UIImage imageWithContentsOfFile:strReadAddr];
        OpenPhotoController *viwe =[OpenPhotoController GetInstance];
        UIImageWriteToSavedPhotosAlbum(img, viwe,
                                       @selector(imageSaved:didFinishSavingWithError:contextInfo:), nil);
    }

接下来需要在info.plist表中添加权限

string AddPhoto=@"<key>NSPhotoLibraryAddUsageDescription</key> <string>XX需要给您添加一张照片</string>";

没有在Xcode中添加这句权限当程序运行到上面那段代码是会强行闪退,我当时在写的时候就踩到这个坑,特意再次声明

到这就保存图片结束了。如有不对的地方请指正!

 

 

 

 

 

 

 

2019-07-18 12:00:35 qq_34662658 阅读数 163
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

错误信息:[d3d11] attempting to ReadPixels outside of RenderTexture bounds! Reading (7000, 340, 8000, 740) from (1920, 1080)

额,还是Texture2D.ReadPixels 参数问题:

纯属手动调试推算,测试无误:

IEnumerator getScreenTexture(RectTransform rectT)
    {
        yield return new WaitForEndOfFrame();
        Texture2D t = new Texture2D((int) rectT.rect.width, (int)rectT.rect.height, TextureFormat.RGB24, true);//需要正确设置好图片保存格式
        float x = rectT.localPosition.x+ (Screen.width - rectT.rect.width )/ 2;
        float y = rectT.localPosition.y + ( Screen.height- rectT.rect.height) / 2;
        Rect position = new Rect(x, y, rectT.rect.width, rectT.rect.height);
        t.ReadPixels(position, 0, 0, true);//按照设定区域读取像素;注意是以左下角为原点读取
        t.Apply();
        //二进制转换
        byte[] byt = t.EncodeToPNG();
        File.WriteAllBytes(Application.dataPath + Time.time + ".png", byt);
        Debug.Log(Application.dataPath + Time.time + ".png");
        System.Diagnostics.Process.Start(Application.dataPath + Time.time + ".png");
    }

 

2015-11-21 11:55:56 honey199396 阅读数 1173
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

大家都知道unity有一个截屏方法,调用Application.CaptureScreenshot("Screenshot.png")方法就可以截取一张图保存到Application.persistentDataPath + "/Screenshot.png",  但是如果你只是想截取屏幕固定部分的内容怎么办呢,而且那个固定部分还是使用程序动态算出来的,这个时候使用全屏截取就会有错误了。

Unity是可以实现截取固定位置屏幕的。

首先在UI下面建立一个面板,


基于父对象中心对齐,然后长宽自由设定,

在父对象中声明一个public RectTransform BackGround 变量,然后将上面设置的面板关联到BackGround。


程序运行是ShareUI设置面板大小

m_Height = Screen.height;
        m_Width = m_Height * m_Height / Screen.width;
        BackGround.sizeDelta = new Vector2 (m_Width, m_Height);

这个可以随意设置。

然后开始截屏了。下面是代码:

Rect m_Rect;

void Start()
{
        m_Height = Screen.height;
        m_Width = m_Height * m_Height / Screen.width;
        BackGround.sizeDelta = new Vector2 (m_Width, m_Height);
        m_Rect= new Rect();
        Vector3[] fourCornersArray = new Vector3[4];

        BackGround.GetWorldCorners (fourCornersArray);

        m_Rect.width = fourCornersArray [2].x - fourCornersArray [0].x;
        m_Rect.height = fourCornersArray [2].y - fourCornersArray [0].y;
        m_Scale = BackGround.sizeDelta.x / m_Rect.width;
        m_Rect.width = BackGround.sizeDelta.x;
        m_Rect.height = BackGround.sizeDelta.y;
        m_Rect.x = Screen.width * 0.5f - m_Rect.width / 2;
        m_Rect.y = Screen.height * 0.5f - m_Rect.height / 2;
}

IEnumerator Screenshot()
{
        yield return new WaitForEndOfFrame();
        BackGround.localScale = new Vector3 (m_Scale, m_Scale, m_Scale);
        Texture2D screenShot = new Texture2D((int)m_Rect.width, (int)m_Rect.height, TextureFormat.RGB24,false);  
        screenShot.ReadPixels(m_Rect, 0, 0);  
        screenShot.Apply();  
        byte[] bytes = screenShot.EncodeToPNG();  
        string filename = Application.persistentDataPath + "/Screenshot.png";  
        System.IO.File.WriteAllBytes(filename, bytes); 
        Invoke ("Share", 2f);
}

这样在需要截图的时候调用StartCoroutine (Screenshot());同样地就在Application.persistentDataPath + "/Screenshot.png";  路径下保存了一份截屏文件。分享时将这种图片分享就可以了。


——Rocky

没有更多推荐了,返回首页