[PERFORMANCE QUESTION] Sprite3D performance

Hi guys!

I have a question about performance related to the 3D elements such as Sprite3D.
I’m notice that Sprite3D performance is very low. I can’t create more than ~50 Sprite3D objects (simple 3D cube) because a performance on my iOS devices is very low. About ~50 Sprite3D objects on the scene is using almost all CPU.

So, question: how can I increase the performance. Maybe I should batch draw calls somehow?

Thank you!

Sprite3D uses renders with MeshCommand which does support batching based on material. If you are using the same GLProgramState/Material then cocos2d-x should automatically batch, with the exception of if force2DQueue=true, in which case batching will only occur for instances whose visit() is called in sequence.

What iOS device are you testing with?
What version of cocos2d-x are you using?
Are you texturing the cubes? Are they using the same texture?
You say CPU usage is high, this is unlikely to be a rendering issue unless the meshes are animated or very large. Do you still see high CPU usage when the Sprite3D instance are setVisible(false)?

@almax27 is more correct noting that if all Sprite3D instances are setup correctly they’ll auto-batch. I’ve mostly experienced that Sprite3D’s are created with separate textures by default, however. Key is to make sure you follow the auto-batching requirements.

Edit: You can check the draw call count to see if they’re batching.

Hi @almax27! Can you please tell me what it means? Thank you so much.

@igormats

Sure.

The way cocos2d-x implements its auto batching is by comparing the material/glProgramState for each subsequent RenderCommand. If the materials are the same then the command gets pushed onto the batch queue, if the materials are different then the batch queue is flushed.

The order commands are processed by the Renderer is dependant on either their local ZOrder and position in the scene graph or their global ZOrder. Global ZOrder overrides local ZOrder.

Let’s consider the following scene graph.

A (1)
∟ B (1)
  ∟ C (1)
  ∟ D (2)
∟ E (3)
  ∟ F (3)
∟ G (1)

Where letters represent the order visit() is called and the numbers the material.
The renderer will behave as such:
A - add to batch queue
B - add to batch queue
C - add to batch queue
D - flush queue, add to batch to queue
E - flush queue, add to batch to queue
F - add to batch queue
G - flush queue, add to batch to queue
Final flush to render G

Therefore even though there are 3 materials, 4 draw calls will be made. One each time the batch queue is flushed.

For more information on how this works, look at the implementation of cocos2d::Node::visit() and cocos2d::Renderer::processRenderCommand().

Hope this answers your question :smiley:

Oh, thank you @almax27 for such a detailed answer but according to cocos2d::Renderer::processRenderCommand I can see that batchDraw method will be called in any condition so CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES will be increment too!

flush3D method is really calling only 1 time but only batchDraw will really draw the content.

Can you please help me with this?
Extremely grateful!

Just wanted to confirm something from my deleted post. Sprite3D by default doesn’t batch, from my testing of adding a bunch of Sprite3D instances using the same box.c3b model from cpp-tests (without any other nodes in the scene). Draw call per each.

I’ve got the same :frowning:

@super626 can you please help us coz it’s your code? Thanks!

@stevetranby @igormats I see where you’re coming from now.

I think CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES should be called in MeshCommand::preBatchDraw() but only when _material == nullptr. It seems using a material does in fact break batching as geometry is rebound (per pass) during MeshCommand::batchDraw() if _material != nullptr.

Perhaps batches should be done per pass, per material instead.

That’s correct.

It works more or less like this:

A Sprite3d object is composed of one or more meshes.
Each mesh has a MeshCommand
MeshCommands have certain properties like: skipBatching, materialId, etc…
Depending on those properties and the renderer context either one of these two options will happen:

  • meshCommand->execute(): immediate drawing, no batching.
  • meshCommand->prebatchDraw() & batchDraw()

The thing is that batchDraw actually does not batch anything. It just reuse the context (VAO), but will perform a glDrawElements for each mesh.

IIRC, MeshCommand never batched the draw calls, but I could be wrong.
What I know for sure, is that if you are using the Material system that was introduced in v3.7 (?), then objects won’t be batched, since the context is being changed in each pass.

@ricardo A couple of questions:

  • Are there plans for implementing material batching?
  • Why do we have separate Mesh/Triangle commands? Shouldn’t Sprites, Trails etc not be considered meshes and be able to leverage the material system?

Could you explain the thinking behind the current approach?

Thanks :smiley:

@almax27

IIRC, we have two different command (Mesh and Triangles) because of legacy reasons.
Right now Mesh is optimized for 3d: it has normals and other attributes needed for 3d. And Triangles is just a simplified mesh optimized for 2d.

I don’t think it is worth unifying them since it is not that common that you are going to batch 2d and 3d objects together, but I could be wrong.

But yes, we should support material batching at some point.

Hi! Tell me please is any steps was made to archieve 3D batching!? Really can’t make a nice game without it :frowning:

not yet, but we are planning a much better 3d renderer for v4.0

1 Like

@ricardo when do you plan to start in on 4.0? Is it going to be an internal private project until some time that it’s deemed complete. And do you know if this is going to be a CREATOR-first project?

we started a few weeks ago with the requirements gathering.
I think the implementation will start in a few weeks (or months?).
the new 3d renderer req. comes mostly from the Chinese market, but it is something that we have been discussing here in the forum as well.
as far as a I know it will be cocos2d-x first.

@ShunLin any idea when the implementation of the 3d renderer will start?

1 Like

The 3D progress is on requirement gathering, and we also doing some research of engineering now.

The prototype of 3D renderer of Cocos2d-x will be created on WebGL firs, and then native support.
The aim of the 3D is Creator friendly, and of course 3D editor will be integrated into Creator.

Now, we are working on v3.1x to fix more bugs as we can, and make sure that users are happy with the quality of v3.1x, then we will put it in maintain mode.

After that we will freeze the v4 requirement and Launch it. Wish we can launch it on Nov.

1 Like

Hi, As far as I know, what you need is really batching, However, in 3d cases, batching is much more hard to archieve than 2D. Generally, two methods will be used for 3D batching, dynamic batching and static batching. Both methods involve merging vertex and index buffer operations. In cocos2d v3.x version, we do not achieve this. the performance improvement in sprite3D is material sorting as @ricardo mentions.

Some more details for 3D renderer.

  1. It would be fully 3D.
  2. support Phong lighting and some Physically based rendering.