Object/Sprite Batching

Started by Jakes, December 28, 2020, 07:36:57 PM

Previous topic - Next topic

Jakes

Hello,

I was wondering if there is a prebuilt method for batching up sprites to the GPU instead of sending multiple objects individualy, as it increases a lot the performance when using particle systems or packs of elements sharing same mesh,

thanks,
Jakes

AGP

Other than new Object3D(object3D, true) with true being reuseMesh, I don't think so.

Jakes

#2
That is not batching the objects per se, rather just reusing the same mesh data in order to reduce memory usage.
What I'm talking about is batching objects (not meshes) in a single call to the GPU in order to reduce callback bottleneck caused by multiple calls to the pipeline.

I've seen this:

https://www.jpct.net/wiki/index.php?title=Instance_Batch_Rendering

but this is not bundled in the JPCT API, so I have some concerns regading Desktop version, and there are no examples on how to use and documentation about understanding it.

does anyone know if this will work with the Desktop vesion and requires a shader explicitly for this?

EgonOlsen

#3
It should work on desktop jPCT as well, I guess. But it would need a different shader, because desktop jPCT relies on OpenGL's magic uniforms for vertex, lighting and texture data were jPCT-AE manages the uniforms all by itself because there is no magic anymore in OpenGL ES.

Edit: Not sure if it's worth the hassle for most usecases, though...

Jakes

My main concern is about reducing overhead on low end computers in game development.

But TBF, the reason I was looking for an improvement on what I have, is mainly because I tend to use a lot of fixed and static objects that are clones, differing only on their position, but sharing not only mesh and texture data as well, and I am already using the shareCompiledData and shareTextureData, but I was having some bottlenecks when having 2000+ more objects on the same scene, and even inside the frustum.

But when it comes to shaders that is not my best preference, because everytime I need to add a shader to an already existing shader, I need to combine them and check if the code still remains valid

Regards,
Jakes

Jakes

#5
Getting back on this topic, the batching example on the wiki didn't work as expected, or even worked at all with relevant results.

So my question is: is there any way of overriding any part so that I could try and implement a simple Batch Use case, mostly for sprites and static objects?
I'm working on a scene that has a lot of concentrated objects all at once (particles) which is dropping the frame rate considerably, and using Batch Instancing would increase it drastically leaving me more room for the rest.

My main idea, would be to simply its usage, something like an extended Object3D, which is a container for children Objects (which are not present in the world) that would be batched all at once

ObjectContainer3D
- InstancedObject3D List
- Refresh();

and after calling the refresh method, the Data will be sent to the GPU.

I think that could improve drastically the performance and usabilty of the framework

EgonOlsen

Quote from: Jakes on January 27, 2021, 01:56:28 PM
My main idea, would be to simply its usage, something like an extended Object3D, which is a container for children Objects (which are not present in the world) that would be batched all at once

ObjectContainer3D
- InstancedObject3D List
- Refresh();

and after calling the refresh method, the Data will be sent to the GPU.

I don't see the point in that approach. It would be the same thing as using multiple objects in the first place or wouldn't it? I can think of two possible solutions: Create an Object3D that contains a bunch of single polygons and use this: https://www.jpct.net/doc/com/threed/jpct/GenericVertexController.html to alter it in a way that the polygons represent your particles. It's still software based that way and requires an upload to the GPU whenever the mesh changes, but it might be fast enough. I did a similar thing to implement a kind of fog of war once (i.e. a dynamically build mesh that covers the floor depending on what the player sees). To hide unneeded polygons, I simply moved them out of view.
The other way would be to do the same thing, but in a shader. That's faster, of course, but maybe harder to write depending on your experience with shaders (I have some and I wouldn't want to do it... ;) ).
Or you can try to throw raw processor power at the problem and use this: https://www.jpct.net/doc/com/threed/jpct/WorldProcessor.html. But as it only speeds up object processing and not the rendering itself, it might not help much if anything at all.

AGP

I have some examples of particle systems (fire, jetpack jet particles, even a fog of war) I did that were perfectly fast. I can look them up tomorrow.

Jakes

#8
Quote from: EgonOlsen on January 29, 2021, 09:03:41 AM
I don't see the point in that approach. It would be the same thing as using multiple objects in the first place or wouldn't it?

Maybe you didn't get my idea.

The concept would be to use references of matrix data (position, rotation and scale), which is the logic side of the system, and then a Global List which is a reference for a single Mesh, that will be sent to the GPU via glDrawArraysInstanced, where the data from the logical objects will be sent via shader, that is predefined, withou the user needing to mess with it.

Something like this:

- InstancedManager (ObjectContainer3D), that receives a mesh reference
- then a user can create as many objects (InstancedObject3D) as he wants (which are objects that only contains matrix data, and maybe some texture related data, alpha, displacement, etc)  which will be sent to a prebuilt shader.

of course this will yield out way better results, no doubt.

and this will make things easy to use and control.

Jakes

#9
This way, it will allow performant operations such as:

- Position change
- Orientation change
- Scaling change
- Visibility change
- And count change

whereas using a mesh and change it via GenericVertexController, wouldn't work as fast as using Instancing, and inscresing or descresing elements in scene, because the control and iteration will be done in the CPU side, which we all know the GPU is way better for such things.

The main goal is clearly reducing the calls to the GPU

EgonOlsen

I see. I guess you could implement an https://www.jpct.net/doc/com/threed/jpct/IRenderHook.html to hook into the pipeline and do something like that.

Quotewhereas using a mesh and change it via GenericVertexController, wouldn't work as fast as using Instancing, and inscresing or descresing elements in scene, because the control and iteration will be done in the CPU side, which we all know the GPU is way better for such things.
No, it most likely wouldn't work as fast. The question is, if that actually matters. It depends on the number of particles that you want to display.

Jakes

#11
About using "https://www.jpct.net/doc/com/threed/jpct/IRenderHook.html", how can I access the Object data in order to manipulate it to the GPU?

For example, if I wanted to call GL11.glDrawElementsInstanced(GLenum,GLsizei,GLenum,indices, GLsizei);, how could I access the indices? and at which moment? beforeRendering()?

Or on the setObject(), should I use a VertexController to send the data to the GPU?

EgonOlsen

I would think that the object itself should be rather empty and that your vertex data has to come from somewhere else. If it would be part of the object, it would be drawn, because the IRenderHook has no option to suppress drawing of the actual object. In this case, the object is more like a hook into the render pipeline than an actual object.