Hi,
With update to version r72 from r71 in our project, the rendering performance with use of THREE.MeshFaceMaterial drastically dropped down to ~5fps for complex meshes.
Here is an example code:
http://jsfiddle.net/w6t2ozam/
It works good with version r71 but with r72 it has a very low performance. When we move our camera (TrackballControls) fps drops, animation is not smooth. That was not an issue with r71 version.
Im new to threejs, I dont know if there is some bug.
Thank you for any help.
That is to be expected with the r.72 implementation.
Typing renderer.info into the console shows 120,000 faces and 60,000 draw calls.
This is a perfect example of a worst-case scenario.
One work-around is to construct your geometry so only faces using the same material are merged. You would then have 6 draw calls -- one for each color.
I'm facing a similar issue. This is due to the groups requiring a contiguous range. In a scene where I had roughly 30 draw calls, I now have about 400.
A workaround is a little tricky as it is a single plane that has been displaced via a heightmap which a player can run along.
I'll post an example later tonight, though I'm not sure anything can be done about this as is.
Maybe we can write a little utility to split geometries. But the reason I went this way was to not break skinning and morphing.
Hi
Thank you for quick replay.
I don't know if I understood the code correctly but I’ve noticed that in r72 function DirectGeometry.computeGroups(geometry) is responsible for splitting geometry on such many groups (60k in expample).
I think that a simple workaround can be to sort faces in complex geometry by materialIndex.
When we add sorting the faces:
mergedGeometry.faces.sort(function (a, b) {
return a.materialIndex - b.materialIndex;
});
The renderer.info.render.calls, shows only 6 calls, and performance is higher.
Nice! Yes, that should do the trick. Actually, it may even work for geometries? @titansoftime?
By now I'll add at as a method in THREE.Geometry...
Interesting, I'll give this a try when I get a chance.
I tried this out. Well, face order is pretty important in my app so for now I did this to get around that issue:
var geometry = new THREE.PlaneGeometry(2000,2000,128,128); // this is actually merged geometries with applied heightmaps in app
var tempGeo = new THREE.BufferGeometry().fromGeometry(geometry);
var posAttribute = tempGeo.getAttribute('position').clone();
tempGeo.dispose();
geometry.sortFacesByMaterial();
var bufferGeo = new THREE.BufferGeometry().fromGeometry(geometry);
bufferGeo.addAttribute('facemap',posAttribute);
So after that I was able to test.
For one this does fix the drawcall issue, everything runs great. Brilliant!
One thing though: There seems to be an issue (I will have to do a fiddle later as I don't have time right now). For now here's a couple screens that may give you guys an idea of whats going on:
This area is fine:

A few paces forward:

From a distance:

And here's the fiddle demonstrating the issue:
@mrdoob Is it because the uv's aren't being sorted along with the faces?
@titansoftime Yes. morphColors will have the same problem.
@WestLangley Makes sense, thanks for the confirmation.
@mrdoob Is it because the uv's aren't being sorted along with the faces?
Oh...
So I was bored at work and just checked on this. The fiddle now seems fine with sortFacesByMaterialIndex. Cheap work pc with Intel HD 8.15.10.2696 Windows 7.
@mrdoob did you change something? The sort function looks the same.
http://jsfiddle.net/t3379d2u/1/
With sortFacesByMaterialIndex in use I am getting 2 drawcalls (3 without) and the uv's seem fine.
Little confused...
Yup broken on my pc (geforce gtx 650 Win7), works on crappy work computer. Weird.
EDIT* Works fine in Firefox (what I use at the office), breaks in Chrome (45.0.2454.101 m).
EDIT2* Ok, it does break in FF (cannot tell in fiddle). I can see it in app, it's just not nearly as noticeable as it is in Chrome.
Uvs should be fixed now I think 😅
Perfecto!
Awesome, thank you =]
Are there any other properties other than morphColors that should be re-sorted, too?
I was actually considering removing morphColors altogether. Seems like it was a hack for the animals for rome. JSONLoader could directly apply the colors if morphColors is found in the json. Then remove the morphColorsToFaceColors() from the examples.
@mrdoob
Hey, I was wondering if it was still an Issue.
I'm using r78 and developing an app that should run with at least 30 FPS on mobile. But with my latest model update I used multi-indexed materials, so each model.json has a few materials attached to it.
Therefore I'm using MeshFaceMaterial(geometry, materials) materials being the list of materials I receive from the JSONLoader callback.
Since I'm using it I have something like 13-16 FPS on mobile (Nexus 6), I did a few test with differents materials that I applied on my whole model (~60'000 triangles).
MeshLambertMaterial(Math.random() * 0xffffff): 58-60 FPSMeshFaceMaterial(materials): 13-16 FPSMeshLambertMaterial(materials[0]): 46-60 FPS@thomasroulin Type renderer.info into the console for each case, and report the results.
@WestLangley Here are the results
{
"render": {
"calls": 1901,
"vertices": 78444,
"faces": 25836,
"points": 0
},
"memory": {
"geometries": 25,
"textures": 9
},
"programs": [
{
"id": 0,
"code": "basic,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 13,
"program": {},
"vertexShader": {},
"fragmentShader": {}
},
{
"id": 1,
"code": "lambert,highp,true,true,3000,false,,3000,false,false,false,3000,true,false,false,true,false,false,false,0,0,,true,false,false,,false,false,251,,false,false,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 3,
"program": {},
"vertexShader": {},
"fragmentShader": {}
},
{
"id": 2,
"code": "lambert,highp,true,true,3000,false,,3000,false,false,false,3000,true,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,false,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 3,
"program": {},
"vertexShader": {},
"fragmentShader": {}
},
{
"id": 3,
"code": "lambert,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,false,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 2,
"program": {},
"vertexShader": {},
"fragmentShader": {}
}
]
}
{
"render": {
"calls": 2003,
"vertices": 82092,
"faces": 27028,
"points": 0
},
"memory": {
"geometries": 27,
"textures": 0
},
"programs": [
{
"id": 0,
"code": "basic,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 14,
"program": {},
"vertexShader": {},
"fragmentShader": {}
},
{
"id": 1,
"code": "lambert,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,false,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 34,
"program": {},
"vertexShader": {},
"fragmentShader": {}
}
]
}
{
"render": {
"calls": 25,
"vertices": 82092,
"faces": 27028,
"points": 0
},
"memory": {
"geometries": 28,
"textures": 0
},
"programs": [
{
"id": 0,
"code": "basic,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 14,
"program": {},
"vertexShader": {},
"fragmentShader": {}
},
{
"id": 1,
"code": "lambert,highp,true,false,3000,false,,3000,false,false,false,3000,false,false,false,false,false,false,false,0,0,,true,false,false,,false,false,251,,false,false,8,4,false,0,3,0,0,false,1,1,false,0,false,false,0,false",
"usedTimes": 12,
"program": {},
"vertexShader": {},
"fragmentShader": {}
}
]
}
@thomasroulin 2000 draw calls is your problem. Try calling
geometry.sortFacesByMaterialIndex();
in the loader calback.
@WestLangley Thank you, I should have understand that from above :sweat_smile:...
I now have 36 calls and 35-45 FPS on mobile, perfect.
Looks like this issue can be closed?