- Home /
Why do get lag when rotating a camera on android ?
Hi there. Iv just been having a little play at running some unity code on an android phone. Im basically just testing to see what i can expect from the phone. So iv got a scene with some basic water, terrain, a camera with some mouse/touch screen controls and a dodgy Frames Per Second display (updates every 5 seconds). The phone seams to run happily around the 30 fps mark until i try rotating the camera and then it drops off to 5 fps. I wasnt expecting to get as much as 30 FPS but I just dont understand why rotating the camera would cause such a huge amount of lag and would love some explanation.
This is the snip it of code responsible for the lag but i cant see a reason for this to cause any problems directly so would love to know if there is something im missing ? My best guess is some accelerated terrain related calculations but then i would have thought translating would be just as bad too.
if (do_rotate)
{
if (mouse_double_tap)
{//do camare rotation
this.rotationX += (mx * sensitivity);
if (rotationX< 0f) this.rotationX+=360f;
if (rotationX>360f) this.rotationX-=360f;
this.rotationY += (my * this.sensitivity);
this.rotationY = Mathf.Clamp (this.rotationY, this.minimumY, this.maximumY);
transform.localEulerAngles = new Vector3(-this.rotationY, this.rotationX, 0);
/* Vector3 p = this.transform.position;
p.x += (Mathf.Sin(this.rotationX*Mathf.Deg2Rad)*Mathf.Cos(this.rotationY*Mathf.Deg2Rad));
p.z += (Mathf.Cos(this.rotationX*Mathf.Deg2Rad)*Mathf.Cos(this.rotationY*Mathf.Deg2Rad));
p.y += (Mathf.Sin(this.rotationY*Mathf.Deg2Rad));
this.transform.LookAt(p);*/
}
}
Android 2.3.3 API level 10 .apk flie
Full Camera Code
using UnityEngine;
using System.Collections;
/// MouseLook rotates the transform based on the mouse delta.
/// Minimum and Maximum values can be used to constrain the possible rotation
/// To make an FPS style character:
/// - Create a capsule.
/// - Add the MouseLook script to the capsule.
/// -> Set the mouse look to use LookX. (You want to only turn character but not tilt it)
/// - Add FPSInputController script to the capsule
/// -> A CharacterMotor and a CharacterController component will be automatically added.
/// - Create a camera. Make the camera a child of the capsule. Reset it's transform.
/// - Add a MouseLook script to the camera.
/// -> Set the mouse look to use LookY. (You want the camera to tilt up and down like a head. The character already turns.)
[AddComponentMenu("Camera-Control/Mouse Look")]
public class MouseLook : MonoBehaviour {
//testing on android ver 2.3.6
public float sensitivity = 15f;
public float minimumY = -90f;
public float maximumY = 0f;
float rotationY = 0f;
float rotationX = 0f;
public bool mouse_down = false;
public bool mouse_double_tap = false;
public float double_tap_speed = 0.25f;//in seconds
public float last_mouse_down_time = -1;
public float touch_last_dist = -1;
public float touch_last_dist_time = -1;
public float touch_max_movment = 50;//should use finger id tracking and replace this
public float fast_dis = 0;//distence to compear touch motion for speed increase. Is set in start using screen size
public float fast_magnitude_increase = 12;//this is the magnitude increase of Touch speed. if fast_dis has been acheived then the speed increase shall = fast_magnitude_increase producing a range of 1-fast_magnitude_increase
public float max_speed = 0f;//for tracking fastest touch movment in pixels a second
//fps mesurements
public float mesure_time = 5;
public float timer_start = 0;
public float frame_count = 0;
public float fps = 0;
public Terrain map = null;
void Update ()
{
//track fps
float t = (Time.time-this.timer_start);
if (t>=this.mesure_time)
{
this.fps = this.frame_count/t;
this.timer_start = Time.time;
this.frame_count=0;
}
this.frame_count++;
//as we are hoping to use a touch screen i am duplicating mouse actions and then simulating them with touches
float mx = Input.GetAxis("Mouse X");//M stands for movment and should be a change compeared to the last known position
float my = Input.GetAxis("Mouse Y");//touches are returned as screen positions not as motion so values are overritten latter if a touch is detected
float zoom_change = (1f-(Input.GetAxis("Mouse ScrollWheel")*0.6f));//scroll wheel is not touch simulated by unity so value is overritten if more than 1 touch is detected
bool do_scroll = false;
bool do_rotate = false;
bool do_zoom = false;
//track double clicks. touches trigger mouse button events too
if (Input.GetMouseButtonUp(0)) mouse_down=false;
if (Input.GetMouseButtonDown(0))
{
mouse_down=true;
mouse_double_tap = ((Time.time-this.last_mouse_down_time)<=this.double_tap_speed);
this.last_mouse_down_time = Time.time;
}
if (Input.touchCount>0)
{//track touches and convert into mouse actions
if (Input.touchCount==1)
{
this.touch_last_dist = 0f;//reset
float speed = Input.touches[0].deltaPosition.magnitude/Input.touches[0].deltaTime;
if (max_speed<speed && !float.IsInfinity(speed) && !float.IsNaN(speed)) max_speed=speed;
float speed_increase = 1f+(this.fast_magnitude_increase*(speed/this.fast_dis));
if (float.IsNaN(speed_increase)) speed_increase=1f;
Vector2 tm = (Input.touches[0].deltaPosition/25)*speed_increase;
if (Input.touches[0].deltaPosition.magnitude<this.touch_max_movment)
{
mx = tm.x;
my = tm.y;
}
else
{
mx = 0f;
my = 0f;
}
}
else
{
mouse_down = false;
Vector2 td = Input.touches[0].position-Input.touches[1].position;
if (this.touch_last_dist!=0f)
{
float dis_change = (this.touch_last_dist-td.magnitude);
float speed = dis_change/(Time.time+this.touch_last_dist_time);
if (max_speed<speed && !float.IsInfinity(speed) && !float.IsNaN(speed)) max_speed=speed;
float speed_increase = 1f+(this.fast_magnitude_increase*(speed/(this.fast_dis*2f)));
if (float.IsNaN(speed_increase)) speed_increase=1f;
if (dis_change<this.touch_max_movment) zoom_change = 1f-((dis_change/100)*speed_increase);
}
this.touch_last_dist = td.magnitude;
this.touch_last_dist_time = Time.time;
}
}
Vector3 map_pos = this.transform.position;
if (mouse_down)
{
do_rotate=mouse_double_tap;
do_scroll=!mouse_double_tap;
}
if (do_rotate)
{
if (mouse_double_tap)
{//do camare rotation
this.rotationX += (mx * sensitivity);
if (rotationX< 0f) this.rotationX+=360f;
if (rotationX>360f) this.rotationX-=360f;
this.rotationY += (my * this.sensitivity);
this.rotationY = Mathf.Clamp (this.rotationY, this.minimumY, this.maximumY);
transform.localEulerAngles = new Vector3(-this.rotationY, this.rotationX, 0);
/* Vector3 p = this.transform.position;
p.x += (Mathf.Sin(this.rotationX*Mathf.Deg2Rad)*Mathf.Cos(this.rotationY*Mathf.Deg2Rad));
p.z += (Mathf.Cos(this.rotationX*Mathf.Deg2Rad)*Mathf.Cos(this.rotationY*Mathf.Deg2Rad));
p.y += (Mathf.Sin(this.rotationY*Mathf.Deg2Rad));
this.transform.LookAt(p);*/
}
}
if (do_scroll)
{//do translation control (might want a scaler based apon rotationY ?)
float height_scale = map_pos.y/70f;
map_pos.x -= ( Mathf.Sin(this.rotationX*Mathf.Deg2Rad)*my*this.sensitivity*height_scale) + ( Mathf.Cos(this.rotationX*Mathf.Deg2Rad)*mx*this.sensitivity*height_scale);
map_pos.z -= ( Mathf.Cos(this.rotationX*Mathf.Deg2Rad)*my*this.sensitivity*height_scale) + (-Mathf.Sin(this.rotationX*Mathf.Deg2Rad)*mx*this.sensitivity*height_scale);
}
//very bad zoom control
do_zoom = zoom_change!=1f;
if (do_zoom)
{
map_pos.y = map_pos.y*zoom_change;
if (map_pos.y< 10) map_pos.y = 10;
if (map_pos.y>500) map_pos.y = 500;
}
//apply translation and zoom adjustments
this.transform.position = map_pos;
}
void Start ()
{
this.timer_start = Time.time;
this.fast_dis = Mathf.Sqrt((Screen.width*Screen.width)+(Screen.height*Screen.height))*2;//covers the full screen in 1/2 a seconde
Input.simulateMouseWithTouches = true;
// Make the rigid body not change rotation
if (rigidbody) rigidbody.freezeRotation = true;
this.QualityChanged();
}
void OnGUI ()
{
if (GUI.Button(new Rect(0,Screen.height-30,50,30),"Exit")) Application.Quit();
GUI.TextField(new Rect(0,Screen.height-60,80,30),"FPS="+this.fps);
GUI.TextField(new Rect(0,0,100,30),this.max_speed.ToString()+" / "+this.fast_dis.ToString());
// GUI.TextField(new Rect(0,30,250,30),this.transform.position.ToString()+" / "+this.transform.localEulerAngles.ToString());
bool update_map = false;
if (GUI.Button(new Rect(Screen.width-160,0,30,30),"-"))
{
QualitySettings.DecreaseLevel();
update_map=true;
}
GUI.TextField(new Rect(Screen.width-130,0,100,30),"Qu="+QualitySettings.names[QualitySettings.GetQualityLevel()]);
if (GUI.Button(new Rect(Screen.width-30,0,30,30),"+"))
{
QualitySettings.IncreaseLevel();
update_map=true;
}
if (update_map) this.QualityChanged();
}
void QualityChanged ()
{
switch(QualitySettings.GetQualityLevel())
{
case 0://fastest
this.map.castShadows = false;
this.map.heightmapPixelError = 200f;
this.map.basemapDistance = 0f;
this.map.detailObjectDistance = 50f;
this.map.detailObjectDensity = 0.1f;
this.map.treeDistance = 200f;
this.map.treeBillboardDistance = 0f;
this.map.treeCrossFadeLength = 0f;
break;
case 1:
this.map.castShadows = false;
this.map.heightmapPixelError = 100f;
this.map.basemapDistance = 250f;
this.map.detailObjectDistance = 75f;
this.map.detailObjectDensity = 0.25f;
this.map.treeDistance = 400f;
this.map.treeBillboardDistance = 40f;
this.map.treeCrossFadeLength = 10f;
break;
case 2:
this.map.castShadows = true;
this.map.heightmapPixelError = 25f;
this.map.basemapDistance = 500f;
this.map.detailObjectDistance = 100f;
this.map.detailObjectDensity = 0.5f;
this.map.treeDistance = 1000f;
this.map.treeBillboardDistance = 80f;
this.map.treeCrossFadeLength = 50f;
break;
case 3://good
this.map.castShadows = true;
this.map.heightmapPixelError = 6f;
this.map.basemapDistance = 1000f;
this.map.detailObjectDistance = 150f;
this.map.detailObjectDensity = 1.0f;
this.map.treeDistance = 1500f;
this.map.treeBillboardDistance = 120f;
this.map.treeCrossFadeLength = 100f;
break;
case 4:
this.map.castShadows = true;
this.map.heightmapPixelError = 3f;
this.map.basemapDistance = 1500f;
this.map.detailObjectDistance = 200f;
this.map.detailObjectDensity = 1.0f;
this.map.treeDistance = 1500f;
this.map.treeBillboardDistance = 1500f;
this.map.treeCrossFadeLength = 150f;
break;
case 5://fantastic
this.map.castShadows = true;
this.map.heightmapPixelError = 1f;
this.map.basemapDistance = 2000f;
this.map.detailObjectDistance = 250f;
this.map.detailObjectDensity = 1.0f;
this.map.treeDistance = 2000f;
this.map.treeBillboardDistance = 2000f;
this.map.treeCrossFadeLength = 200f;
break;
}
}
}