I've ported a desktop OpenGL application to Android NDK (under OpenGL ES 2), and there seems to be a random deformation of my mesh. On most application runs, it looks 100% perfect, but sometimes it looks as follows:
The inconsistency of the problem is the most concerning to me. I don't know if it's because of my Android simulator, or if it's something else. Through my testing, I can establish that it's either:
My model process looks as follows:
On every draw:
- bind the program
- change the uniforms
- if (has vao support)
- bind vao
- enable all vertex attribute arrays
- for every mesh
- bind array buffer
- set the attribute pointer for each vertex array
- bind element buffer
- bind texture & set uniform of texture location
- glDrawElements
- disable all vertex attribute arrays
And this is the actual code:
glUseProgram(program_);
if (loaded_vao_)
{
#if !defined(TARGET_OS_IPHONE) && !defined(__ANDROID__)
glBindVertexArray(vao_);
#else
glBindVertexArrayOES(vao_);
#endif
}
glEnableVertexAttribArray(vPosition_);
glEnableVertexAttribArray(vTexCoord_);
glEnableVertexAttribArray(boneids_);
glEnableVertexAttribArray(weights_);
for (unsigned int i = 0; i < vbo_.size(); i++)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_[i]);
glVertexAttribPointer(vPosition_, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(vTexCoord_, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(texcoord_locations_[i]));
#if !defined(TARGET_OS_IPHONE) && !defined(__ANDROID__)
glVertexAttribIPointer(boneids_, 4, GL_INT, 0, reinterpret_cast<void*>(bone_id_locations_[i]));
#else // APPLE OR ANDROID
glVertexAttribPointer(boneids_, 4, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(bone_id_locations_[i]));
#endif
glVertexAttribPointer(weights_, 4, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(bone_weight_locations_[i]));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_[i]);
// Textures
if (!textures_.empty())
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures_[texture_numbers_[i]]);
glUniform1i(textureSample_, 0);
}
glDrawElements(GL_TRIANGLES, ind_size_[i], GL_UNSIGNED_SHORT, 0);
}
glDisableVertexAttribArray(vPosition_);
glDisableVertexAttribArray(vTexCoord_);
glDisableVertexAttribArray(boneids_);
glDisableVertexAttribArray(weights_);
As well, my vertex shader looks as follows:
precision mediump float;
attribute vec3 vPosition;
attribute vec2 vTexCoord;
attribute vec4 boneids;
attribute vec4 weights;
uniform mat4 pos;
uniform mat4 view;
uniform mat4 scale;
uniform mat4 rotate;
uniform mat4 proj;
uniform mat4 bones[50];
uniform int has_bones;
varying vec4 color;
varying vec2 texcoord;
void main()
{
color = vec4(1.0f);
texcoord = vTexCoord;
vec4 newPos = vec4(vPosition,1.0);
if (has_bones == 1)
{
mat4 bone_transform = bones[int(boneids[0])]*weights[0];
bone_transform += bones[int(boneids[1])]*weights[1];
bone_transform += bones[int(boneids[2])]*weights[2];
bone_transform += bones[int(boneids[3])]*weights[3];
newPos = bone_transform * newPos;
}
gl_Position = proj * view * pos * scale * rotate * newPos;
}
Do note that I've tried commenting out the bone_transform
in the vertex shader, and the problem still persists.
EDIT:
It seems that I was able to recreate some deformations on my Linux OpenGL 3.3 version by removing any assimp optimization post process flags:
scene = importer.ReadFile(file_path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_LimitBoneWeights | aiProcess_ValidateDataStructure);
Based on the output of the Assimp::DefaultLogger, there's no errors or vertex warnings.
The issue seemed to be a part of Blender's COLLADA export, or Assimp's COLLADA reader.
By exporting to FBX and using Autodesk's free FBX to DAE tool, the deformation was fixed.
Assimp, even with all logging and data integrity flags on, did not post any errors about corruption, so I don't know which component to blame. Regardless, I'm happy I've found a workaround.