Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (741)
Games in Android Showcase (225)
games submitted by our members
Games in WIP (823)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  OpenGL - Draw multiple objects issue  (Read 7125 times)
0 Members and 1 Guest are viewing this topic.
Offline vfmachado

Junior Devvie


Medals: 9
Exp: 4 years



« Posted 2017-02-17 22:43:31 »

Hi everyone,

There is some time from my last post in the community, I'm still working on something that I'm calling engine Tongue

Today I want to get suggestions about rendering a lot of stuff... To test the "power" of my code I put it to run with 5k colored/textured cubes. Running in a full-hd resolution with a good computer I can get max 35~40 FPS with the current solutions. So I want to know what are the best practices to draw a lot of elements. I'll link the video.

This question comes to me when I try to add a lot of "grass" in a terrain, each grass has 3 faces, textures, normal, transform matrix, etc.. But my performance immediately goes down.

Thank you all guys... this forum is the best place to get inspiration Smiley
<a href="http://www.youtube.com/v/pehHt9Fqnlg?version=3&amp;hl=en_US&amp;start=" target="_blank">http://www.youtube.com/v/pehHt9Fqnlg?version=3&amp;hl=en_US&amp;start=</a>
Offline KaiHH

JGO Kernel


Medals: 482



« Reply #1 - Posted 2017-02-18 21:01:43 »

For rendering grass over some terrain let's start getting to a good solution by writing down some basic assumptions/constraints:

0. the whole meadow is composed of tens of thousands of grass "patches"
1. each grass patch is made of the same geometry/model, just at different positions and with some rotation
2. once each patch is put on the ground at a given position it stays there and does not move
3. each path has probably the ability to "wave" with the wind (that is, its upper vertices can be displaced)

As usual, you have the following constraints to achieve good performance with OpenGL:
a) you want to minimize the number of draw calls (that is, the number of glDraw*() calls and, _god forbid if you are doing it_ the number of glBegin/glEnd calls)
b) you want to minimize the number of actual vertices being drawn, including omitting vertices not visible to the user
c) you want to minimize the dynamic update of buffer data at each render loop cycle

Given constraint 0, 1 and 2 the optimal solution would probably be to fill a whole VBO with all pre-transformed world-space grass patches and then simply do a single (indexed) draw call. This would allow to optimize constraint a) and c) to the fullest, but would keep b) suboptimal, since you would also render grass patches not visible to the camera.

To optimize for b) we could start clustering grass patches. That is, we do not store _all_ grass patches in a single buffer, but spatially divide them into multiple buffers. Then during rendering we can do simple frustum culling to decide whether one cluster is visible and draw them with a draw call.
Here you can also unpack a host of spatial acceleration data structures to do the culling most efficiently.

You might also consider OpenGL hardware instancing (google for "OpenGL instancing" and read the first 5-6 search results). You'd achieve a significantly smaller overall memory footprint when using it, because you'd only have to store the following information:
- the geometry information of a single grass patch (with instance divisor 0)
- the world-space position for each grass patch (with instance divisor 1)
- the 2x2 rotation matrix for each grass patch (with instance divisor 1)

Why do we need a 2x2 rotation matrix now? Because each grass patch should be able to rotate randomly so as to reduce the appearance of uniformity in the grass patches on the terrain. (much like what is presented in this GPU gems article)

In the non-instanced variant described above, we do all positioning and rotation by pre-transforming all vertices into world-space and then submitting them to the buffer object.

When using instancing we cannot do that anymore, because we are back at model-space. So, we need a way to represent rotation. We could get away with a single rotation angle, but that would then require to evaluate sin/cos in the shader. This however would hurt performance more than storing 3 additional float values for the 2x2 matrix, in which that sin/cos calculation has already been done once on the CPU.

I'd start with implementing the "put all grass patches pre-tranformed into a single VBO and render them using a single draw call" method. I've implemented both approaches some eight years ago or so, and in both ways blending/overdraw was the main bottleneck in the end with rendering grass patches with alpha blending or with alpha discard.
If you are more into instancing, read this interesting article first, of which the "Extensions - ARB_instanced_arrays" is the method I suggested here.
Offline KaiHH

JGO Kernel


Medals: 482



« Reply #2 - Posted 2017-02-19 00:27:01 »

This is an example of instanced rendering featuring 100,000 animated grass patches (each with three faces) at full hd resolution @70 FPS on a 2011 notebook graphics card:

So, rendering hundreds of thousands of little objects is doable! Smiley

EDIT: Or with just using four different grass and flower textures based on simplex noise:
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline vfmachado

Junior Devvie


Medals: 9
Exp: 4 years



« Reply #3 - Posted 2017-02-19 16:40:44 »

KaiHH,

really thanks for this awesome answer. I'll read the articles and then try to codify it in this week.

I'll try to update this thread if I had any doubts. =)

Thanks!!
Offline vfmachado

Junior Devvie


Medals: 9
Exp: 4 years



« Reply #4 - Posted 2017-03-05 01:19:01 »

It works!!! Smiley

Thanks KaiHH


Offline Riven
Administrator

« JGO Overlord »


Medals: 1324
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #5 - Posted 2017-03-05 11:45:52 »

When using instancing we cannot do that anymore, because we are back at model-space. So, we need a way to represent rotation. We could get away with a single rotation angle, but that would then require to evaluate sin/cos in the shader. This however would hurt performance more than storing 3 additional float values for the 2x2 matrix, in which that sin/cos calculation has already been done once on the CPU.
If you take a 16bit integer (giving you up to 0.005 degrees of accuracy), you can then lookup the sin/cos values in a uniform-buffer or (as a fallback) a texture. This reduces 128 bits (4 floats) to 16 bit, at the cost of 2 lookups on the GPU. I expect that would yield a slight performance increase. You can decide to use only 10 bits, reducing the side of the uniform-buffer. For grass even 256 distinct rotation angles (8 bit integer) would be enough.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Offline theagentd
« Reply #6 - Posted 2017-03-06 22:16:55 »

Err, sin() and cos() are pretty cheap in shaders. Also, vertex shaders are also often limited by the "export" cost of writing the output of the attributes to temporary memory, making all operations "free" up to a certain point. Even if cos/sin was that expensive, you could just precompute them on the CPU and upload them directly, then construct a rotation matrix from those two values.

Myomyomyo.
Pages: [1]
  ignore  |  Print  
 
 

 
xxMrPHDxx (21 views)
2017-11-21 16:21:00

xxMrPHDxx (14 views)
2017-11-21 16:14:31

xxMrPHDxx (16 views)
2017-11-21 16:10:57

Ecumene (114 views)
2017-09-30 02:57:34

theagentd (150 views)
2017-09-26 18:23:31

cybrmynd (260 views)
2017-08-02 12:28:51

cybrmynd (250 views)
2017-08-02 12:19:43

cybrmynd (247 views)
2017-08-02 12:18:09

Sralse (260 views)
2017-07-25 17:13:48

Archive (881 views)
2017-04-27 17:45:51
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!