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 8 9 |
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 7 8 |
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 44 45 |
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 26 27 |
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 13 14 |
// 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程序研究院 发表
为啥不用unity官方提供的API?
QualitySettings.resolutionScalingFixedDPIFactor
分辨率的变更,有办法在Unity层面上监控吗?等价于Java层面上Change监控~~~
其实还有一个很土的办法,就是再定时0.1秒后再设置一次分辨率就可以解决分辨率错乱的问题了
根据雨松的思路,完美解决了闪烁问题了。
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.
下降肯定是有的。。