Fillrate... Device.Present... ideas please?

Hello,

I am developing a 3D Game with 2D mechanic (I want some objects to be 3d, but some others are 2d, and the mechanic itself is 2d), and I am having performance issues on devices such as iPad, Galaxy Tab (10.1), in another words, the bigger the device, the slower it runs (iPad 2 however runs it smoothly at 60 FPS, since it is considerably more powerful then iPad 1).

My question is: what is the ideal way of working with transparent elements on the game? Even tho our game does not use that many transparent elements during gameplay (only on menu), they are still causing the game to run slow on some devices. I’ve read a great post about Zombieville USA about how its made and I might be very ignorant on the subject (I am, actually), but I dont know what they were doing differently yet.

Here is one of my scenarios:

There is this scene:

And it consists of: animated 2D character (with transparent planes), 4 transparent planes (buttons/logo), 4 transparent background planes (houses layer 1, houses layer 2, ground, ceiling) and 1 diffuse background plane. In another words, transparent elements are the following:

This gave me a 15-20fps performance on iPad 1.

After long readings and understanding some concepts, and people speaking of how merciless transparencies can be, I’ve made some changes: I modeled (poorly) the background transparencies (the 4 transparent planes), and made the parallax effect using the transform instead of the UV. Looks like this on the editor view:

This gives me a 25-35 fps performance on iPad 1. The profiler looks like this:

So, for test purposes, I removed all the remaining transparent geometry… so the scene looks like this:

And the profiler like this:

And it is still at 45-50 fps! So my question is: How is the RIGHT way of handling this? What am I doing wrong? Im not saying 45-50 fps is bad, but if no transparency at all, and 1.7k tris cost the device 10-15 fps… there must be something I am not grasping here.

This is just a menu problem, since I have some scrolling for world selection, it looks terrible at low FPS, and the click events sometimes seen not to be sent due to the FPS, which is also terrible… but it also happens during the game, making the gameplay (its an action/strategy game) awkward… so please, if anyone has any ideas on the right way to tackle this… because I see game menus (and in game scenes) that are extremely complex and animated and full of particles and huge transparent elements… and it runs perfectly… and my simple game is lagging =(

I am sorry for the long post, but I dont know what else to do!
Thank you for your attention,
Best regards,
Allan

This could be the result of many things… so lets start with the easy ones.

Possible Solution 1:
By default the GPU of many devices runs at 30fps. To set the GPU to run at 60 fps make sure you call this somewhere in a script on launch:

	Application.targetFrameRate = 60;

Devices cap out at 60 fps so there’s no need to set it higher than this.

Possible Solution 2:
Shaders are often to blame for lagging performance, especially on older devices like 3GS, iPhone 4 and iPad 1. I personally found that using the constantColor function in ShaderLab completely and utterly unusably slow. If you are using constant colour in your shaders, try removing it and see if it’s better. If it is better try think of another way to color things, like using vertex colors.

            SetTexture [_MainTex] {
                constantColor [_Color]
                Combine texture * primary DOUBLE, texture * constant
            }

Note that this is the only one i found that is terribly slow but there might be more shader functions I haven’t used that are also very slow.

Possible Solution 3:
What are your textures set to? are they power of 2? Are the PVRCT compressed? Textures that are not square, pvrct format, or power of 2 can slow down devices. I would expect older devices such as iPad 1 to be most effected.

Good luck

Hey Antony, thanks for the answer.

targetFPS is set to 60, unfortunately =(

I am completely ignorant so far as shaders inner workings, so that leaves me with Unity/Mobile/Unlit or, the one I am currently using, MADFINGER/Diffuse/Simple (one of the free shaders Madfinger has made available) I suppose these are fast, right?

All textures are power of 2, PVRTC compressed (from Advanced import settings)

Any other ideas? =/

Well, first thing i noticed, you could cut those background shapes out using far, far fewer triangles, but that doesn’t matter, there’s still not many of them.

How are you moving the object now? In code? If so, show code… Also, can you show your stats window? That should work fine, even on an iPad 1.

Do you have an OnGui things hanging around? Etc

Hey Jtbentley,

I’ve got 3 scripts running during this test (cant post em right now because I am not at the office, can post later):

One that does UV animation by storing and changing the UV settings of the texture (the diffuse background). It does so through Update by material.setoffset or something like that.

The other one is for the model parallax… it is something basically like this:

Update()
{
myTransform.position += new Vector3(speed, 0, 0);
if (myTransform.position.x < screenLimit)
{
myTransform.position += new Vector3(screenLimit * 2, 0, 0);
}
}

Just so the model moves in the target direction, and when it gets out of the screen, I reposition it on the other side of the screen, so it enters again… very simple stuff.

Finally, the 3rd script is the framerate from the community, which does fine by itself.

Also, I’ve tried removing these codes (as simple as they are), but the results are the same =/

I will post a screenshot of Stats window, but if I remember well it was something like 4 draw calls, 1.7k triangles… textures are very small in size, 256x256 I think.

I dont believe the problem is related to this tho =/

Ok, yesterday I didnt have the time, but here are all the infos on the scene (the last screenshot, without transparencies):

Stats window during play:

Code: - UV Animation for fartest background (diffuse plane)

public class TextureOffsetAnimator : MonoBehaviour
{
	public float speed;
	public int backgroundIndex;
	private Material myMaterial;
	
	private void Start()
	{
		myMaterial = renderer.material;
		myMaterial.mainTextureOffset = GlobalValues.backgroundOffset[backgroundIndex];
	}
	
	private void Update()
	{
		GlobalValues.backgroundOffset[backgroundIndex].x += speed;
		myMaterial.mainTextureOffset = Vector2.Lerp(myMaterial.mainTextureOffset, GlobalValues.backgroundOffset[backgroundIndex], 0.5f);
	}
}

Code: - Model animator for parallax effect (other layers of parallax)

public class ModelParallaxAnimator : MonoBehaviour
{
	public float objectDistance;
	public float speed;
	public Transform[] childObjects;
	public int backgroundLayer;
	
	private void Start()
	{
		if (GlobalValues.backgroundOffset[backgroundLayer] == Vector3.zero)
			GlobalValues.backgroundOffset[backgroundLayer] = childObjects[0].localPosition;
		if (GlobalValues.backgroundOffset[backgroundLayer + 1] == Vector3.zero)
			GlobalValues.backgroundOffset[backgroundLayer + 1] = childObjects[1].localPosition;
	}
	
	private void Update()
	{
		GlobalValues.backgroundOffset[backgroundLayer].x -= speed;
		GlobalValues.backgroundOffset[backgroundLayer + 1].x -= speed;
		if (GlobalValues.backgroundOffset[backgroundLayer].x < -objectDistance)
			GlobalValues.backgroundOffset[backgroundLayer].x += objectDistance * 2;
		if (GlobalValues.backgroundOffset[backgroundLayer + 1].x < -objectDistance)
			GlobalValues.backgroundOffset[backgroundLayer + 1].x += objectDistance * 2;
		childObjects[0].localPosition = GlobalValues.backgroundOffset[backgroundLayer];
		childObjects[1].localPosition = GlobalValues.backgroundOffset[backgroundLayer + 1];
	}
}

Also, there is code for touch events, and even tho I wasnt actually touching the screen, I will post it anyway, maybe I could do it some other way that is faster:

public class TouchHandlerBasic : MonoBehaviour
{
	private bool buttonClick;
	private Camera guiCamera;
	
	private void Start()
	{
		guiCamera = GameObject.Find("GUICamera").GetComponent<Camera>();
		if (Application.platform != RuntimePlatform.Android  Application.platform != RuntimePlatform.IPhonePlayer)
			Destroy(this);
	}
	
	private void Update()
	{
        foreach (Touch touch in Input.touches)
		{
			if (touch.fingerId == 0)
			{
	            if (touch.phase == TouchPhase.Began)
				{
					buttonClick = true;
					
				}
				if (touch.phase == TouchPhase.Ended)
				{
					if (buttonClick)
					{
						Ray ray = guiCamera.ScreenPointToRay(touch.position);
						RaycastHit hit = new RaycastHit();
						if (Physics.Raycast(ray, out hit, Mathf.Infinity))
						{
							hit.collider.gameObject.SendMessage("OnMouseDown", SendMessageOptions.DontRequireReceiver);
						}
					}
				}
			}
		}
    }
}

Well… thats it. Hints about the code (something I could do in a faster way, anything) are VERY appreciated, but I am still trying to understando why the device.present is being a killer, without transparencies in the scene. (Oh, and there is a code that just adjusts the targetframerate to 60)

Once again, thank you for your attention,
Best regards,
Allan

You should ideally be moving things with Time.deltaTime, otherwise you can get inconsistent movement speeds… Search the help for some application examples with :slight_smile: deltaTime is specifically for handling the amount of time that’s passed since the previous frame, so if the code isn’t running super smoothly (for whatever reason), the motion will be compensated for.

For example…