Hello, I really do not understand why I am getting really bad frames on Android
I am using Libgdx, and using 3D. I have two textures, not including the font texture so basically 3.
The game on android runs at about 50 fps however it dips down to 20 fps which makes the game feel really horrible… and this has no logic only rendering
and on Desktop with no vSync enabled I get 5500 fps, but thats with a GTX 1080 and I7 6700K
Here is a screen shot of the game running
I render everything the whole map in one mesh (batch)
The main texture sheet is 256x256 and I use it as a sprite sheet for 16x16 textures
The shader has point and directional light which has a max of 15 lights per vertex
I did have other entities running which are dynamic but i stored them all into one batch, however when i removed it the performance was only a tad better
I really have no idea why my frames a dipping when there is nothing much going on, the phone I tested with was the Samsung Galaxy Ace 2 (Can run Dead Trigger and Gta) I also tried the Nexus 7 which i get even worse frames, yet the Nexus 7 is better??
Render Code (Without uniforms)
mesh.bind(shader);
{
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, mesh.getNumIndices(), GL20.GL_UNSIGNED_SHORT, 0);
}
mesh.unbind(shader);
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
uniform mat4 u_projTrans;
uniform mat4 transformMatrix;
varying vec4 v_color;
varying vec2 v_texCoords;
uniform vec3 directionLight;
uniform vec4 directionLightColour;
uniform int useDirectionalLight;
const int AMOUNTOFLIGHTS = 15;
uniform vec3 pLightPosition[AMOUNTOFLIGHTS];
uniform vec4 pLightColour[AMOUNTOFLIGHTS];
uniform vec3 pAttenuation[AMOUNTOFLIGHTS];
uniform int pAmount;
varying vec3 lightDiffuse;
void main(){
v_color = a_color;
v_texCoords = a_texCoord0;
vec4 worldPos = transformMatrix * a_position;
vec3 unitNormal = normalize((transformMatrix * vec4(a_normal,0.0)).xyz);
lightDiffuse = vec3(0.0);
for(int i = 0;i < pAmount;++i){
vec3 lightDir = pLightPosition[i] - worldPos.xyz;
float distance = length(lightDir);
float attFactor = pAttenuation[i].x + (pAttenuation[i].y * distance) + (pAttenuation[i].z * distance * distance);
vec3 unitLightVector = normalize(lightDir);
float nDot = dot(unitNormal,unitLightVector);
float brightness = max(nDot,0.0) / attFactor;
vec3 light = brightness * pLightColour[i].rgb;
lightDiffuse += light;
}
if(useDirectionalLight == 1){
float nDot = dot(unitNormal,-directionLight);
float brightness = max(nDot,0.0);
vec3 diffuse = brightness * directionLightColour.rgb;
lightDiffuse += diffuse;
}
lightDiffuse = max(lightDiffuse,0.4);
gl_Position = u_projTrans * worldPos;
}
FRAGMENT
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec4 fogColour;
uniform float fogThickness;
varying vec3 lightDiffuse;
void main(){
vec4 texColour = texture2D(u_texture, v_texCoords);
if(texColour.a < 0.5) discard;
vec4 outputFrag = vec4(lightDiffuse,1.0) * (v_color * texColour);
// FOG
float perspective_far = 12.0;
float fog_cord = (gl_FragCoord.z / gl_FragCoord.w) / perspective_far;
float fog = fog_cord * fogThickness;
gl_FragColor = mix(fogColour, outputFrag, clamp(1.0-fog,0.0, 1.0));
}
Batching Code
package com.hawk.tommo.game.graphics;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;
import com.hawk.tommo.game.entities.RenderableEntity;
import com.hawk.tommo.game.entities.RenderableModelEntity;
public class EntityBatchRenderer implements Disposable {
static final int SIZE = 1000;
static final int POSITIONCOMPONENT = 3;
static final int NORMALCOMPONENT = 3;
static final int TEXTURECOMPONENT = 2;
static final int COLORCOMPONENT = 1;
final static int components = POSITIONCOMPONENT + NORMALCOMPONENT + TEXTURECOMPONENT + COLORCOMPONENT;
private Mesh mesh;
private float[] vertices;
private short[] indices;
private int lastVerticesCount, lastIndicesCount, lastIndiceID;
public EntityBatchRenderer() {
lastVerticesCount = 0;
lastIndicesCount = 0;
vertices = new float[SIZE * components];
indices = new short[SIZE * 3];
mesh = new Mesh(false, vertices.length, indices.length,
new VertexAttribute(Usage.Position, POSITIONCOMPONENT, "a_position"),
new VertexAttribute(Usage.Normal, NORMALCOMPONENT, "a_normal"),
new VertexAttribute(Usage.TextureCoordinates, TEXTURECOMPONENT, "a_texCoord0"),
new VertexAttribute(Usage.ColorPacked, COLORCOMPONENT + 3, "a_color"));
}
static Vector3 tmp = new Vector3();
public void render(RenderableEntity entity) {
this.render(entity.getMesh(), entity.getTransform(), entity.getColor(), entity.getTextureRegion());
}
public void render(RenderableModelEntity entity) {
this.render(entity.getMesh(), entity.getTransform(), entity.getColor(), null);
}
public void render(Mesh mesh, Matrix4 transform, Color color, TextureRegion tex) {
FloatBuffer vBuffer = mesh.getVerticesBuffer();
ShortBuffer iBuffer = mesh.getIndicesBuffer();
int vLimit = vBuffer.limit();
int iLimit = iBuffer.limit();
if (lastVerticesCount + vLimit < vertices.length) {
float floatColor = (color != null) ? color.toFloatBits() : -1;
for (int i = lastVerticesCount; i < vLimit + lastVerticesCount; i += components) {
tmp.set(vBuffer.get(i - lastVerticesCount), vBuffer.get(i + 1 - lastVerticesCount),
vBuffer.get(i + 2 - lastVerticesCount));
if (transform != null)
tmp.mul(transform);
vertices[i] = tmp.x;
vertices[i + 1] = tmp.y;
vertices[i + 2] = tmp.z;
vertices[i + 3] = vBuffer.get(i + 3 - lastVerticesCount); // n
vertices[i + 4] = vBuffer.get(i + 4 - lastVerticesCount); // n
vertices[i + 5] = vBuffer.get(i + 5 - lastVerticesCount); // n
if (tex != null) {
vertices[i + 6] = vBuffer.get(i + 6 - lastVerticesCount) + tex.getU(); // t
vertices[i + 7] = vBuffer.get(i + 7 - lastVerticesCount) + tex.getV(); // t
} else {
vertices[i + 6] = vBuffer.get(i + 6 - lastVerticesCount); // t
vertices[i + 7] = vBuffer.get(i + 7 - lastVerticesCount); // t
}
if (floatColor != -1) {
vertices[i + 8] = floatColor;
} else {
vertices[i + 8] = vBuffer.get(i + 8 - lastVerticesCount); // t
}
}
int largest = Short.MIN_VALUE;
for (int i = lastIndicesCount; i < iLimit + lastIndicesCount; ++i) {
indices[i] = (short) (iBuffer.get(i - lastIndicesCount) + lastIndiceID);
largest = indices[i] > largest ? indices[i] : largest;
}
lastVerticesCount += vLimit;
lastIndicesCount += iLimit;
lastIndiceID = largest + 1;
} else {
Gdx.app.log("ERROR", "Can't render anymore, need bigger batch size!");
}
}
public void flush(ShaderProgram shader) {
mesh.setVertices(vertices);
mesh.setIndices(indices);
mesh.bind(shader);
{
Gdx.gl.glDrawElements(GL20.GL_TRIANGLES, lastIndicesCount, GL20.GL_UNSIGNED_SHORT, 0);
}
mesh.unbind(shader);
lastVerticesCount = 0;
lastIndicesCount = 0;
lastIndiceID = 0;
}
@Override
public void dispose() {
mesh.dispose();
}
}