Does anyone came across to this error with armory and know what is actually causing this issue?
I suspect my 3d model is too complex and I am searching after some directions in order to run it correctly in Armory and making it more simple.
What is a "uniform" and how does it translate in Blender?
Any input will be much appreciated.
Thanks
A uniform is like a shader variable that's uniform to all "executions" of that shader in a particular draw call (draw call = tell the GPU it should draw something). It is a bit like a global variable that can be used to pass parameters to a shader.
So it is probably caused by a too complex material or world shader. Maybe the only way to find the exact cause is to check all generated .glsl files in build/compiled/Shaders/ and search for a file with many uniforms at the top (they use the keyword uniform so they're easy to find). But (if I'm not mistaken) the amount of variables is not the crucial factor, it's their size. A vec4 will take 4 times the space a float takes, an array or a sampler (texture) may take even more space. Depending on the target and hardware there might be different limits to how many uniforms can be used.
To verify your findings you can hide all meshes with that particular material.
thanks @MoritzBrueckner so I removed one by one any complex elements, materials, etc, from my 3D model and looked at all the GLSL materials and else and tested every time and it turns out it to be the following :
An Armory3D project will just stop with a "too many uniforms" error only in specific cases:
It occurs ONLY with Adreno GPUs which all have a pretty low Vertex Uniform and Fragment Uniform counts in their hardware: 256 vs usually 1024 for Mali GPUs while being much faster in 3D than Mali GPUs.
When you export a 3D model with a complex Armature and lot of Bones it will simply crash with this error on Adreno GPUs but it will work on an old and 70 times slower Mali GPU.
I checked other engines, Unreal, Unity and they do have 3D models with complex Armature animation running correctly on Adreno GPU. (Ex: Genshin Impact which is running using Unity).
This seems to be a problem with Armory and Adreno GPU while handling Armatures and Bones.
The way Armatures and bones are processed using and here I guess "Uniforms" is causing the issue.
For now the best workaround I found is using over simplified Armatures with low bones counts. (so no moving hairs or cloths, etc...)
Hi @onelsonic, Thanks for the info.
Would you be able to do the following checks and see if there are any differences please:
Remove ALL textures from the model and use only a simple diffuse shader. Keep the high number of bones and the complex armature.
There is an option in the Object settings panel of Armory that says "Skinned object" or similar. Try it with your character and check again.
Also, does your "Character" object have more than one sub-meshes ?
Best Regards,
QC
is not working: crashing with "too many uniforms" on Adreno and running smooth even on old Mali GPU.
There is a "dynamic usage" settings for the object, I activated it, but same as above.
Then this 2013/2014 thread seems similar to what I am experiencing with modern high end Adreno GPU:
https://developer.qualcomm.com/comment/6972
Issue probably come from this :
The GLES shading language spec:
http://www.khronos.org/files/opengles_shading_language.pdf
Chapter 12, Appendix A, section 5 "Limitations for ES 2.0", page 115
_Uniforms (excluding samplers):
In the vertex shader, support for all forms of array indexing is mandated. In the fragment shader, support
for indexing is only mandated for constant integral expressions._
I guess the same limitations applies to ES 3.0, my Adreno is running on 3.0
Hi there, after further investigation and tests.
It looks like the problem comes from Animating the 3D model with complex geometry on Adreno GPU.
Loading a static skeleton and complex bones do work on Adreno.
So the way the animation is exported and then loaded on Adreno GPU is probably using too large uniforms that are not supported on these mobile GPUs.
Anyone know how animation are stored in Armory, do they use "uniforms"?
I think we would need to rewrite this piece using the info from this thread in order to fix the problem.
https://developer.qualcomm.com/comment/6972
Haven't delved too deep into armory's bone animations, but from what I could gather:
https://github.com/armory3d/iron/blob/master/Sources/iron/object/BoneAnimation.hx
The skinBuffer float array from the BoneAnimation class is passed under the link _skinBones here https://github.com/armory3d/iron/blob/a2d8e4280ae5ad2e50f017a2dc6d5fa3cf61301e/Sources/iron/object/Uniforms.hx#L989
which is used by this shader https://github.com/armory3d/armory/blob/master/Shaders/std/skinning.glsl
and how it's used when writing vertex shaders https://github.com/armory3d/armory/blob/master/blender/arm/material/make_skin.py
If too many uniforms may be tripped probably is because of that uniform.
thanks @N8n5h, I checked all codes you mentioned and run a few tests and succeed to localise the issue.
It comes from this line here :
https://github.com/armory3d/armory/blob/48952e04a8f29379e55e1a368dc86101cf918eed/Shaders/std/skinning.glsl#L3
On Adreno GPUs (skinMaxBones * 2) is too high for the hardware. (Or badly supported, not sure...)
Hard coding the 'skinMaxBones * 2' value to 245 partially fix the problem as we just limit it to how many uniforms Adreno GPU are supporting.
uniform vec4 skinBones[245];
not sure why 245 works, when I think it should technically be 256.
Also changing this line here has no effect whatsoever on the GLSL shader:
public static var skinMaxBones = 128;
https://github.com/armory3d/iron/blob/a2d8e4280ae5ad2e50f017a2dc6d5fa3cf61301e/Sources/iron/object/BoneAnimation.hx#L17
Looking at how Adreno's work :
I read that Adreno GPU's OpenGL was bogus somehow and not sure if it is still the case now...
Also Adreno GPU's are currently the fastest GPU's on android and the Google Pixel's phones all have it.
Reported bogus drivers here:
https://github.com/godotengine/godot/issues/12816#issuecomment-355991771
https://developer.qualcomm.com/comment/6972
some proposals to fix this for Adreno:
1: should bones skinning use texture data instead of uniforms? Will it be as fast?
2 : is there a way to force the use of OpenGL ES2 instead of ES3 for android or webGL2.0 to test it? It might fix this issue.
3: then not sure if it is related but when I try to set the Max bones parameters manually, here : the export crashes with the below:

to

_compilation crash logs:_
Exporting Scene
Traceback (most recent call last):
File "C:\armory/blender\arm\props_ui.py", line 870, in execute
make.build(item.arm_project_target, is_publish=True, is_export=True)
File "C:\armory/blender\arm\make.py", line 383, in build
export_data(fp, sdk_path)
File "C:\armory/blender\arm\make.py", line 125, in export_data
ArmoryExporter.export_scene(bpy.context, asset_path, scene=scene, depsgraph=depsgraph)
File "C:\armory/blender\arm\exporter.py", line 154, in export_scene
cls(context, filepath, scene, depsgraph).execute()
File "C:\armory/blender\arm\exporter.py", line 2139, in execute
self.export_objects(self.scene)
File "C:\armory/blender\arm\exporter.py", line 2001, in export_objects
self.export_mesh(mesh_ref)
File "C:\armory/blender\arm\exporter.py", line 1436, in export_mesh
exporter_opt.export_skin(self, bobject, armature, vert_list, out_mesh)
File "C:\armory/blender\arm\exporter_opt.py", line 301, in export_skin
log.warn(bobject.name + ' - ' + str(bone_count) + ' bones found, exceeds maximum of ' + str(max_bones) + ' bones defined - raise the value in Camera Data - Armory Render Props - Max Bones')
NameError: name 'log' is not defined
not sure why 245 works, when I think it should technically be 256.
Not sure, but I guess it's because there are still other uniforms somewhere that add to this count.
then not sure if it is related but when I try to set the Max bones parameters manually, here : the export crashes with the below:
Added a fix, this was not related to your changes: https://github.com/armory3d/armory/pull/2021
Digging into this problem,
another possible solution will be to rewrite the GPU skinning shader to use "Uniform Buffer Object" instead of "Vertex Uniform".
https://github.com/armory3d/armory/blob/master/Shaders/std/skinning.glsl
The size of skinBuffer from BoneAnimation is computed here https://github.com/armory3d/iron/blob/a2d8e4280ae5ad2e50f017a2dc6d5fa3cf61301e/Sources/iron/object/BoneAnimation.hx#L73,
this.skinBuffer = new Float32Array(skinMaxBones * boneSize);
so it's weird that reducing the value of skinMaxBones doesn't change anything. Have you tried drastically reducing the value to see if it has the same effect still?
Also be sure to check to what value armory writes the const int skinMaxBones in compiled/Shaders/compiled.inc.
Armory seems to be using textures in some places to store data (other than images), maybe the same could be applied to store that skin data instead as an alternative?
setting skinMaxBones to 1 or 122 in BoneAnimation.hx has no effect, the animation will play correctly on Mali GPU but crash on Adreno. Yes strange, there is probably something overwriting its value when running.
https://github.com/armory3d/iron/blob/a2d8e4280ae5ad2e50f017a2dc6d5fa3cf61301e/Sources/iron/object/BoneAnimation.hx#L17
I will provide a file so it can illustrate this issue :
Blend File:
https://github.com/onelsonic/armory_tests/blob/master/animation-android-adreno-bug/link.blend
You can test the animation and run it with Google Chrome on Android (Adreno and Mali GPU)
https://onelsonic.github.io/animation-android-adreno-bug/index.html

This issue comes from how OpenGL GPU skinning is rendered on Android with Adreno GPU, so the same issue will occur natively on Android as well.
Solution:
Rewriting the "uniform vec4 skinBone" here :
https://github.com/armory3d/armory/blob/48952e04a8f29379e55e1a368dc86101cf918eed/Shaders/std/skinning.glsl#L3
using either Texture buffer object or Uniform Buffer not sure which one is bigger on Adreno.
full adreno OpenGL specs link
(https://user-images.githubusercontent.com/53947594/100106245-9bc83d80-2e68-11eb-8981-2720a47f915e.png)

This is what is overwriting the skinMaxBones value.
If set manually to 122 (thanks to @MoritzBrueckner fix #2021 ) --> 122*2 = 244 we get the same as hard coding the value to 244.
Stripping the extra bones. If set to Auto it will default to an automatic calculated value.
Then back to the Adreno skinning problem, I think Texture buffer objects might be the way to fix this.
(below is what we should be aware of using Texture buffer objects)
https://gamedev.stackexchange.com/questions/174019/instancing-and-gpu-skinning.
Edit:
using just textures, here are other useful GLSL references:
https://webgl2fundamentals.org/webgl/lessons/webgl-skinning.html
_Let's update the shader to get the matrices out of a texture._Dual Quaternion Skinning using textures:
https://github.com/ConstantineRudenko/DQ-skinning-for-Unity/blob/2cd819b840a93086b29a641f20bdd423bef05873/Code/DQ%20skinning/Shaders/Material/HackedStandard/HackedStandard.shader#L135
Most helpful comment
A uniform is like a shader variable that's uniform to all "executions" of that shader in a particular draw call (draw call = tell the GPU it should draw something). It is a bit like a global variable that can be used to pass parameters to a shader.
So it is probably caused by a too complex material or world shader. Maybe the only way to find the exact cause is to check all generated .glsl files in
build/compiled/Shaders/and search for a file with many uniforms at the top (they use the keyworduniformso they're easy to find). But (if I'm not mistaken) the amount of variables is not the crucial factor, it's their size. A vec4 will take 4 times the space a float takes, an array or a sampler (texture) may take even more space. Depending on the target and hardware there might be different limits to how many uniforms can be used.To verify your findings you can hide all meshes with that particular material.