Andoird太头疼了,尤其有些机器就是屏幕大别的硬件条件都很烂,为了优化渲染效率可以试试安卓的硬件缩放技术,我在真机上已经测试通过,效率确实提升了很多,FPS直线上升。。
原理如下 http://android-developers.blogspot.it/2013/09/using-hardware-scaler-for-performance.html
但是需要拿到Unity android的GLSurfaceView,可是我试过了很多办法就是拿不到它,不过还好Unity 直接提供了方法。
找一个合适的地方调用如下方法即可,这个方法在IOS和Android上都支持,但是经过测试IOS没必要使用,在android上还是很有必要使用的。
Screen.SetResolution(960,640,true);
这样会强制把屏幕的分辨率指定成960X640. 但是你的目标设备的分辨率可能不是3:2的,所以你需要做一个算法,假设搭建界面的时候是960X640,此时运行在1280X760的分辨率上,1280X760 和 960X640 等比换算一下 即可。代码我就不贴了。。。使用如下代码可以取出当前手机的屏幕分辨率,根据算法算一下就行了。
int width = Screen.currentResolution.width;
int height = Screen.currentResolution.height;
还有一点需要注意,经过我的测试发现 横屏游戏时 Android切到后台在返回前台渲染区域变成竖屏了。 所以每次切到前台的时候一定要强制设置一下分辨率。
1 2 3 4 5 6 7 |
void OnApplicationPause(bool paused) { Logger.Print("paused:", paused); if (!paused) { Screen.SetResolution(960,640,true); } } |
还有个问题就是当调用Screen.SetResolution(960,640,true); 紧跟着就打开NGUI界面,可能会造成UI闪烁一下。我想最好可以通过unity的GLSurfaceView在java内层去设置分辨率,但是我不知道怎么取到GLSurfaceView,或者如果有朋友知道请在下面留言告诉我一下。
做一个比较简单的界面, 界面上就写上 “正在加载中..”几个大字,因为背景是黑的闪就闪吧反证我们的策划说能忍。。
1 2 3 4 5 6 |
IEnumerator Start() { Screen.SetResolution(960,640,true); yield return new WaitForSeconds(0.1f); //在下面代码里面在处理设置完分辨率以后的逻辑 } |
可能我上面写 Screen.SetResolution(960,640,true); 可能会误导大家,我举个里例子。开发的时候布的界面是 960X640 ,此时运行在 1280X720上。 那么 修改后的分辨率 就是 Screen.SetResolution(1138,640,true);
因为 1138 = 1280/(720/640)但是你还要去考虑 比 960X640 大的情况 或者 比 960X640小的情况。 总之就是等比例的计算 目标分辨率。如果一个是960 另一个就按比例算, 如果一个是640 另一个也按比例算。
设置分辨率以后不会影响到你的代码原有的任何逻辑,效率确实提升了很多,建议大家最好在android上用一下。嘿嘿。欢迎大家在下面给 @雨松MOMO 留言,大家一起讨论。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
private int scaleWidth =0; private int scaleHeight =0; public void setDesignContentScale() { #if UNITY_ANDROID if(scaleWidth ==0 && scaleHeight ==0) { int width = Screen.currentResolution.width; int height = Screen.currentResolution.height; int designWidth = 960; int designHeight = 640; float s1 = (float)designWidth / (float)designHeight; float s2 = (float)width / (float)height; if(s1 < s2) { designWidth = (int)Mathf.FloorToInt(designHeight * s2); } else if(s1 > s2) { designHeight = (int)Mathf.FloorToInt(designWidth / s2); } float contentScale = (float)designWidth/(float)width; if(contentScale < 1.0f) { scaleWidth = designWidth; scaleHeight = designHeight; } } if(scaleWidth >0 && scaleHeight >0) { if(scaleWidth % 2 == 0) { scaleWidth += 1; } else { scaleWidth -= 1; } Screen.SetResolution(scaleWidth,scaleHeight,true); } #endif } void OnApplicationPause(bool paused) { if (paused) { } else { setDesignContentScale(); } } |
我在补充一下: 这个方法不会影响NGUI的自适应,也不会影响游戏原有的任何逻辑也不用在改别的代码,在各种Android分辨率上都可行,效率就可以提升很多。我们项目已经轰轰烈烈的使用了,唯一的缺点就是设置分辨率的时候屏幕会闪一下。可以做一个黑屏 或者 几个字“正在加载中” 。。 所以我想在java层去改, 但是拿不到GLSurfaceView 。。如果有知道的朋友请在下面留言告诉我。谢谢。
这两天测试发现有时候按下手机的关机键,然后在返回游戏发现游戏屏幕竖过来了(我们是横屏游戏)。而且是随机性的,效果如下图所示:
在这两篇文章中我找到了答案
http://blog.k-res.net/archives/1702.html
http://stackoverflow.com/questions/7185644/android-opengl-crazy-aspect-ratio-after-sleep
解决这个问题需要在java这一层来配合,需要改一下你的UnityPlayerNativeActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private int width,height; // Setup activity layout @Override protected void onCreate (Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); getWindow().takeSurface(null); setTheme(android.R.style.Theme_NoTitleBar_Fullscreen); getWindow().setFormat(PixelFormat.RGB_565); mUnityPlayer = new UnityPlayer(this); if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true)) getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(mUnityPlayer); mUnityPlayer.requestFocus(); //保存一下游戏屏幕的宽和高 DisplayMetrics dm = getResources().getDisplayMetrics(); width = dm.widthPixels; height = dm.heightPixels; } |
还是在这个类里。
1 2 3 4 5 6 7 8 9 10 11 12 |
// This ensures the layout will be correct. @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //在这里强制设置一下屏幕的宽和高 mUnityPlayer.getView().getLayoutParams().width = width; mUnityPlayer.getView().getLayoutParams().height = height; Log.v("unity", width+" " + height ); mUnityPlayer.configurationChanged(newConfig); } |
好了,目前我用这个方法已经完美解决了这个问题,大家如果还有什么好得经验分享,欢迎在下面给我留言。
- 本文固定链接: https://www.xuanyusong.com/archives/3205
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
根据雨松的思路,完美解决了闪烁问题了。
c#代码
AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
var java = jc.GetStatic(“currentActivity”);
java.Call(“SetConfiguration”, scaleWidth, scaleHeight); // 缩放宽高,自己计算
Screen.SetResolution(scaleWidth, scaleHeight, true, 30);
android代码
public void SetConfiguration(int fW, int fH)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().takeSurface(null);
setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
getWindow().setFormat(PixelFormat.RGB_565);
mUnityPlayer = new UnityPlayer(this);
if (mUnityPlayer.getSettings ().getBoolean (“hide_status_bar”, true))
getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
Configuration config = getResources().getConfiguration();
//在这里强制设置一下屏幕的宽和高
mUnityPlayer.getView().getLayoutParams().width = fW;
mUnityPlayer.getView().getLayoutParams().height = fH;
mUnityPlayer.configurationChanged(config);
//ShowToast(“width=” + width + “, height=” + height);
}
我用了这个方法,发现android 输入框输入不了文字,这个有碰到的吗?咋整?
雨松大大威武.哈哈哈
巍大,好久不见啊。。
momo 你好。我们游戏在适配的时候 打算多余的地方留黑边,设置了ui和3d摄像机的大小。但是使用SetResolution 会导致ui全部全屏,超出了本来摄像机的可视范围。
求教一下,这段代码的作用是什么?看着逻辑好奇怪。。。 if(scaleWidth % 2 == 0) { scaleWidth += 1; } else { scaleWidth -= 1; }
同上求教
为什么说这个技术没必要在IOS上使用呢?
ios 就那么几个机器。 很容易测试。。。
我按老师的方法做了, 发现切换之后画质会有肉眼明显可见的下降。不知道老师有没有这个情况?设备分辨率1920*1080,设计分辨率1136*640.
下降肯定是有的。。
Unity自带VR上这代码就不管用了,Screen.SetResolution
谷歌出了GLSurfaceView.java的源码 不知道对你有用没
momo大神,我用这个这个设置,但是我用NGUI做的点击空白区域关闭界面就关不了。我是在空白区域加了个碰撞盒实现的。
松哥,我执行 mUnityPlayer = new UnityPlayer(this)就直接闪退了.. 怎么破呢…还有. 我是想获取手机虚拟键盘的高度.. 能不能指点下呢..
这个我也没做过。。
这种情况,有什么必先的方法没有
我这边只是一些机器上会偶尔出现
雨松大,我尝试在UnityPlayerNativeActivity.java中利用反射调用mUnityPlayer.setScreenSize()方法,成功设置了surfaceview的分辨率,不会闪,但是问题是触摸范围却出问题了,1080p的自己,切换到640,整个触摸范围被缩小到左上角一小块
用我这个吧。。 可以在设置里面做分辨率 调节。。。 让用户自己去选择
效率在魅族mx4上得到了神一样的提升,唯一蛋疼就是Screen.SetResolution会闪那一下,目前我是黑屏0.5s等设置好了才开始显示….
谢谢 分享~~有用!
高手,请问怎么知道是调用unity自己的GLSurfaceView?有这个类不同的import吗?知道这个GLSurfaceView 类大概在哪里吗?
请问在JAVA层修改的话,是不是在使用Android插件的情况下需要修改?
不是, 不使用android插件也要修改。。。
饿,请问怎么改呢?是在安装目录下改吗?
plugin/android 下面。 你可以在网络上搜索一下。。
再请问下,效率提升大概能有多少呢?
我测试的结果是 1080P手机 改成 640 直接从 30FPS提升到50FPS。。。。
很牛逼的样子。以后可能会用上。关注!!
嗯, 欢迎讨论。。
直接用下面那段安卓代码就可以了吧
不行的, 因为 下面的安卓代码是改屏幕尺寸的 不是分辨率。。。 如果 java哪里能拿到 GLSurfaceView的话 就好办了。。
多谢
UI闪烁那个也解决了吗?
哪个解决不了哦。。。
特别是UI
难道界面没有被拉伸么? 我试的时候 界面全被拉伸了啊 很虚的
你的界面自适应是怎么做的?我没出现这个问题,效果挺好的, 我把所有大于 960X640的都 改了。。
你好,就是NGUI的自适应 ,现象就像 320*480的图片放大到640*960的样子似的~
momo 我在游戏刚启动后也就是Unity的图标消失后void Start () { int rew = Screen.currentResolution.width; int reh = Screen.currentResolution.height; Screen.SetResolution(rew / (reh / 640), 640, true);}添加的这样的代码,运行后发现显示会有问题,目标分辨率是 1920 * 1080小米3,这是怎么回事呢
原来是算错了,晕死
momo 我在游戏刚启动后也就是Unity的图标消失后void Start () { int rew = Screen.currentResolution.width; int reh = Screen.currentResolution.height; Screen.SetResolution(rew / (reh / 640), 640, true); }添加的这样的代码,运行后发现显示会有问题,目标分辨率是 1920 * 1080小米3,这是怎么回事呢
没有啊 我们在 s4 小米3上 都试过。。 改完分辨率 就是 1136 X 640 。 你说的有问题 是UI有问题 还是 3D有问题?
啥都没有问题,哈哈,有问题的应该都是算错了,得到的比例应该是浮点数,
强制设置Screen.SetResolution(960, 640, true)后 实际屏幕比它大或小了 会是什么情况? 全屏自动拉伸填充满整个屏幕?
这个和屏幕自适应的原理差不多。。我们已经在项目里 轰轰烈烈的使用了 效果非常好。。
960*640 等比缩放后,1140*760 或者 1280 * 854,明显针对1280*720分辨率的只能用1140*760,这么说的话要上下留黑边。理解正确吗? 文中所指的算法是什么?
开发的时候布的界面是 960X640 ,此时运行在 1280X720上。 那么 修改后的分辨率 就是 Screen.SetResolution(1138,640,true);1138 = 1280/(720/640)但是你还要去考虑 比 960X640 大的情况 或者 比 960X640小的情况。不会有黑边的, 因为你改的是分辨率。。并不是显示区域。。。